2.3
1..买卖股票的最佳时机
2..买卖股票的最佳时机II
3.最长递增子序列
4.最长连续递增的子序列
5.最长重复子数组
6.最长公共子序列
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/
定义:dp[i][0] 表示第i天持有股票所得现⾦。dp[i][1] 表示第i天不持有股票所得现⾦。
所以dp[i][0]的转移有两种方向,
第一点是没有卖股票所以保持上一次的状态为dp[i-1][0]
第二点是买了股票,所以为买掉股票的钱
所以得到了转移方程:dp[i][0] = max(dp[i - 1][0], -prices[i]);
dp[i][1]也同样有两种方向
第一点,没有买进股票保持上一次的状态dp[i-1][1]
第二点,卖了股票,所以就是当前卖股票的钱
所以转移方程为:dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
class Solution {
public:int maxProfit(vector<int>& prices) {int len=prices.size();vector<vector<int> >dp(len,vector<int>(2));dp[0][0]-=prices[0],dp[0][1]=0;for (int i=1;i<len;++i){dp[i][0]=max(dp[i-1][0],-prices[i]);dp[i][1]=max(dp[i-1][1],prices[i]+dp[i-1][0]);}return dp[len-1][1];}
};
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/
同样有两个状态
dp[i][0] 表示第i天持有股票所得现⾦
dp[i][1] 表示第i天不持有股票所得最多现⾦
但唯一不同的是,卖掉股票之后,还可以继续买进
所以dp[i][0]的转移有两种方向,
第一点是没有卖股票所以保持上一次的状态为dp[i-1][0]
第二点是第i天卖了股票股票,第i-1天所有的钱减去买掉股票的钱
所以得到了转移方程:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
dp[i][1]也同样有两种方向
第一点,没有买进股票保持上一次的状态dp[i-1][1]
第二点,卖了股票,所以就是当前卖股票的钱
所以转移方程为:dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
class Solution {
public:int maxProfit(vector<int>& prices) {int len = prices.size();vector<vector<int> >dp(len,vector<int>(2,0));dp[0][0]-=prices[0],dp[0][1]=0;//0表示持有股票,1表示不持有股票,持有股票的状态是由不持有股票买股票转移//不持有股票的状态是由持有股票后卖掉股票得到for (int i=1;i<len;++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]);//卖股票} return dp[len-1][1];}
};
https://leetcode.cn/problems/longest-increasing-subsequence/description/
由于是找到最长的递增的子序列,因此没有严格要求是递增的,那么建立dp[i]表示i之前最长的递增子序列,通过双循环i,j,j可以从头遍历到i-1,如果符合nums[i]>nums[j],那么dp就可以+1,因此得到转移方程:if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
由于是找子序列,所以最短的子序列的长度一定是1,所以所有的初始化应该是1.
class Solution {
public:int lengthOfLIS(vector<int>& nums) {vector<int>dp(nums.size()+1,1);int res=1;for (int i=0;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 (res<dp[i])res=dp[i];}else dp[i]=dp[i];}}return res;}
};
https://leetcode.cn/problems/longest-continuous-increasing-subsequence/description/
这题和上一题的区别就在是否连续,这道题需要连续的递增子序列,所以dp数组只需要和前面一个数比较,如果大于前面一个数,那么当前状态就需要+1,否则就继续进行遍历。
class Solution {
public:int findLengthOfLCIS(vector<int>& nums) {vector<int>dp(nums.size()+1,1);int maxn=1;for (int i=1;i<nums.size();++i){if (nums[i]>nums[i-1]){dp[i]=dp[i-1]+1;if (dp[i]>maxn) maxn=dp[i];}}return maxn;}
};
https://leetcode.cn/problems/maximum-length-of-repeated-subarray/description/
定义dp[i][j]数组为下标i-1,和j-1的子串的最长重复子串的长度
转移方程:dp[i][j]只能当i-1和j-1上的字符相等的时候才能转换过来
class Solution {
public:int findLength(vector<int>& nums1, vector<int>& nums2) {int dp[1005][1005];memset(dp,0,sizeof(dp));int maxn=0;for (int i=1;i<=nums1.size();++i){for (int j=1;j<=nums2.size();++j){if (nums1[i-1]==nums2[j-1]){dp[i][j]=dp[i-1][j-1]+1;if (maxn<dp[i][j]) maxn=dp[i][j];}}}return maxn;}
};
https://leetcode.cn/problems/longest-common-subsequence/description/
这题和上一题的区别就在于这个不需要连续,所以dp[i][j]这个状态就不只是可以从dp[i-1][j-1]这个状态推出了,可以继承前面的最大子序列,如果相等就在前者就基础上加一,反之就继承前面的最大子序列
所以转移方程分为两种情况,第一种相等:
dp[i][j] = dp[i - 1][j - 1] + 1;
如果不相等:
那就看看text1[0, i - 2]与text2[0, j - 1]的最⻓公共⼦序列 和 text1[0, i - 1]与text2[0, j - 2]的最⻓公共⼦序列,取最⼤的。
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
class Solution {
public:int longestCommonSubsequence(string text1, string text2) {int dp[1005][1005];memset(dp,0,sizeof(dp));int maxn=0;for (int i=1;i<=text1.size();++i){for (int j=1;j<=text2.size();++j){if (text1[i-1]==text2[j-1]){dp[i][j]=dp[i-1][j-1]+1;}else {dp[i][j]=max(dp[i][j-1],dp[i-1][j]);}}}return dp[text1.size()][text2.size()];}
};