动态规划和贪心

动态规划和贪心

剑指offer

https://www.zhihu.com/question/32096465

以前没有好好学习算法,最近因为再看剑指offer看到动态规划和贪心就上了知乎看看大家的理解。

“某种程度上,动规是贪心的泛化,贪心是动规的特例。”

动规:大爆搜
贪心:把大爆搜剪枝剪到只有一条

贪心是求局部最优,以得到全局最优(不一定是正确的,需要证明)

dp是通过一些状态来描述一些子问题,然后通过状态之间的转移来求解(一般只要转移方程是正确的,答案必然是正确的)

贪心着眼现实当下,动规谨记历史进程。

https://blog.csdn.net/jarvischu/article/details/6056387

借鉴这位博主的话

相同:

动态规划和贪心算法都是一种递推算法
均有局部最优解来推导全局最优解

不同点:
贪心算法:
1.贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留。
2.由(1)中的介绍,可以知道贪心法正确的条件是:每一步的最优解一定包含上一步的最优解。

动态规划算法:
1.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因此需要记录之前的所有最优解
2.动态规划的关键是状态转移方程,即如何由以求出的局部最优解来推导全局最优解
3.边界条件:即最简单的,可以直接得出的局部最优解

在动态规划之前要分析能否把大问题分解成小问题,分解后的小问题也存在最优解,如果把小问题的最优解组合起来能够得到整个问题的最优解。

动态规划的四个特点

  1. 求一个问题的最优解(通常是最大值或最小值)
  2. 该问题能划分为若干个子问题
  3. 子问题之间还有重叠的更小的子问题
  4. 由于子问题在分解大问题的过程中重复出现,为了避免重复求解子问题,我们可以从下往上的顺序先计算小问题的最优解并存储下来,再以此为基础求取大问题的最优解。从上往下分析问题,从下往上求解问题。

剪绳子问题

给你一根长度为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));
    }

总结

动态规划的四个特点

  1. 求一个问题的最优解(通常是最大值或最小值)
  2. 该问题能划分为若干个子问题
  3. 子问题之间还有重叠的更小的子问题
  4. 由于子问题在分解大问题的过程中重复出现,为了避免重复求解子问题,我们可以从下往上的顺序先计算小问题的最优解并存储下来,再以此为基础求取大问题的最优解。从上往下分析问题,从下往上求解问题

贪心是求局部最优,以得到全局最优(不一定是正确的,需要证明

某种程度上,动规是贪心的泛化,贪心是动规的特例

基本是知乎上和剑指offer书上的大佬见解,通过这个例子稍微理解了,感谢感谢!

    原文作者:动态规划
    原文地址: https://blog.csdn.net/u013164931/article/details/79844880
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