Leetcode の基本アルゴリズム: スライディング ウィンドウについてお話しましょう

Leetcode の基本アルゴリズム: スライディング ウィンドウについてお話しましょう

[[434663]]

序文

LeetCode を練習していると、スライディング ウィンドウ タイプの問題によく遭遇します。スライディング ウィンドウの問題は非常に古典的かつ技術的であり、一般的に大企業で出題されます。今日は、スライディングウィンドウのルーチンを学びましょう。記事に間違いがあれば、指摘してください。ありがとうございます〜

  • スライディングウィンドウとは何ですか?
  • アルゴリズムの問​​題がスライディングウィンドウに入る
  • スライディングウィンドウを使用するとどのような問題を解決できますか?
  • スライディングウィンドウフレームルーチン
  • Leetcode ケース分析

スライディングウィンドウとは何ですか?

スライディングウィンドウという言葉は誰もが知っていると思います。 TCP について話すとき、私たちはしばしばスライディング ウィンドウ プロトコルについて話します。これは TCP プロトコルのアプリケーションであり、ネットワーク データ転送中に輻輳を回避するためのフロー制御に使用されます。

TCP ヘッダーには、16 ビットのウィンドウ サイズを表す win というフィールドがあります。これは、ローカル TCP 受信バッファが収容できるデータのバイト数を相手に伝え、相手側がデータの送信速度を制御できるようにすることで、フロー制御の目的を達成します。

TCP のスライディング ウィンドウは、ある瞬間のウィンドウ サイズが固定されたスライディング ウィンドウであり、ネットワーク トラフィックなどの要因が変化するとウィンドウ サイズも変化します。アルゴリズムのスライディング ウィンドウは、ウィンドウ (キュー/配列) を維持し、それを連続的にスライドさせて、答えを更新するという点で、多少似ています。スライディング ウィンドウとは、ある種の問題を解決する方法のことです。ある種の問題は、配列上の 2 つのポインターを同じ方向に移動することによって解決されます。

スライディングウィンドウアルゴリズムの例

アルゴリズムの問​​題を見てみましょう。整数配列が与えられた場合、長さ k の連続するサブ配列の最大合計を計算します。

  1. 入力: arr[] = {100,200,300,400} k = 2
  2.  
  3. 出力: 700
  4.  
  5. 説明: 300 + 400 = 700

この質問を見ると、すぐに力ずくで解決する方法を考えますが、2 つの for で十分です。

  1. 公共  int maxSum( int [] arry, int k) {
  2. 整数 サイズ= 配列の長さ;
  3. 整数最大合計 = 0;
  4.  
  5. ( int i = 0; i <サイズ- k + 1; i++) {
  6. int現在の合計 = 0;
  7. ( int j = 0; j < k; j++)の場合{
  8. 現在の合計 = 現在の合計 + 配列[i + j];
  9. }
  10.  
  11. maxSum = Math.max (現在の合計、最大合計);
  12. }
  13.  
  14. maxSumを返します
  15. }

ブルートフォース法では 2 つのネストされた for ループが使用され、時間の計算量は O(k*n) と理想的ではありませんが、スライディング ウィンドウ アルゴリズムではネストされたループの問題を解決し、時間の計算量を効果的に削減できます。

スライディングウィンドウは、ウィンドウを維持し、継続的にスライドさせてから、答えを更新するためです。 スライディング ウィンドウ アルゴリズムを使用して、次の手順を実行します。

k=2のとき、

  • 長さ2のウィンドウを維持し、最初のウィンドウ値の合計を初期化して保存することができます。
  • その後、ウィンドウは右にスライドし続け、スライドの過程で保存された最大値と比較され、答えが更新されます。
  • ウィンドウは右端までスライドするまで終了しません。

k=3の場合も同様

  • 長さ3のウィンドウを維持し、最初のウィンドウ値の合計を初期化して保存することができます。
  • その後、ウィンドウは右にスライドし続け、スライドの過程で保存された最大値と比較され、答えが更新されます。
  • ウィンドウは右端までスライドするまで終了しません。

