一、什么是动态规划
不懂动态规划的程序猿,不是好攻城狮。
在面试算法题时,当你看到以下四个特点时,脑海中就应该想到【动态规划】这四个词了。
【1】求一个问题的最优解(最大值或者最小值);
【2】该问题可以分解成类似的若干个子问题,即整个问题的最优解是依赖于各个子问题的最优解;
【3】分解后的子问题还有相互重叠的更小的子问题,换句话说在算法计算中我们会重复计算某些个子问题的值,因此,为了提高效率,我们需要合理利用(保存)已经计算过的值,不能做重复的操作;
【4】分析问题时,从整体到局部亦或说从上至下分析,解题时从下往上求解问题,这样可以利用已经计算过的值去解决更大一点问题的值。
二、应用实例
题目大意:
给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n>1并且m>1)每段绳子的长度记为k[0],k[1],…,k[m].请问k[0]k[1]…*k[m]可能的最大乘积是多少?例如,当绳子的长度为8时,我们把它剪成长度分别为2,3,3的三段,此时得到的最大乘积是18.
代码实现(java):
/**
* @author lm
* @create 2018-03-27 14:39
* @desc dd
**/
public class CuttingRope {
public int maxAfterCutting(int length) {
if (length < 2) return 0;
if (length == 2) return 1;
if (length == 3) return 2;
/*
声明整形数组,用于保存中间结果;
子问题的最优解存储在数组中,数组中的第i个元素表示把长度为i的绳子剪成若干段后各段长度乘积的最大值。
*/
int resultArr[] = new int[length + 1];
resultArr[0] = 0;
resultArr[1] = 1;
resultArr[2] = 2;
resultArr[3] = 3;
int max = 0;
//求每个i的最大值
for (int i = 4; i <= length; i++) {
max = 0;
for (int j = 1; j <= i/2; j++) {
int tempResult = resultArr[j] * resultArr[i - j];
if (tempResult > max) {
max = tempResult;
}
resultArr[i] = max;
}
}
max = resultArr[length];
return max;
}
}
//测试用例
public class CuttingRopeTest {
CuttingRope cuttingRope = new CuttingRope();
@Test
public void maxAfterCutting() throws Exception {
assertEquals(4, cuttingRope.maxAfterCutting(4));
assertEquals(18, cuttingRope.maxAfterCutting(8));
assertEquals(2, cuttingRope.maxAfterCutting(3));
}
}
总结
本题是一道典型的动态规划算法题,为了避免递归产生的重复计算,采用了从下而上的计算顺序实现。