代码随想录算法训练营第三十二天| 122 买卖股票的最佳时机II 55 跳跃游戏 45 跳跃游戏II

代码随想录算法训练营第三十二天| 122 买卖股票的最佳时机II 55 跳跃游戏 45 跳跃游戏II

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

题目链接: 122.买卖股票的最佳时机II

思路:只有一支股票,只有买股票和卖股票的操作。

可以将利润分解成以每天为单位的维度,而不是从某一天再到另一天去考虑!

然后利用贪心算法只收集正的利润,通过收集每天的正利润来实现全局最优。

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

动态规划(虽然不懂,但是尝试理解理解)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        //dp[i][1]第i天持有的最多现金
        //dp[i][0]第i天持有股票后的最多现金
        int n = prices.size();
        vector<vector<int> > dp(n, vector<int>(2, 0));
        dp[0][0] -= prices[0];  //持股票
        for(int i = 1; i < n; i++) {
            //第i天持股票所剩最多现金 = max(第i-1天持股票所剩现金-买第i天的股票)
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
            //第i天持股票持有最多现金 = max(第i - 1天持有的最多现金,第i - 1天持有股票的最多现金+第i天卖出股票)
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
        }
        return max(dp[n - 1][0], dp[n - 1][1]);
    }
};

股票问题实质上是一个系列,属于动态规划的范畴。

LeetCode 55 跳跃游戏

题目链接: 55.跳跃游戏

思路:刚接触到本题时会想到究竟跳几步,思考会比较多,但是我们应该思考可跳的覆盖范围,不一定非要明确一次究竟调几步,每次取最大步数,明确覆盖范围即可。那么此问题转变为跳跃覆盖范围究竟能否覆盖到终点。

局部最优:每次取最大值

整体最优:最后得到整体覆盖范围,看能否到达终点

i每次移动只能在cover的范围内移动,每移动一个元素,cover得到该元素数量数值,然后i继续移动下去。

cover每次只取max,若cover能够覆盖终点下标,return true即可。

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

LeetCode 45 跳跃游戏II

题目链接: 45.跳跃游戏II

思路:此题比上题要复杂很多,虽然按照贪心的思想,局部最优就是尽可能先多走,,从而实现整体最优。然而从代码里无法体现能走多远就走多远。

所以此题需要统计两个覆盖范:当前这一步的最大覆盖范围和下一步最大覆盖范围

若当前移动下标到达了当前这一步的最大覆盖距离还没到终点,就必须再走一步来增加覆盖范围,直到覆盖范围覆盖终点。

class Solution{
public:
    int jump(vector<int>& nums) {
        if(nums.size() == 1) return 0;
        int curDistance = 0;  //当前覆盖最远距离下标
        int ans = 0;
        int nextDistance = 0;  //下一步覆盖最远距离下标
        for(int i = 0; i < nums.size(); i++) {
            nextDistance = max(nums[i] + i, nextDistance);
            if(i == curDistance) {
                if(curDistance < nums.size() - 1) {
                    ans++;
                    curDistance = nextDistance;
                    if(nextDistance >= nums.size() - 1) break;
                } else break;
            }
        }
        return ans;
    }
};
// 版本二
class Solution {
public:
    int jump(vector<int>& nums) {
        int curDistance = 0;    // 当前覆盖的最远距离下标
        int ans = 0;            // 记录走的最大步数
        int nextDistance = 0;   // 下一步覆盖的最远距离下标
        for (int i = 0; i < nums.size() - 1; i++) { // 注意这里是小于nums.size() - 1,这是关键所在
            nextDistance = max(nums[i] + i, nextDistance); // 更新下一步覆盖的最远距离下标
            if (i == curDistance) {                 // 遇到当前覆盖的最远距离下标
                curDistance = nextDistance;         // 更新当前覆盖的最远距离下标
                ans++;
            }
        }
        return ans;
    }
};

总结:看起来很简单,但是想不到

你可能感兴趣的:(代码随想录每日打卡,算法,leetcode,数据结构)