デュアルポインタとスライディングウィンドウアルゴリズムテンプレート

デュアルポインタとスライディングウィンドウアルゴリズムテンプレート

[[428819]]

ダブルポインタのアルゴリズム原理は、2 つのポインタを介して 1 つの for ループで 2 つの for ループの作業を完了することです。時間計算量は から最適化されます。

ダブルポインターアルゴリズムのテンプレートは比較的単純であり、突破口は主に問題の単調性を見つけてそれを利用することにあります。

高速ポインターと低速ポインター

高速ポインタと低速ポインタはリンクリストの操作手法であり、「ウサギとカメの競争」という面白い名前も付けられています。

  • 要素を削除します:

  1. クラスソリューション{
  2. 公共
  3. int要素を削除(ベクトル< int >& 数値, int値) {
  4. スローインデックス = 0;
  5. ( int fastIndex = 0; fastIndex < nums.size ( ) ); fastIndex++) {
  6. if (val != nums[fastIndex]) {
  7. nums[slowIndex++] = nums[fastIndex];
  8. }
  9. }
  10. slowIndexを返します
  11. }
  12. };
  • リングの入口位置: 高速ポインターと低速ポインターを使用します。高速ポインターは 2 ステップ進み、低速ポインターは 1 ステップ進みます。ループがある場合、2 つのポインタは遅かれ早かれ出会います。ループがない場合、高速ポインタは末尾に到達してループを終了します。ループがある場合は、遅いポインターが再び開始し、速いポインターが交差点になります。同じ速度の 2 つのポインターの交差点が入り口である必要があります。
  1. クラスソリューション{
  2. 公共
  3. リストノード *detectCycle(リストノード *head) {
  4. ListNode* 遅い = ヘッド;
  5. ListNode* fast = ヘッド;
  6. while (fast && fast-> next ){
  7. fast = fast-> next- > next ;
  8. slow = slow-> next ;
  9. if (fast == slow) break;
  10. }
  11.          
  12. if (fast && fast-> next ){
  13. 遅い = 頭;
  14. while(遅い!=速い){
  15. slow = slow-> next ;
  16. fast = fast-> next ;
  17. }
  18. ゆっくりと戻る;
  19. }
  20. nullptrを返します
  21. }
  22. };
  • リンク リストの中間ノード: 高速ポインターと低速ポインターを適用します。高速ポインターは 2 ステップ実行し、低速ポインターは 1 ステップ実行します。高速ポインタが端に到達すると、低速ポインタはちょうど半分まで移動した状態になり、戻り点は中間のノードになります。
  • リンク リストの N 番目から最後のノードを削除します。最初に高速ポインターが n ステップ移動し、次に高速ポインターと低速ポインターが同時に移動し、高速ポインターが最後に到達すると、低速ポインターは n 番目から最後の位置にあります。

バックポインタ

典型的な逆ポインター問題には、N 和級数とバイナリ検索のバリエーションがあります。

N和シリーズの典型的な問題は、3つの数字の合計である。

  1. def threeSum(数値):
  2. nums.sort()
  3. # [-4, -1, -1, 0, 1, 2]
  4. res_list = []
  5. # ヘッドループ検索
  6. i が範囲(len(nums))内にある場合:
  7. # 条件nums[i] > nums[i - 1]をチェックする必要がある
  8. i == 0またはnums[i] > nums[i - 1] の場合:
  9. # 左端
  10. 1 = i + 1 です
  11. # 右端
  12. r = 長さ(数値) - 1
  13. while l < r: # 検索中
  14. 3つの合計 = nums[i] + nums[l] + nums[r]
  15. three_sum == 0の場合:
  16. res_list.append([nums[i], nums[l], nums[r]])
  17. l += 1 # 1ビット右にシフト
  18. r -= 1 # 1ビット左にシフト
  19. l < rかつnums[l] == nums[l - 1]の場合:
  20. # 左から右へ、同じ値をスキップします
  21. 1 += 1
  22. r > lかつnums[r] == nums[r + 1] の場合:
  23. # 右から左へ、同じ値をスキップします
  24. r -= 1
  25. three_sum > 0の場合:
  26. # 0より大きい場合、右側の値が大きいので左に移動します
  27. r -= 1
  28. それ以外
  29. # ゼロ未満、左側の値が小さいので右に移動
  30. 1 += 1
  31. res_listを返す

