剑指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 2 ) 同时需要 O(n) 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) O ( 1 ) 的时间复杂度和空间复杂度计算该问题的最优化值。

    数学证明:对与长度为n的绳子,当其剪为长度为k和n-k的两段绳子时,其乘积为 k(nk) k ( n − k ) ,通过求导可以发现当k接近n/2时,其乘积最大。以此推及到n=4和n=5的情况(n<4的情况上述已经计算)。当n=4,则k=2时取得最大乘积;当n=5,则k=3时取得最大乘积。此时乘积为 3(n3) 3 ( n − 3 ) 。因此当 n>=5 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));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值