动态规划和贪心
剑指offer
以前没有好好学习算法,最近因为再看剑指offer看到动态规划和贪心就上了知乎看看大家的理解。
“某种程度上,动规是贪心的泛化,贪心是动规的特例。”
动规:大爆搜
贪心:把大爆搜剪枝剪到只有一条
贪心是求局部最优,以得到全局最优(不一定是正确的,需要证明)
dp是通过一些状态来描述一些子问题,然后通过状态之间的转移来求解(一般只要转移方程是正确的,答案必然是正确的)
贪心着眼现实当下,动规谨记历史进程。
借鉴这位博主的话
相同:
动态规划和贪心算法都是一种递推算法
均有局部最优解来推导全局最优解
不同点:
贪心算法:
1.贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留。
2.由(1)中的介绍,可以知道贪心法正确的条件是:每一步的最优解一定包含上一步的最优解。
动态规划算法:
1.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因此需要记录之前的所有最优解
2.动态规划的关键是状态转移方程,即如何由以求出的局部最优解来推导全局最优解
3.边界条件:即最简单的,可以直接得出的局部最优解
在动态规划之前要分析能否把大问题分解成小问题,分解后的小问题也存在最优解,如果把小问题的最优解组合起来能够得到整个问题的最优解。
动态规划的四个特点
- 求一个问题的最优解(通常是最大值或最小值)
- 该问题能划分为若干个子问题
- 子问题之间还有重叠的更小的子问题
- 由于子问题在分解大问题的过程中重复出现,为了避免重复求解子问题,我们可以从下往上的顺序先计算小问题的最优解并存储下来,再以此为基础求取大问题的最优解。从上往下分析问题,从下往上求解问题。
剪绳子问题
给你一根长度为n的绳子,请把绳子剪成m段(m,n都是整数,n>1,并且m>1)(m可以剪成2段,3段随你),每段绳子的长度记为k[0],k[1],k[2]..k[m],请问k[0]* k[1]* k[2]* k[3]* … k[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到得最大乘积是18。
思路:剪第一刀时有n-1种方式,剪出来的第一段绳子的可能长度分别为1,2,3..n-1。f(n)=max(f(i)*f(n-i)),i>0&&i
public class MaxCutRope {
public static void main(String[] args) {
System.out.println(maxCutRope(6));
}
public static int maxCutRope(int length){
//长度小于2,等于2,等于3时
if(length<2){
return 0;
}else if(length==2){
return 1;
}else if(length==3){
return 2;
}
int[] maxMultiply=new int[length+1];
maxMultiply[0]=0;
maxMultiply[1]=1;
maxMultiply[2]=2;
maxMultiply[3]=3;
for(int i=4;i<=length;i++){
int max=0;
for(int j=1;j<=i/2;j++){
if(max<maxMultiply[j]*maxMultiply[i-j])
max=maxMultiply[j]*maxMultiply[i-j];
}
maxMultiply[i]=max;
}
return maxMultiply[length];
}
}
从下到上计算每个长度的最大值。
贪心法
思路:当绳子长度>=5时尽可能多的去剪长度为3的绳子,当剩下绳子长度等于4时剪成2段绳子长度为2。
为什么这样的贪婪选择能得到最优解?
需要用数学公式去证明贪婪法是正确的。
当n>=5时
2*(n-2)>n 成立, 3 * (n-3)>=2*(n-2)成立
所以尽可能多的剪长度为3的绳子。
public static int greedyMaxCutRope(int length){
//长度小于2,等于2,等于3时
if(length<2){
return 0;
}else if(length==2){
return 1;
}else if(length==3){
return 2;
}
//尽可能多的剪长度为3的绳子
int numThree=length/3;
length=length%3;
//当剩下绳子长度为4时
if(length==1){
numThree--;
length+=3;
}
int numTwo=length/2;
return (int)(Math.pow(2,numTwo)*Math.pow(3,numThree));
}
总结
动态规划的四个特点
- 求一个问题的最优解(通常是最大值或最小值)
- 该问题能划分为若干个子问题
- 子问题之间还有重叠的更小的子问题
- 由于子问题在分解大问题的过程中重复出现,为了避免重复求解子问题,我们可以从下往上的顺序先计算小问题的最优解并存储下来,再以此为基础求取大问题的最优解。从上往下分析问题,从下往上求解问题。
贪心是求局部最优,以得到全局最优(不一定是正确的,需要证明)
某种程度上,动规是贪心的泛化,贪心是动规的特例。
基本是知乎上和剑指offer书上的大佬见解,通过这个例子稍微理解了,感谢感谢!