動的プログラミングの考え方についてはここでは詳しく説明しませんが、理解する必要がある場合は、この記事「動的計画の手順」を読んでください。
直接トピックに進み、動的プログラミングのアイデアを使用して343. 整数分割 - LeetCodeを解決しましょう。
最初のステップは、配列 dp を決定し、整数を分割した後に得られる最大の積を格納する配列を作成することです。
# 确定数组的长度,每次拆分的计算结果是为上一次的最大乘积,作为占位符。
dp = [0] * (n+1)
2 番目のステップは、配列 dp の初期値を決定することです。
質問から、n == 0 または n == 1 を分割するのは無意味であることがわかります。明らかに、n == 2 を分割すると、2 = 1 + 1 が得られるため、最大の積は 1 になります。、dp[2] = 1、その後計算される積の結果も dp[2] の結果に基づきます。
dp[2] = 1
3 番目のステップは、状態遷移方程式を決定することです。dp[i] = max(dp[i], j * (ij), j * dp[i - j])
簡単な例で説明すると、n = 5 の場合、dp 配列には各整数を分割して得られる最大積の値が格納されます。
注意すべき問題がいくつかあります。
1. 分割問題: 2 つ以上の整数の加算が元の数値と等しく、分割値の積が最大になるように整数を分割する必要があります。したがって、2 つの正の整数を分割してから、それらを分割するかどうかを検討する必要があります。
1) i を j と i−j の和に分割すると、i−j は複数の正の整数に分割されなくなり、このときの積は j * (ij) となります。
2) i を j と i−j の和に分割し、さらに i−j を複数の正の整数に分割します。このときの積は j * dp[ij] です。このとき、前の値が必要です。 dp 配列値が呼び出されます。
2. j は 1 からトラバースを開始します。ij は、分割する必要がある n の値から、対応する j のトラバース値を減算するものとして理解できます。
j * (i - j) は 2 つの整数を分割した積です。
3. j * (i - j) と j * dp[ij] の積の最大値を比較する必要があります。
したがって、状態遷移方程式は次のようになります。 dp[i] = dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
for i in range(3, n + 1):
for j in range(1, i - 1):
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
4 番目のステップは、走査順序を決定することです。
dp[i] は dp[i - j] の状態に依存するため、i のトラバースは前から後ろにトラバースする必要があります。i は 3 から始まり、j を列挙する場合は 1 から始まります。このように、dp[i - j] は dp[2] となり、初期化した値によって計算できます。
例として n = 5 を使用する 5 番目のステップは、上の表から推測できます。
Pythonコードの表示:
def integerBreak(n):
dp = [0] * (n + 1)
dp[2] = 1
for i in range(3, n + 1):
for j in range(1, i - 1):
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
return dp[n]
print(integerBreak(5))