1. 程式人生 > >劍指offer(面試題14): 動態規劃和貪心演算法求解最優化問題

劍指offer(面試題14): 動態規劃和貪心演算法求解最優化問題

題目

給定一長為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為較大值時乘積的最大值。演算法的時間複雜度是O(n2)同時需要O(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; }
  • 貪心演算法
    從數學角度證明貪心策略的正確性,然後應用數學公式推導,以O(1)的時間複雜度和空間複雜度計算該問題的最優化值。

    數學證明:對與長度為n的繩子,當其剪為長度為k和n-k的兩段繩子時,其乘積為k(nk),通過求導可以發現當k接近n/2時,其乘積最大。以此推及到n=4和n=5的情況(n<4的情況上述已經計算)。當n=4,則k=2時取得最大乘積;當n=5,則k=3時取得最大乘積。此時乘積為3(n3)。因此當n>=5時,應該儘可能多地剪出長度為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));
}