当前位置: 首页 > 科技观察

请不要再问我关于贪心算法的问题了!_0

时间:2023-03-21 16:01:40 科技观察

前言贪心算法可以用来求三角形的最短路径和吗?所以本文打算简单介绍一下贪心算法。介绍完了我们来看看这个三角形最短路径问题能不能用贪心算法解决。本文将从以下几个方面介绍贪心算法。什么是贪心算法?贪心算法就是一个例子。选择时,做出当前阶段(或状态)的最佳选择,期望结果是全局最优解(但不一定是全局最优解)。贪心算法其实是动态规划的一种,因为它的“贪心”只关注当前阶段的最优解,所以每个子问题只会计算一次。如果由此得到全局最优解,与动态规划相比,需要对每个子问题都求全局最优解,其时间复杂度无疑下降了一个数量级。举个简单的例子,比如给定一定数量(比如250)和100、50、10、5、1张纸币(不限)的数量,这个数量怎么用最少数量的纸币兑换?显然每次兑换都要从大面额的纸币开始,第一次选择100,第二次选择100,第三次选择次大的50元,选择最大面额小于的纸币每次的剩余量,这样得到的解一定是全局最优解!时间复杂度无疑是线性的。我们先看一些贪心算法可以解决的示例问题我们现在要给这些孩子分发糖果,但是糖果少,孩子多(ma.start));//第一次遍历从-1,0开始returnremoveSubDuplicate(-1,0,间隔);}privatestaticIntegerremoveSubDuplicate(intpre,intcur,Interval[]intervals){if(cur==intervals.length){return0;}intnotRemove=Integer.MAX_VALUE;if(pre==-1||intervals[pre].end<=intervals[cur].start){/***如果是第一次遍历,或者pre区间的终点小于cur区间的起点(即区间不重叠),*thenpre=cur;cur=cur+1*/notRemove=removeSubDuplicate(cur,cur+1,intervals);}/***如果pre区间的终点大于cur区间的起点,是我ans两个区间重叠,cur指向下一个区间,即cur=cur+1*表示cur被移除,所以需要加1(代表这个区间被移除)*/intremove=removeSubDuplicate(pre,cur+1,intervals)+1;//取两者中较小的值returnMath.min(notRemove,remove);}publicstaticvoidmain(String[]args){//初始化intervalInterval[]intervals={newInterval(1,2),newInterval(3,5),newInterval(4,7),newInterval(8,10),newIinterval(9,11)};intresult=removeDuplicateIntervas(intervals);System.out.println("result="+result);}}2.分析递归过程中是否存在大量重复的子问题和如何判断是否存在大量重复的子问题,在学习动态规划解题技巧的第一篇文章中,我们提出了画递归树的解法,但是为此画递归树比较麻烦问题,其实我们可以简单分析一下组合问题,对于每个区间,要么选择,要么不选择。我们用1表示区间被选中,0表示区间未被选中。那么简单考虑下面两个组合1101011001,仔细看,红框里的部分是重复的子题!可能有人会说这种分析也有点难,那我再教大家一招,打印!如图,在递归函数中打印出来,然后分析打印的规则,可以看到确实存在重复的子问题。时间复杂度是多少?选择或不选择每个间隔。一共有两种状态。如果有n个区间,就是2^n,所以我们知道时间复杂度是O(2^n),呈指数级!显然不能接受,因为存在重复问题,那么我们进入动态规划的第三步3。使用备忘的方法保存子问题的解,避免大量的重复计算(剪枝)。在上面的分析中,我们基本看出,其实pre,cur可能存在很多重复,所以我们保存pre和cur对应的中间结果,如下//SavetheintermediateresultsprivatestaticHashMapmap=newHashMap();privatestaticIntegerremoveSubDuplicate(intpre,intcur,Interval[]intervals){Stringkey=pre+","+cur;if(map.get(key)!=null){returnmap.get(key);}if(cur==intervals.length){return0;}intnotRemove=Integer.MAX_VALUE;if(pre==-1||intervals[pre].end<=intervals[cur].start){notRemove=removeSubDuplicate(cur,cur+1,间隔);}间歇期ve=removeSubDuplicate(pre,cur+1,intervals)+1;intresult=Math.min(notRemove,remove);map.put(key,result);returnresult;}形式缓存子问题的中间结果后ofmemo,时间复杂度直线下降到O(n^2)(因为pre和cur这两个变量不断向后移动,也就是两层循环,所以是O(n^2))4.使用一种自下而上的递归方法,即动态规划。我们定义dp[i]为从0到第i个区间的最大非重叠区间数,因此我们得到状态转移方程dp[i]=max{dp[j]}+1,其中0<=jinterval[j].end需要满足,即保证i和j指向的区间不重叠。那么最后的dp[区间总数-1]就是连续不重叠区间的最大个数,那么区间总数-连续不重叠区间的最大个数就不是要去掉的区间的最小个数。dp方程,写代码很快,如下/***判断两个区间是否重叠,第i区间的起点大于j区间,如果j区间的终点大于第i个区间的起点,然后重叠*/privatestaticbooleanisOverlapping(Intervali,Intervalj){returnj.end>i.start;}/***动态规划解法*/privatestaticIntegerremoveSubDuplicateWithDP(Interval[]intervals){//根据区间排序到起点从小到大Arrays.sort(intervals,Comparator.comparingInt(a->a.start));int[]dp=newint[intervals.length];Arrays.fill(dp,0);dp[0]=1;//设置dp[0]为1,因为即使所有区间重叠,连续不重叠的区间也至少为1intresult=1;for(inti=1;ia.end));intcur=0;//设置第一个为当前区间intcount=1;//最大不重叠区间数,最小为1for(inti=1;i