4 つのバイナリ検索バリアントでは、Wang Zheng のアルゴリズム コラムによれば、low = 0、high = len(list) - 1 がハードコードされています。ループ条件は low <= high です。左に高く移動 = 中 - 1、右に低く移動 = 中 + 1

  1. def binary_search(数値、ターゲット):
  2. '' '標準バイナリ アルゴリズム テンプレート' ''  
  3. 低い = 0
  4. high = len(nums) - 1 # 注 1 low と high は、検索するリストの部分を追跡するために使用されます。
  5. low <= high: # 注2 要素が1つに減っていない限り、チェックを続ける
  6. 中 = (低 + 高) // 2
  7. リスト[mid] == ターゲットの場合:
  8. 戻る途中
  9. elif リスト[mid] > ターゲット:
  10. high = mid - 1 # 注3: 推測した数値が高すぎる
  11. elif list[mid] < ターゲット:
  12. low = mid + 1 # 注4: 推測した数字が小さすぎる
  13. 戻る途中
  14.  
  15.  
  16. def bsearch_low(数値、ターゲット):
  17. '' '固定値に等しい最初の値を見つける' ''  
  18. 低い = 0
  19. 高さ = 長さ(数値) - 1
  20. # <= はここに必要です
  21. 低 <= 高の場合:
  22. # 注意: ((high - low) >> 1) を使用する場合は、二重拡張が必要です。
  23. 中 = 低 + ((高 - 低) >> 1)
  24. nums[mid] < targetの場合:
  25. 低 = 中 + 1
  26. elif nums[mid] > ターゲット:
  27. 高 = 中 - 1
  28. それ以外
  29. mid == 0またはnums[mid-1] != target の場合:
  30. 戻る途中
  31. それ以外
  32. 高 = 中 -1
  33.  
  34. -1を返す
  35.  
  36. def bsearch_high(数値,ターゲット):
  37. '' '固定値に等しい最後のものを見つける' ''  
  38. 低い = 0
  39. 高さ = 長さ(数値) -1
  40. 低 <= 高の場合:
  41. 中 = 低 + ((高 - 低) >> 1 )
  42. nums[mid] > targetの場合:
  43. 高さ = 中 - 1
  44. elif nums[mid] < ターゲット:
  45. 低 = 中 +1
  46. それ以外
  47. mid == (len(nums) -1)またはnums[mid] != nums[mid+1] の場合:
  48. 戻る途中
  49. それ以外
  50. 低 = 中 +1
  51. -1を返す
  52.  
  53. '' '
  54. 指定された値以上の最初の要素を検索します
  55. * たとえば、3、4、6、7、19というシーケンスで、5より大きい最初の要素である6を見つけて、 2を返します
  56. * 最初の値が指定された値より大きい場合、前の値は指定された値より小さいことを意味します。
  57. '' '
  58. def bsearch_low_not_less(数値、ターゲット):
  59. 低い = 0
  60. 高さ = 長さ(数値) -1
  61. (低<=高)の場合:
  62. 中 = 低 + ((高-低) >> 1)
  63. nums[mid] >= targetの場合:
  64. mid == 0またはnums[mid - 1] < target の場合:
  65. 戻る途中
  66. それ以外
  67. # 左に移動
  68. 高 = 中 - 1
  69. それ以外
  70. # 右に移動
  71. 低 = 中 +1
  72. -1を返す
  73.  
  74. '' '
  75. 指定された値より小さい最初の要素を見つける
  76. * たとえば、3、4、6、7、19というシーケンスで、5より小さい最初の要素である4を見つけて、1を返します。
  77. * 最初の値が指定された値より大きい場合、前の値は指定された値より小さいことを意味します。
  78. '' '
  79. def bsearch_high_not_greater(数値、ターゲット):
  80. '' '以下の最後の値を検索' ' '  
  81. 低い = 0
  82. 高さ = 長さ(数値) -1
  83. 低 <= 高の場合:
  84. 中 = 低 + (( 高 - 低 ) >> 1)
  85. nums[mid] <= targetの場合:
  86. (mid == len(nums) -1)または(nums[mid + 1] > target) の場合:
  87. 戻る途中
  88. それ以外
  89. 低 = 中 +1
  90. それ以外
  91. 高さ = 中間 -1
  92. -1を返す

スライディングウィンドウ

原文: https://mp.weixin.qq.com/s/ioKXTMZufDECBUwRRp3zaA

スライディング ウィンドウ アルゴリズムは、ダブル ポインター テクニックの最高レベルであり、主に 2 つの文字列を一致させる問題に使用されます。

スライディング ウィンドウの問題解決テンプレートを習得すると、一連の文字列一致問題を簡単に解決できます。