したがって、次のようなコードを記述できます。

  1. 公共  int maxSum1( int [] arry, int k) {
  2. 整数 サイズ= arry.length;
  3.  
  4. (サイズ<k)の場合{
  5. -1 を返します
  6. }
  7.  
  8. // 最初のウィンドウ値の合計を初期化します
  9. 整数最大合計 = 0;
  10. ( int i = 0; i < k; i++) {
  11. 最大合計 = 最大合計 + arry[i];
  12. }
  13.  
  14. 整数 合計= 最大合計;
  15. ( int i = k; i <サイズ; i++) {
  16. 合計=合計+ 配列[i] - 配列[i - k];
  17. maxSum = Math.max (maxSum、合計);
  18. }
  19.  
  20. maxSumを返します
  21. }

スライディング ウィンドウを使用すると、時間の計算量は O(n) のみになります。

スライディングウィンドウはどのような問題を解決できますか?

スライディング ウィンドウを使用して解決できる LeetCode の問題はどれですか?

一般に、最小カバー部分文字列、最小の長さを持つサブ配列などの部分文字列の問題はすべて、スライディング ウィンドウ アルゴリズムを使用して解決できます。より典型的なスライディングウィンドウの質問は次のとおりです。

  • 重複文字のない最長の部分文字列
  • 最小被覆部分文字列
  • 単語のすべての部分文字列を連結する
  • 最大2つの異なる文字を含む最長の部分文字列
  • 最小の長さを持つサブ配列
  • スライディングウィンドウの最大値
  • 弦の配置
  • 最小ウィンドウサブシーケンス

これらはすべて Leetcode からのオリジナルの質問です。Leetcode の公式 Web サイトにアクセスして、質問の雰囲気をつかんでください。

スライディングウィンドウフレームルーチン

スライディング ウィンドウの一般的な論理フレームワーク、疑似コードは次のとおりです。

  1. 整数 = 0、= 0;
  2. while (< s.size ()) {
  3. // ウィンドウを大きくする
  4. window.add (s[]);
  5. ++;
  6.    
  7. while (ウィンドウを縮小する必要がある){
  8. // ウィンドウを縮小する
  9. window.remove (s[]);
  10. ++;
  11. }
  12. }

基本的なプロセスは次のとおりです。

  • まず最初に、元の文字列の長さを取得します。
  • 次にウィンドウ(配列、ハッシュ、キュー)を維持します
  • ウィンドウは段階的に右に拡大します
  • ウィンドウが拡大して右にスライドしているときに、左側を縮小する必要があるかどうかを判断する必要があります。
  • 最終比較更新回答

このフレームワークを使用して、実際の LeetCode の質問を解決してみましょう。

タイトル: 文字列 s が与えられた場合、重複する文字を含まない最長の部分文字列の長さを計算してください。

例1:

  1. 入力: s = "abcabcbb"  
  2. 出力: 3
  3. 説明: 重複文字のない最長の部分文字列は「abc」なので、その長さは 3 です。

例2:

  1. 入力: s = "bbbbb"  
  2.  
  3. 出力: 1
  4.  
  5. 説明: 重複文字のない最長の部分文字列は「b」なので、その長さは 1 です。

重複した文字があるかどうかを判断する必要があるため、ウィンドウとしてハッシュセット(HashSet)を使用します。

  1. int lengthOfLongestSubstring(文字列 s){
  2. //元の文字列の長さを取得します
  3. int len ​​= s.length();
  4. //ハッシュコレクションウィンドウを維持する
  5. <文字>を設定します。windows = new HashSet<>();
  6. 整数 = 0、= 0;
  7. 整数res =0;
  8.  
  9. while(<len){
  10. char c = s.charAt();
  11. //ウィンドウを右に移動する
  12. ++;
  13.  
  14. //左のウィンドウを縮小する必要があるかどうかを判断します。すでに含まれている場合は縮小する必要があります
  15. while ( windows.contains (c)){
  16. windows.remove(s.charAt());
  17. ++;
  18. }
  19. ウィンドウズ.add (c);
  20. // 答えを比較して更新する
  21. res = Math.max ( res,windows.size ());
  22. }
  23. resを返します
  24. }

