投稿されたコードの説明は次のとおりです。これを効率的に機能させるための2つの重要なトリックがあります。(I)Kadaneのアルゴリズムと、(II)プレフィックス合計の使用です。また、(III)トリックをマトリックスに適用する必要があります。
パートI:カダネのアルゴリズム
Kadaneのアルゴリズムは、合計が最大の連続するサブシーケンスを見つける方法です。最大連続サブシーケンスを見つけるためのブルートフォースアプローチから始めて、それを最適化してKadaneのアルゴリズムを取得することを検討しましょう。
次のシーケンスがあるとします。
-1, 2, 3, -2
ブルートフォースアプローチの場合、シーケンスに沿って歩き、以下に示すようにすべての可能なサブシーケンスを生成します。すべての可能性を考慮して、各ステップでリストを開始、拡張、または終了できます。
At index 0, we consider appending the -1
-1, 2, 3, -2
^
Possible subsequences:
-1 [sum -1]
At index 1, we consider appending the 2
-1, 2, 3, -2
^
Possible subsequences:
-1 (end) [sum -1]
-1, 2 [sum 1]
2 [sum 2]
At index 2, we consider appending the 3
-1, 2, 3, -2
^
Possible subsequences:
-1, (end) [sum -1]
-1, 2 (end) [sum -1]
2 (end) [sum 2]
-1, 2, 3 [sum 4]
2, 3 [sum 5]
3 [sum 3]
At index 3, we consider appending the -2
-1, 2, 3, -2
^
Possible subsequences:
-1, (end) [sum -1]
-1, 2 (end) [sum 1]
2 (end) [sum 2]
-1, 2 3 (end) [sum 4]
2, 3 (end) [sum 5]
3, (end) [sum 3]
-1, 2, 3, -2 [sum 2]
2, 3, -2 [sum 3]
3, -2 [sum 1]
-2 [sum -2]
このブルートフォースアプローチでは、最終的に合計が最良のリストを選択し(2, 3)
ます。それが答えです。ただし、これを効率的にするために、すべてのリストを保持する必要はないことを考慮してください。終わっていないリストのうち、あなたは最高のものを保持する必要があるだけで、他のものはそれ以上のことはできません。終了したリストのうち、終了していないリストよりも優れている場合にのみ、最良のリストを保持する必要がある場合があります。
したがって、位置配列と合計配列だけで必要なものを追跡できます。位置配列は次のように定義されます。で終了し、で始まるposition[r] = s
リストを追跡します。そして、で終わるサブシーケンスの合計を与えます。この最適化されたアプローチは、Kadaneのアルゴリズムです。r
s
sum[r]
index r
この方法で進捗状況を追跡しながら、例をもう一度実行します。
At index 0, we consider appending the -1
-1, 2, 3, -2
^
We start a new subsequence for the first element.
position[0] = 0
sum[0] = -1
At index 1, we consider appending the 2
-1, 2, 3, -2
^
We choose to start a new subsequence because that gives a higher sum than extending.
position[0] = 0 sum[0] = -1
position[1] = 1 sum[1] = 2
At index 2, we consider appending the 3
-1, 2, 3, -2
^
We choose to extend a subsequence because that gives a higher sum than starting a new one.
position[0] = 0 sum[0] = -1
position[1] = 1 sum[1] = 2
position[2] = 1 sum[2] = 5
Again, we choose to extend because that gives a higher sum that starting a new one.
-1, 2, 3, -2
^
position[0] = 0 sum[0] = -1
position[1] = 1 sum[1] = 2
position[2] = 1 sum[2] = 5
positions[3] = 3 sum[3] = 3
繰り返しますが、最良の合計は5であり、リストはインデックス1からインデックス2、つまり(2、3)です。
パートII:プレフィックスの合計
任意の始点から任意の終点について、行に沿って合計を計算する方法が必要です。その合計を単に加算するのではなく、O(1)時間で計算したいのですが、これにはO(m)時間がかかります。ここで、mは合計の要素数です。いくつかの事前計算で、これを達成することができます。方法は次のとおりです。行列があるとします。
a d g
b e h
c f i
この行列は事前に計算できます。
a d g
a+b d+e g+h
a+b+c d+e+f g+h+i
これが完了すると、2つの値を減算するだけで、列の開始から終了まで、任意の列に沿って合計を実行できます。
パートIII:トリックをまとめて最大部分行列を見つける
最大部分行列の一番上の行と一番下の行がわかっていると仮定します。あなたはこれを行うことができます:
- 一番上の行より上の行を無視し、一番下の行より下の行を無視します。
- 残っている行列を使用して、各列の合計を使用してシーケンスを形成することを検討してください(複数の行を表す行のようなもの)。(プレフィックス合計アプローチを使用すると、このシーケンスの任意の要素を迅速に計算できます。)
- Kadaneのアプローチを使用して、このシーケンスの最良のサブシーケンスを見つけます。取得したインデックスは、最適な部分行列の左右の位置を示します。
さて、実際に一番上の列と一番下の列を理解するのはどうですか?すべての可能性を試してください。可能な限り上部を配置し、可能な限り下部を配置してみてください。すべての可能性について、前述のKadaneベースの手順を実行してください。最大値を見つけたら、上下の位置を追跡します。
行と列を見つけるには、O(M ^ 2)が必要です。ここで、Mは行数です。列の検索にはO(N)時間がかかります。ここで、Nは列の数です。したがって、合計時間はO(M ^ 2 * N)です。また、M = Nの場合、必要な時間はO(N ^ 3)です。