LeetCode刷题笔记【24】:贪心算法专题-2(买卖股票的最佳时机II、跳跃游戏、跳跃游戏II)

前置知识

参考前文

参考文章:
LeetCode刷题笔记【23】:贪心算法专题-1(分发饼干、摆动序列、最大子序和)

122.买卖股票的最佳时机II

题目描述

截图

LeetCode链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/

贪心-直观写法

思路: 贪心算法
假设这个股票交易员有预知明天股票价格的能力;
当明天的价格大于今天的时候, 就买入/持有;
当明天价格下跌时, 就在今天抛售/不购买;
最后一天的时候如果手里还有, 就售出;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int ans=0;
        if(prices.size()<=1)
            return ans;
        bool holding=false;
        for(int i=0; i<prices.size(); ++i){
            if(i==prices.size()-1){//最后一天, 手里还有股票
                if(holding)
                    ans += prices.back();//卖出
                break;//不管咋样都要break了
            }
            if(prices[i+1] > prices[i] && !holding){//明天升值, 并且手里没有股票
                ans -= prices[i];//买入
                holding = true;
            }else if(prices[i+1] <= prices[i] && holding){//明天贬值, 并且手里有股票
                ans += prices[i];//卖出
                holding = false;
            }
        }
        return ans;
    }
};

贪心-优化代码更简洁

以上过程可以抽象为以下操作:
遍历整个prices序列, 只记录其中升序的部分的差值

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int ans=0;
        for(int i=0; i<prices.size()-1; ++i){
            ans += max(0, prices[i+1]-prices[i]);
        }
        return ans;
    }
};

55. 跳跃游戏

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/jump-game/description/

贪心-借助ability数组

创建并维护一个vector<bool> ability数组
从头开始遍历nums, 最开始ability[0]=true
然后如果ability[i]==true, 那么将ability[i]~ability[i+nums[i]]都为true
过程中发现某个ability[i]==false, 那么就为false

class Solution {
public:
    bool canJump(vector<int>& nums) {
        vector<bool> ability(nums.size(), false);
        ability[0] = true;
        for(int i=0; i<nums.size(); ++i){
            if(ability[i]){
                for(int j=i+1; j<=i+nums[i]; ++j){
                    if(j>=nums.size())
                        return true;;
                    ability[j] = true;
                }
            }else{
                return false;
            }
        }
        return true;
    }
};

贪心-只用int far记录最远距离

用不到一个数组, 用一个far表示最远能到达的点就可以了

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int far=0;
        for(int i=0; i<nums.size(); ++i){
            if(far >= nums.size()-1)
                return true;
            if(far>=i){
                far = max(far, i+nums[i]);
            }else{
                return false;
            }
        }
        return true;
    }
};

核心思想是: 不要纠结这次跳几步, 而是关注最远能跳到哪里

45.跳跃游戏II

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/jump-game-ii/description/

回溯算法

思路: 回溯算法
每一层的回溯过程就是在遍历自己从这一步跳出去, 可以跳的距离的所有可能性
终止条件是index>nums.size()-1, 或者nums[index]==0

class Solution {
private:
    int ans = INT_MAX;
    int cur = 0;
    void backtrack(vector<int>& nums, int index){
        if(index>=nums.size()-1){
            ans = min(ans, cur);
            return;
        }
        if(nums[index]==0)
            return;
        for(int i=nums[index]; i>0; --i){
            cur++;
            backtrack(nums, index+i);
            cur--;
        }
        return;
    }
public:
    int jump(vector<int>& nums) {
        backtrack(nums, 0);
        return ans;
    }
};

贪心算法

回溯法肯定是可以解决问题的, 但是奈何回溯的本质是遍历, 时间复杂度过高, 超出时间限制
所以老老实实用贪心吧:
和<55. 跳跃游戏>的核心思路是一样的, 都是尽量往远了跳, 但是这个又不能乱跳, 因为涉及到要不要ans++的问题

所以贪心的思路是: 先看一下这一步能跳多远, 如果可以满足要求, 就结束, 如果不能, 那么就再跳一步
具体的实现是: 用nextDistence记录在当前范围内, 再跳一步可以达到的最远结果;
当遍历达到了curDistence处时, 如果还没有到最后一位, 那么就转nextDistence

class Solution {
public:
    int jump(vector<int>& nums) {
        int ans = 0;
        if(nums.size()<=1)
            return ans;
        int nextDistence=0, curDistence=0;
        for(int i=0; i<nums.size(); ++i){
            nextDistence = max(nextDistence, i+nums[i]);
            if(i==curDistence){
                ans++;
                curDistence = nextDistence;
                if(nextDistence>=nums.size()-1)
                    break;
            }
        }
        return ans;
    }
};

总结

贪心算法大概率就是没法把握, 甚至看起来是"千题千解", 尽量熟悉吧只能说, 如果之后遇到类似的题目了, 可以想起来最好.
实在不行的话或许只能用回溯和动态规划尝试了.

刚才的第二题, 说到不要纠结这次跳几步, 而是关注最远能跳到哪里, 或许也是某种人生哲学呢哈哈哈.
本质上我们或多或少的都在用贪心算法规划自己的人生.
(用贪心还算好了, 至少是当下和未来一部分时间内的最优, 还有不知道多少人是在后视镜开车呢)

本文参考:
买卖股票的最佳时机II
跳跃游戏
跳跃游戏II

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值