劍指offer(面試題14): 動態規劃和貪心演算法求解最優化問題
阿新 • • 發佈:2019-02-17
題目
給定一長為n的繩子,要求把繩子剪成m段(m,n都是整數且n>1,m>1),每段繩子的長度記為k[0], k[1], k[2]…,k[m]。請問k[0]*k[1]*k[2]….*k[m]可能的最大乘積是多少?例如,當繩子的長度是8時,可以剪成2*3*3的三段得到最大的乘積。
解法
- 動態規劃
從下往下分析問題,從下往上解決問題。先計算當繩子長度為2,3,4等這些較小的容易看出的最大值,再以此往上計算n為較大值時乘積的最大值。演算法的時間複雜度是同時需要的空間複雜度。
#include <iostream>
using namespace std;
int maxProductAfterCutting(int length) {
if(length < 2)
return 0;
if(length == 2)
return 1;
if(length == 3)
return 2;
int* products = new int[length+1];
products[0] = 0;
products[1] = 1;
products[2] = 2;
products[3] = 3; // n == 4的初始值
int max;
for(int i = 4; i <= length ; ++i) {
max = 0;
// find the maximum among all possible value
for(int j = 1; j < i/2; ++j) {
int product = products[i] * products[i-j];
if(max < product) {
max = product;
}
products[i] = max;
}
}
max = products[length];
delete[] products;
return max;
}
貪心演算法
從數學角度證明貪心策略的正確性,然後應用數學公式推導,以的時間複雜度和空間複雜度計算該問題的最優化值。數學證明:對與長度為n的繩子,當其剪為長度為k和n-k的兩段繩子時,其乘積為,通過求導可以發現當k接近n/2時,其乘積最大。以此推及到n=4和n=5的情況(n<4的情況上述已經計算)。當n=4,則k=2時取得最大乘積;當n=5,則k=3時取得最大乘積。此時乘積為。因此當時,應該儘可能多地剪出長度為3的繩子段。(任何比5大的整數切分成兩段的結果最終都會歸結到繩子段長為3,4,5的情況)
int maxProductAfterCutting2(int length) {
if(length < 2) return 0;
if(length == 2) return 1;
if(length == 3) return 2;
// most cut of length 3
int timesOf3 = length/3;
// if remained length equals to 4
if(length - timesOf3 * 3 == 1)
timesOf3 -= 1;
int timeOf2 = (length - timesOf3*3)/2;
return (int)(pow(3,timesOf3)) * (int)(pow(2, timeOf2));
}