2.3学习总结

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()];
    }
};
  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值