これは動的計画法の問題のようです。配列を構築するときは、特定の各インデックスまでの累積合計を含む別の配列を構築します。したがってi
、その配列のそれぞれには からの合計があり1..i
ます。
p..q
これで、インデックスの値の合計が であることが簡単にわかりますSUM(q) - SUM(p-1)
(特別な場合はSUM(0)
です0
)。明らかに、ここでは 1 ベースのインデックスを使用しています... この操作は O(1) なので、最適なものを見つけるには O(n) アルゴリズムが必要です。
p
簡単な解決策は、 andを追跡し、q
これらを配列内で処理することです。最初に展開しq
ます。次に、毛虫がアレイを這うように、収縮p
と拡張を繰り返します。q
展開するにはq
:
p <- 1
q <- 1
while SUM(q) - SUM(p-1) < K
q <- q + 1
end while
現在q
は、部分配列の合計がちょうど超えた (または等しい) 位置にありK
ます。サブ配列の長さは ですq - p + 1
。
ループの後、q
部分配列の長さが現在のベストよりも短いかどうかをテストします。次にp
、(最適なソリューションを誤ってスキップしないように) 1 ステップ進み、もう一度進みます。
配列を実際に作成する必要はありませんSUM
...サブ配列の合計を作成するだけで済みます...直前のものではなく、「実際の」を使用することに戻る必要がありますp
。
subsum <- VAL(1)
p <- 1
q <- 1
while q <= N
-- Expand
while q < N and subsum < K
q <- q + 1
subsum <- subsum + VAL(q)
end while
-- Check the length against our current best
len <- q - p + 1
if len < bestlen
...
end if
-- Contract
subsum <- subsum - VAL(p)
p <- p + 1
end while
ノート:
j_random_hacker は次のように述べています: O(n^2) の可能なすべての個別のサブ配列ではなく、このアルゴリズムが検査する O(n) の個別のサブ配列のみを検査することが許容される理由を正確に説明するのに役立ちます。
動的プログラミングの哲学は次のとおりです。
- 最適でない結果につながるソリューション パスをたどらないでください。と
- 以前の解の知識を使用して、新しい解を計算します。
この場合、単一の解候補 ( の(p,q)
ようなものp <= q
) は、要素の合計によって計算されます。これらの要素は正の整数であるため、任意の解候補(p,q)
について、解候補(p,q+1)
が大きくなることがわかっています。
(p,q)
したがって、 が最小解である場合はそうではないことがわかり(p,q+1)
ます。候補が見つかったらすぐに検索を終了し、その候補がこれまでに見たどの候補よりも優れているかどうかをテストします。つまり、各 に対してp
、1 つの候補のみをテストする必要があります。これにより、両方が増加するだけp
でq
なく、常に増加するため、検索は線形になります。
これの他の部分 (以前のソリューションを使用) はsum(p,q+1) = sum(p,q) + X(q+1)
、それと同様に認識することから来ていsum(p+1,q) = sum(p,q) - X(p)
ます。p
したがって、すべてのステップの間およびすべてのステップですべての要素を合計する必要はありませんq
。検索ポインターの 1 つを進めるたびに、1 つの値を加算または減算するだけで済みます。
それが役立つことを願っています。