当前位置:首页 » 《随便一记》 » 正文

代码随想录算法训练营day51|| 309.最佳买卖股票时机含冷冻期 ||714.买卖股票的最佳时机含手续费 ||300.最长递增子序列

10 人参与  2022年11月14日 10:33  分类 : 《随便一记》  评论

点击全文阅读


309.最佳买卖股票时机含冷冻期

思路:

这题相对于买卖股票最佳时机2多了一个冷冻期的条件,买卖股票最佳时机2每天只用考虑两个状态,买入股票状态和卖出股票的状态。这题多了一个条件就需要多出一些状态求解,这题就需要总的每天可能分为四个状态:1.持有股票 2.第i天之前不持有股票(前一天是冷冻期,或者前一天超过冷冻期并且不持有股票) 3.第i天卖出股票 4.当天为冷冻期

为什么不把状态二和状态三结合在一起呢?因为状态四是冷冻期,状态四之前的一天一定是状态三,股票卖出的当天。但是如果将状态二和三结合在一起了,那么就无法保证状态四的前一天是刚好卖出股票的那一天,冷冻期的剩余金额一定是卖出股票当天的剩余金额。

动规五部曲:

1.dp[i][j]及其下标的定义:第i天状态j下的最大剩余金额.

2.递推公式:dp[i][0]=max(dp[i-1][0],max(dp[i-1][1],dp[i-1][3])-prices[i])

dp[i][1]=max(dp[i-1][1],dp[i-1][3]);

dp[i][2]=dp[i-1][1]+prices[i];        dp[i-1][3]=dp[i-1][2];

3.初始化:dp[0][0]=-prices[0],其他初始化为0;

4.遍历顺序:从小到大

5.验证dp

class Solution {public:    int maxProfit(vector<int>& prices) {        int n = prices.size();        if (n == 0) return 0;        vector<vector<int>> dp(n, vector<int>(4, 0));        dp[0][0] -= prices[0]; // 持股票        for (int i = 1; i < n; i++) {            dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i]);            dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);            dp[i][2] = dp[i - 1][0] + prices[i];            dp[i][3] = dp[i - 1][2];        }        return max(dp[n - 1][3],max(dp[n - 1][1], dp[n - 1][2]));    }};

714.买卖股票的最佳时机含手续费

思路:

这题相较于买卖股票的最佳时机就主要差别在于递推公式上,当你在第i天持有时没什么差别,要么在前一天就持有了,要么当天买入。但是在卖出的时候就会有所差距,如果是当天卖出,还要减去手续费。dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]-fee);

class Solution {public:    int maxProfit(vector<int>& prices, int fee) {        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++) {            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);        }        return max(dp[n - 1][0], dp[n - 1][1]);    }};

300.最长递增子序列

思路:

最长上升子序列是动规的经典题目,这里dp[i]可以根据dp[j](j<i)推导出来,动规五部曲分析一波:

1.dp[i]的定义:

dp[i]表示i之前包括i的以nums[i]结尾最长上升子序列的长度。注意:这个是以nums[i]结尾的最长子序列的长度,而不是遍历到数组i时的最长子序列长度,所以当遍历完nums之后,最长子序列长度不一定是dp[nums.size()-1].可能是前面的元素。

2.状态转移方程。

位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列+1的最大值(前提当然是位置i的值大于j位置的值).所以:if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);

3.初始化

每一个i,对应的dp[i]起始大小最少为1.

4.确定遍历顺序:

从前到后遍历

class Solution {public:    int lengthOfLIS(vector<int>& nums) {        if (nums.size() <= 1) return nums.size();        vector<int> dp(nums.size(), 1);        int result = 0;        for (int i = 1; i < nums.size(); i++) {            for (int j = 0; j < i; j++) {                if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);            }            if (dp[i] > result) result = dp[i]; // 取长的子序列        }        return result;    }};


点击全文阅读


本文链接:http://zhangshiyu.com/post/48298.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1