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

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

[[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つの応用シナリオ

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

ブログ    

推薦する

協働ロボットが製造業の未来に与える大きな影響

近年、協働ロボットはサイバー空間でよく使われる用語になりました。信頼性と効率性が厳しく問われているに...

...

浙江大学の「ホッキョクグマセーター」がサイエンス誌に掲載、ダウンジャケットの5倍の断熱効果

最近は寒波が次々と襲来し、ダウンジャケットは冬を過ごすための必需品となっています。浙江大学は、暖かい...

企業がAI対応データベースを使用してAI導入を加速する方法

企業は、AI を搭載し、AI 向けに構築されたデータベースを検討する必要があります。最適化と使いやす...

AirPodsは「あなたの脳を読む」ことができるのか?あるいは汗中の乳酸濃度も監視できるタイプ|ネイチャー

AirPods は脳の信号を監視できますか? !それともアルツハイマー病やパーキンソン病を予測できる...

機械はどのように学習するのでしょうか?人工知能の「双方向戦闘」を詳しく解説

金庸の武侠小説『射雁英雄伝』には、桃花島に閉じ込められた「悪童」周伯同が「左右の格闘術」を編み出した...

...

AIの未来: 汎用人工知能

人工知能を真に理解するために、研究者は、環境に対する人間のような理解を再現できる基礎的な AGI 技...

調査によると、AIはデータ文化に大きな影響を与えている

2023年はGenAIの年ですが、GenAI(生成型人工知能)の採用率は期待に応えていません。ほとん...

強力な視覚 AI でもこれらの写真を正確に識別できないのはなぜでしょうか?

▲ テーブルの上にいるのはマンホールの蓋でしょうか、それともトンボでしょうか?(写真提供:ダン・ヘ...

中国のAI臨床診断がネイチャー誌に初掲載:71人の専門家が人間の医師を上回る精度の報告書を寄稿

[[257228]] 【新知能紹介】中国内外の科学者71人が共同で、検査結果を検知し、医師と同じくら...

データセンター管理者は AI と ML の爆発的な増加にどのように備えればよいのでしょうか?

生成 AI と機械学習 (ML) は急速に一般の人々の意識に入り込み、これらの有望なテクノロジーの能...

機械知能のための TensorFlow 実践: 製品環境へのモデルの導入

TesnsorFlow を使用して、基本的な機械学習モデルから複雑なディープラーニング ネットワーク...

...

機械学習の実践者が直面する8つの大きな課題

機械学習 (ML) や人工知能 (AI) と聞くと、多くの人はロボットやターミネーターを想像します。...