問題の説明:
長さ n のロープが与えられた場合、ロープを整数の長さの m 個のセグメントに切断してください (m と n は両方とも整数、n>1 および m>1)。各ロープの長さは k[0],k [ 1]...k[m-1] 。k[0] k[1]*...*k[m-1] の積の最大値は何ですか? たとえば、ロープの長さが 8 の場合、長さが 2、3、3 の 3 つの部分に切断します。このとき得られる最大の製品は 18 です。
例:
输入: 2 输出: 1 解释: 2 = 1 + 1, 1 × 1 = 1
输入: 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
問題解決のアイデア:
1.動的計画法の考え方は数学の考え方です
正の整数 n の場合、n≧2 の場合、少なくとも 2 つの正の整数の合計に分割できます。最初に分割された正の整数を k とすると、残りの部分は n-k になります。n-k はそれ以上分割されないか、少なくとも 2 つの正の整数の合計に分割され続ける場合があります。各正の整数に対応する最大積は、より小さい正の整数に対応する最大積に依存するため、動的計画法を使用してそれを解くことができます。
配列 array の意味: array[i] は、正の整数 i を少なくとも 2 つの正の整数の合計に分割した後の、これらの正の整数の最大積を表します。
境界条件: 0 は正の整数ではなく、1 は最小の正の整数で、0 も 1 も分割できないため、array[0]=array[1]=0 となります。
**状態遷移方程式: **i≥2 の場合、正の整数 i から分割された最初の正の整数が j (1≤j<i) であると仮定すると、次の 2 つのオプションがあります。
i を j と i-j の合計に分割すると、i-j は複数の正の整数に分割されなくなり、このときの積は j×(i-j) になります。
i を j と i−j の和に分割し、さらに i−j を複数の正の整数に分割します。このときの積は j × array[i−j] となります。
したがって、j が固定の場合、array[i]=max(j×(i-j),j×array[i-j]) となります。j の値の範囲は 1 から i-1 であるため、array[i] の最大値を取得するにはすべての j を走査する必要があるため、状態遷移方程式は次のように取得できます。
array[n] の最終値は、正の整数 n を少なくとも 2 つの正の整数の合計に分割した後の、これらの正の整数の最大積です。
コード
class Solution {
public int cuttingRope(int n) {
//建立数组用于存放绳子剪后每一段绳子
int[] array = new int[n + 1];
array[2] = 1;
//遍历获取各种可能下的乘积
for(int i = 3;i < array.length;i++){
for(int j = 1;j < i;j++){
//判断array[i]的最大值
array[i] = Math.max(array[i],Math.max(j*(i - j),j * array[i - j]));
}
}
return array[n];
}
}
2.貪欲な考え
ロープを 3 つの等しい長さに切断すると、得られる製品が最大になります。アイデアを結び付けて導き出すことができる一連の数学理論があります
セグメンテーション ルール:
最適: n 3. ロープをできるだけ多くの長さ 3 の部分に切ります。最後に残ったロープの長さは 3 つの状況で 0、1、2、2 になります。
次善:n 2 。最後のロープの長さが 2 の場合、それは保持され、1+1 に分割されません。
最悪:n 1秒。最後のロープの長さが 1 の場合、3 + 1+1 の一部を 2 + 2+2 に置き換える必要があります。
コード
class Solution {
public int cuttingRope(int n) {
//n < 4时,结果都是n - 1
if(n < 4){
return n - 1;
}
//尽可能的得到n能分成多少个3
int a = n / 3;
int b = n % 3;
//判断取3后的余数
if(b == 0){
//利用Math.pow()计算n次方结果,结果由于是double对此进行int强转
return (int)Math.pow(3,a);
}else if(b == 1){
return (int)Math.pow(3,a - 1) * 4;
}else{
return (int)Math.pow(3,a) * 2;
}
}
}