【LeetCode-java】复习专题(4):贪心算法[0804]

200804今天复习专题写的是贪心算法的122. 买卖股票的最佳时机II55. 跳跃游戏 Jump Game134. 加油站 Gas Station

4. 贪心算法

今天不讲太多太难的题了,就讲一下贪心算法。贪心算法还是很要有研究的。《算法导论》上有关于贪心算法的一些证明。当然看一些国内的教材如《算法设计与分析》会从归纳的角度证明贪心算法的全局最优性。

122. 买卖股票的最佳时机II Best Time to Buy ans Sell Stock II

  • 难度:简单
  • 这个题不多说了,非常经典的贪心算法的简单应用。因为这里没有限制股票的买卖次数,因此我们实质上每天都可以买卖股票。如果比上一日价格高,就卖出(收益为price[i]-price[i-1],如果高,就不操作(收益为0)。
  • 《剑指Offer》上讲关于程序鲁棒性的讨论很重要。虽然这个题为了合题意不会出一些诸如null或者只有一个的输入,但是有养成习惯。总有些人喜欢在测试用例里搞事情,这样其实尽量符合题意的适量加异常处理条件就好。
class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length == 0 || prices.length == 1) return 0;
        int ans = 0;
        for (int i = 1; i < prices.length ; i++){
            ans += Math.max(0, prices[i] - prices[i-1]);
        }
        return ans;
    }
}
  • 时间复杂性:只需要用for遍历一次,时间复杂度为 O ( n ) \mathcal{O}(n) O(n)
  • 空间复杂性:没有用数据结构存储到额外的内存空间,每次做Math.max判断,空间复杂度 O ( 1 ) \mathcal{O}(1) O(1)

55. 跳跃游戏 Jump Game

  • 难度:中等
  • 直接用贪心就可以了。max保存的是在目前的遍历的数组中能达到的最右节点。
  • 所以如果是中间的点,只需要比较max(之前能到达的最右点)和i + nums[i](现在遍历到的点如果加上这一点的值能到达的点),取其更远者即可。
  • 如果能达到最后一个(不需要相等,只要max >= n - 1就可以了),就直接返回true
  • 如果i > max,说明之前数组能达到的最大点都不能到达现在遍历的点。遍历到最后一个的时候如果仍没有出现max >= n-1,那就是永远到不了了,跳出for返回false
public class Solution {
    public boolean canJump(int[] nums) {
        int len = nums.length;
        int max = 0;
        for (int i = 0; i < len; ++i) {
            if (i <= max) {
                max = Math.max(max, i + nums[i]);
                if (max >= n - 1) {//可以跳到最后一个
                    return true;
                }
            }
        }
        return false;
    }
}
  • 时间复杂度:用for遍历一遍,则时间复杂度 O ( n ) \mathcal{O}(n) O(n)
  • 空间复杂度:不需要额外的空间开销 O ( 1 ) \mathcal{O}(1) O(1)

134. 加油站 Gas Station

  • 难度:中等
  • 有两个条件:
  • 第一个,也就是代码中的rest,是绕一圈后的剩余油量。这个与起始点无关,总是要绕一周的。如果这个值都有rest < 0,那么怎么选起始点都是不能围绕一周的,返回false
  • 第二个,也就是代码中的run,是指从现在的start点开始到现在这个结点当前剩余的油量。如果目前的run < 0,那么车将无法到达下一个结点。则把下一个加油站作为start
  • 至于原理这里写不下了,大家可以看官方题解。结论是:如果有rest >= 0则一定有一个结点 N s t a r t N_{start} Nstart出发能绕一周。
class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) 
        int rest = 0;
        int run = 0;
        int start = 0;
        for (int i = 0 ; i < gas.length ; i++){
            run += (gas[i] - cost[i]);
            rest += (gas[i] - cost[i]);
            if (run < 0){//如果中途一个点没油了,就把start移到下一个。
                start = i + 1;
                run = 0;
            }
        }
        return rest < 0 ? -1 : start;
    }
}
  • 时间复杂度:同样的,一次for循环,时间复杂度 O ( n ) \mathcal{O}(n) O(n)
  • 空间复杂度:只使用了常数空间存储,空间复杂度 O ( 1 ) \mathcal{O}(1) O(1)

  • 今日总结:

  • 1.贪心算法的条件比较苛刻,证明是全局最优也不是容易想到的方法。所以一般不好想到贪心算法上,用其他如动态规划之类的做也没有任何问题。优化的时候还是尽量多想一些。

  • 2.贪心一般会和其他结合起来。单纯的贪心(如122)应该比较少。不少题还是有一些脑筋急转弯的成分在其中的。

  • 3.做到目前还不觉得贪心有什么固定的套路,比如看到一个最长子串就马上想到动态规划等,还要再学习呀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值