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

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

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

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

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

推薦する

顔の特徴を検出するシンプルなディープラーニング手法を教えます

著者注: 携帯電話で、人の顔に特殊効果を加えるアプリを見たことがあるかもしれません。これらのアプリは...

大型模型シリーズ - RAGの解釈

RAG は、2023 年に最も人気のある LLM ベースのアプリケーション システム アーキテクチャ...

人工知能が中国の古典「古いドラマ」と「古い映画」に新たな表情を与える

映画「トンネル戦争」修復前と修復後の比較。画像はインタビュー対象者より提供新華社北京1月1日(記者フ...

Panda-Gym のロボットアームシミュレーションを使用したディープ Q 学習強化学習

強化学習 (RL) は、エージェントが試行錯誤を通じて環境内でどのように動作するかを学習できるように...

マイクロソフト、進化拡散法を用いたタンパク質生成のための新しい AI フレームワーク EvoDiff をオープンソース化

進化により、細胞プロセスを正確に制御する多様な機能性タンパク質が生み出されました。近年、この多様性か...

アートデザインにおける人工知能

AdobeやCelsysなどのソフトウェア企業は近年、デジタルデザインソフトウェアに人工知能機能を追...

ディープラーニングの限界と将来

[[227297]]注: この記事は、Keras の作者である François Chollet に...

CCTV、春節に初めてバーチャル司会者サ・ベイニン氏を迎える

AIブロックチェーン企業の技術が中国の重要な国家夜会で正式に使用された。 2019年のオンライン春節...

初心者のための NLP: 先のことを心配せずに、1 つの記事でコーパスの前処理を理解しましょう

自然言語処理は AI の最高峰であり、コーパス前処理は自然言語処理の基礎です。 [[336067]]...

...

GPT-4より18倍高速、世界最速の大型モデルGroqが登場!毎秒500トークンが記録を破る、自社開発LPUはNVIDIA GPUの10倍

気がつくと、1 秒あたり 500 トークンを出力できる Groq モデルがインターネット上に広まって...

ホワイトハウスのAIに関する大統領令がサイバーセキュリティリーダーに何を意味するか

AIは引き続きテクノロジーの注目を集めており、2023年の最後の四半期を迎えるにあたり、AIの力を活...

Google 数学 AI が Nature に発表: IMO 金メダルの幾何学レベル、定理証明は呉文軍の 1978 年の法則を上回る

Google DeepMindが再びNatureを出版、AIのAlphaシリーズが力強く復活、数学レ...

Transformer のコンテキスト学習機能はどこから来るのでしょうか?

トランスフォーマーはなぜ優れたパフォーマンスを発揮するのでしょうか?多くの大規模言語モデルにもたらさ...