代码随想录训练营第54天|休息日 小结

打家劫舍系列

198. 打家劫舍对于当前的房间,无非就两种选择:偷与不偷。如果当前房间偷,那么前一个房间就不偷,即dp[i] = dp[i-2] + nums[i];如果当前房间不偷,那么dp[i] = dp[i-1],因此递推公式为:

dp[i] = max(dp[i-1],dp[i-2] + nums[i])

213. 打家劫舍 II这个题上上一题的基础之上加入了成环的约束条件,因为第一间房间和最后一间房间只能偷一间,因此可以分为两种情况,一种是不偷第一间房,另一种是不偷最后一间房间,这样两种情况都不同考虑成环的问题且都转化为了上一个题,因此可以用上一个题的思路求解,最终的结果是两种情况中的最大值。
337. 打家劫舍 III这题将数组变成了树,因此涉及到树的遍历方式,这里使用后序遍历。

买卖股票系列

121. 买卖股票的最佳时机这个题只能买卖一次,因此只能在最低点买入,在最低点后的最高点卖出,定义dp数组dp[i][0]和dp[i][1],递推公式如下:

dp[i][0] = min(prices[i],dp[i-1][0]);				//买入时花费的最少现金
dp[i][1] = max(dp[i-1][1],prices[i]-dp[i][0]);		//卖出时所得的最大利润

122. 买卖股票的最佳时机 II这个题可以多次买卖,因此在买入的时候还要考虑在此之前花费的现金,递推公式如下,注意和上一个题递推公式的差别:

dp[i][0] = min(prices[i] - dp[i-1][1],dp[i-1][0]);  	//买入时花费的最少现金
dp[i][1] = max(dp[i-1][1],prices[i]-dp[i][0]);			//卖出时所得的最大利润

123. 买卖股票的最佳时机 III188. 买卖股票的最佳时机 IV求解思路是一样的,在只允许买卖两次的时候就可以发现规律,无非就是要列出每天的所有可能状态。买卖k次时的代码实现如下:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        vector<vector<int>> dp(prices.size(),vector<int>(2 * k + 1));
        //初始化dp数组
        for(int j = 1 ; j < 2 * k + 1; j += 2) //注意这里是j += 2
            dp[0][j] = -prices[0];  //买入状态初始化,卖出状态已经初始化为0
        //遍历
        for(int i = 1; i < dp.size(); i++){
            //dp[i][0] = dp[i-1][0];  //始终保持不变,可以不用
            for(int j = 1; j < 2 * k + 1; j += 2){      //注意这里是j += 2
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-1] - prices[i]);    //买入
                dp[i][j+1] = max(dp[i-1][j+1],dp[i-1][j] + prices[i]);  //卖出
            }
        }
        return dp.back()[2*k];
    }
};

当j为奇数的时候表示买入,当j为偶数的时候表示卖出。

309. 最佳买卖股票时机含冷冻期这个题在前四个题的基础上加入了冷冻期,在求解过程中要理清楚状态转移过程,在这个题中定义下面的四个状态:

  • 状态一( j = 0):买入状态,不一定当天买入,也可能是之前就已经买入了
  • 状态二( j = 1):卖出状态且已经度过了冷冻期
  • 状态三( j = 2):今天卖出,还未度过冷冻期
  • 状态四(j = 3):冷冻期

根据状态转移关系即可得到递推公式:

dp[i][0] = max(dp[i-1][0],max(dp[i-1][1] - prices[i],dp[i-1][3] - 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];

714. 买卖股票的最佳时机含手续费这个题在122. 买卖股票的最佳时机 II的基础上加入了手续费,因此在卖出的时候考虑手续费即可。

子序列问题

子序列问题一定要清楚dp[i]的定义,以及子序列连续和不连续的求解区别。

300. 最长递增子序列中dp[i]定义为以nums[i]作为子序列的最后一个元素的最长子序列为dp[i],因此最终的结果是dp数组中的最大值。核心代码如下:

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];
}

674. 最长连续递增序列这个题要求子序列是连续的,因此dp[i]只能和dp[i-1]有关系,递推公式为:

if(nums[i] > nums[i-1]) dp[i] = dp[i-1] + 1;

如果不满足nums[i] > nums[i-1],则dp[i]保持1不变(初始化的时候已经赋值为1),因此一个元素就可以构成一个子序列。

718. 最长重复子数组这个题涉及到两个数组,因此要使用二维dp数组,且dp[i][j]只能由dp[i-1][j-]1得到。如下图所示:
在这里插入图片描述
1143. 最长公共子序列718. 最长重复子数组的区别在于这题的子序列不连续,差异主要体现在初始化和递推公式上,本题的递推公式为:

if(text1[i] == text2[j])
    dp[i][j] = dp[i-1][j-1] + 1;
else
    dp[i][j] = max(dp[i-1][j],dp[i][j-1]);

dp[i][j]不仅和dp[i-1][j-1]有关,还和dp[i-1][j]、dp[i][j-1]有关。

1035. 不相交的线1143. 最长公共子序列完全一样,关键是要想明白怎么个一样法!

53. 最大子序和这个题其实就是求的是局部的最大和,dp数组中保存的是局部最大和,最终的结果是dp数组中的最大值,递推公式如下:

dp[i] = max(dp[i-1] + nums[i],nums[i]);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆昔z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值