Leetcode ケース分析

印象を深めるために、実際の LeetCode の質問をもう一つ見てみましょう。

タイトル: 文字列 S と文字列 T が与えられます。 T 内のすべての文字を含む S の最小の部分文字列を返します。 S に T のすべての文字を含む部分文字列がない場合、空の文字列 "" が返されます。

例1:

  1. 入力: s = "ADOBECODEBANC" 、t = "ABC"  
  2.  
  3. 出力: "BANC"  

例2:

  1. 入力: s = "a" 、t = "a"  
  2.  
  3. 出力: "a"  

私たちは今でもこのフレームワークプロセスを適用しています:

  1. - まず、元の文字列の長さを取得します。
  2.  
  3. - 次にウィンドウ(配列、ハッシュ、キュー)を維持します
  4.  
  5. - ウィンドウが段階的に右に拡大します
  6.  
  7. - ウィンドウが拡大して右にスライドしているとき、左側を縮小する必要があるかどうかを判断する必要があります。
  8.  
  9. - 前回の比較更新された回答

元の文字列の長さを取得します。

これは比較的簡単です。元の質問では、文字列 S をトラバースするために左ポインタと右ポインタがまだ必要だからです。

  1. int len ​​= S.length();

次にウィンドウ(配列、ハッシュ、キュー)を維持し、右にシフトし、左に減らす

まず、長さが 0 の最小ウィンドウを定義します。ウィンドウを定義するときは、ウィンドウがいつ右に移動するのか、いつ左に縮小するのか、そしてどのように比較して答えを更新するのかを考える必要があります。

最小のウィンドウを右にシフトできるのはいつですか? 質問では T のすべての部分文字列をカバーする必要があるため、ウィンドウは T のすべての文字が含まれるまで先頭で右にシフトできます。

明らかに、ウィンドウ文字列 ADOBEC は、T のすべての文字をカバーする S の最初の部分文字列です。ただし、私たちが探しているのは最小の部分文字列であり、ADOBEC が最小のものではない可能性があります。なぜなら:

  • 1. 現在のウィンドウには、タイトル条件を満たす小さなサブウィンドウ文字列が含まれている可能性があります。 (左側は縮小可能)
  • 2. ウィンドウがスライドしていない領域に、条件を満たす小さな文字列が含まれている可能性があります。 (ウィンドウは右に移動し続けることができます)

条件を満たす最初のウィンドウ文字列 ADOBEC を見つけた後、より小さな子ウィンドウ文字列を探します。我々はできる:

  • 1. 左側を縮小します。縮小されたウィンドウにまだ T のすべての文字が含まれている場合、現在のウィンドウは最小の部分文字列である可能性があります。それを格納し(スライディングウィンドウフレームの更新された回答と同様に)、左からウィンドウを縮小し続けます。
  • 2. ウィンドウを縮小しても T を含むすべての文字が収まらない場合は、ウィンドウの左側の縮小を停止し、ウィンドウを右側に拡大することができます。

ウィンドウは最初に左側に縮小され、次に右側に移動し、条件を満たすウィンドウが保存されます

上記の手順を繰り返し、条件を満たすウィンドウを保存し、比較して最小の部分文字列を取得します。条件を満たす最小の部分文字列はBANCである