次のテンプレート コードは labuladong からのものであり、LeetCode の問題 76「最小ウィンドウ サブ文字列」を解決して、最小のカバー サブ文字列を見つけます。

  1. /* スライディングウィンドウアルゴリズムフレームワーク */
  2. 文字列minWindow(文字列s, 文字列t) {
  3. // 2 つの unordered_maps。1 つはパターン文字列内の文字数を記録し、もう 1 つのウィンドウはウィンドウ内の文字を記録します。
  4. unordered_map< char , int > 必要、ウィンドウ;
  5. // 初期化が必要
  6. ( char c : t )必要です[c]++;
  7.  
  8. 整数 = 0、= 0;
  9. // 条件を満たした unordered_map の数
  10. 整数有効 = 0;
  11. //最小カバー部分文字列の開始インデックスと長さを記録する
  12. int開始 = 0、長さ = INT_MAX;
  13. while (< s.size ()) {
  14. // c はウィンドウに移動する文字です
  15. char c = s[];
  16. // ウィンドウを右に移動する
  17. ++;
  18. // ウィンドウ内のデータに対して一連の更新を実行します
  19. if (need. count (c)) {
  20. ウィンドウ[c]++;
  21. if (window[c] == need[c])
  22. 有効++;
  23. }
  24.  
  25. // 左のウィンドウを縮小するかどうかを決定します
  26. while (有効 == need.size ()) {
  27. // ここで最小被覆部分文字列を更新します
  28. -< 長さ)の場合{
  29. 開始 =;
  30. len =-;
  31. }
  32. // dはウィンドウ外に移動する文字です
  33. char d = s[];
  34. // ウィンドウを左に移動する
  35. ++;
  36. // ウィンドウ内のデータに対して一連の更新を実行します
  37. 必要数( d)の場合
  38. if (window[d] == need[d])
  39. 有効- ;  
  40. ウィンドウ[d] --;  
  41. }
  42. }
  43. }
  44. // 最小の被覆部分文字列を返す
  45. len == INT_MAXを返しますか?
  46. "" : s.substr(開始, 長さ);
  47. }

Pythonでは、unnodeed mapはcollections.defaultdictとcollections.Counterを使用して実装できます。

<<:  人工知能の7つの応用シナリオ

>>:  興味深いアルゴリズムを知っていますか?

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

...

ベンジオとヒントンの絶え間ない探求:ディープラーニングアルゴリズムが脳の学習方法を明らかにする

[[384610]] 「脳の学習メカニズムや学習方法の一部を解明できれば、人工知能はさらに進歩できる...

確かにGANによって生成されました!中国のチームは瞳孔の形状で「本物」と「偽物」の肖像画を判定する

写真をじっくり見るだけで本物か偽物かがわかりますか?最近、ニューヨーク州立大学の中国人研究者が、目の...

...

ガートナー: 2020 年の人工知能の成熟度曲線、どのテクノロジーが価値があるか

1. ガートナー: 2018 年から 2020 年までの AI 成熟度曲線の概要最近、世界的に有名な...

速報です! ImageNetデータセット内のすべての顔はぼかされている

2012 年、AI 研究者はコンピューター ビジョンで大きな進歩を遂げ、ImageNet として知ら...

2020 年に爆発的に増加する 9 つの AI マーケティング トレンド

マーケティングに AI を使用すると、代理店の専門家の作業がさまざまな点で楽になります。消費者に合わ...

DxRアルゴリズムのアイデアに基づいて設計されたルーティングアイテム配置構造の図

まず、タイトルには、検索構造ではなく、ルーティング項目の配置構造と書かれています。つまり、この構造を...

GPT-4V でさえ解明できない未来推論の解決策があります!華中科技大学と上海理工大学出身

マルチモーダル大規模言語モデルは、強力な画像理解および推論機能を発揮します。しかし、現在の観察に基づ...

...

バイナリ検索ツリーの検証: インターネット上の古典的なアルゴリズム

[[427951]]この記事はWeChatの公開アカウント「Programmer Bear」から転載...

Python ベースのパーセプトロン分類アルゴリズムの実践

[[374354]]パーセプトロンは、バイナリ分類タスク用の線形機械学習アルゴリズムです。これは、人...

...

...

世界を席巻しているトップ10のプログラミングアルゴリズムを鑑賞しましょう

[[121078]]アルゴリズムは今日の私たちの生活にとって非常に重要なので、いくら強調してもし過ぎ...