この問題の難しいところは、実際には S の部分文字列に T が含まれているかどうかをどうやって判断するかということです。コードを見てみましょう。

  1. クラスソリューション{
  2. パブリック文字列minWindow(文字列s、文字列t) {
  3. s.length() == 0 || s.length() < t.length() の場合 {
  4. 戻る  "" ;
  5. }
  6.  
  7. int sLen = s.length();
  8. Map<文字整数> lookup = new HashMap<>();
  9.           
  10. ( int i = 0; i < sLen; i++) {
  11. lookup.put(s.charAt(i), 0);
  12. }
  13.  
  14. ( int i = 0; i < t.length(); i++) {
  15. 文字c = t.charAt(i);
  16. (lookup.containsKey(c))の場合{
  17. lookup.put(c, lookup.get(c) + 1);
  18. }それ以外{
  19. 戻る  "" ;
  20. }
  21. }
  22.  
  23. 整数 = 0;
  24. 整数 = 0;
  25. int minLen = Integer.MAX_VALUE ;
  26. int tCount = t.length();
  27. 文字列結果 = "" ;
  28. 右の長さがsLen未満の場合)
  29. char c = s.charAt();
  30. lookup.get(c) > 0 の場合、tCount --;  
  31. lookup.put(c, lookup.get(c) - 1);
  32. //ウィンドウを右に移動する
  33. ++;
  34.              
  35. //すでにTの文字がすべて含まれています
  36. (tCount == 0) の間 {
  37. // 答えを比較して更新する
  38. (最小長さ>-)の場合{
  39. minLen =-;
  40. 結果 = s.substring ();
  41. }
  42. char c2 = s.charAt();
  43. lookup.get(c2) == 0 の場合、tCount++;
  44. lookup.put(c2, lookup.get(c2) + 1);
  45. // ウィンドウを左から縮小する
  46. ++;
  47. }
  48. }
  49. 結果を返します
  50. }
  51. }

leetcode 提出の結果は次のとおりです。

<<:  毎日のアルゴリズム: 回文部分文字列

>>:  AI 駆動型データ分析ツールが企業や組織にもたらすメリット

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

推薦する

音声認識:市場の見通しは有望だが、コア技術にはまだブレークスルーが必要

人工知能製品が私たちの生活の中でますます普及するにつれて、テクノロジーの発展は社会の関心の焦点となっ...

...

AIによる顔を変える技術によって危害を受けるのではないかと心配ですか?怖がらないで!ディープフェイク偽造対策チームが到着

ディープフェイクは登場以来、人間性の暗い側面へと向かっています。 Bステーションのユーザーは、陸小玲...

清華大学の光電子コンピューティングにおける新たなブレークスルー:チップの性能が1万倍向上、研究がネイチャー誌でトップに

各種の大規模モデルやディープニューラルネットワークの登場により、人工知能の発展に対応し、高い計算能力...

ChatGPT は IT ネットワーク エンジニアの代わりになるのでしょうか?

現代の IT ネットワークは、ファイアウォール、ルーター、スイッチ、サーバー、ワークステーション、そ...

サイバー犯罪者はAIを利用してマルウェア攻撃ソフトウェアにサンドボックスを作成

2020 年に世界中の企業の 42% がサイバー攻撃を受けたことをご存知ですか? サイバー犯罪者が...

この「水中トランスフォーマー」はNASAによって困難な水中作業のためにテストされている。

[[273668]] ▲写真:アクアノートロボットがNASAの中立実験室で水中浮遊テストを受けてい...

自動運転と軌道予測についてはこちらの記事をお読みください。

この記事は、Heart of Autonomous Driving の公開アカウントから許可を得て転...

2019年の人工知能の予測と展望

2019 年に人工知能の分野はどのように進化するでしょうか? 過去数年と比べてどのように変化するでし...

人工知能:今優先すべき7つの役割

近年の退職者の急増は、労働力不足が現実であることを示している。セントルイス連邦準備銀行の調査によると...

産業用ロボットの開発動向

産業用ロボットは、さまざまな産業用タスクを自動的に実行できる一種の機器として、製造、組み立て、梱包、...

ビジネスプロセス管理を使用してマイクロサービス、人、ロボットを調整する方法

DevOps チームがプロセスの自動化を計画している場合は、ビジネス プロセス管理 (BPM) エン...

Baidu Brain の「EasyDL Classic Edition」はあなたを魅了しました。実際の業界アプリケーションを手に入れましたか?

既存のビジネスやソリューションをベースに、企業は AI 機能を導入することで、どのようにすれば効率性...

ディープラーニングの深層: モデリング知識とオープンソースツールのオプション

[51CTO.com クイック翻訳] この記事では、ディープラーニングアルゴリズムを使用してデータモ...

月給5万ドルでこのホットなAI分野をマスターするには、これらの9冊の本を読むだけで十分です

はじめに:国内の求人検索サイトのデータによると、2019年現在、上海の自然言語処理(NLP)関連職種...