代码随想录算法训练营Day48 | 121.买卖股票的最佳时机、122.买卖股票的最佳时机 II

文章讲述了如何使用动态规划解决买卖股票的问题,先介绍了半贪心半动态规划的实现,然后对比了贪心算法版本,并详细阐述了两种方法中DP数组的定义、初始化和递推公式。后续部分探讨了在考虑多次买入卖出的复杂情况下的改进策略。
摘要由CSDN通过智能技术生成

121.买卖股票的最佳时机

(想写动态规划写着写着变成贪心了)

半贪心半动规:

int maxProfit(vector<int>& prices) {
	vector<int> dp(prices.size(), 0);
	int minVal = prices[0];

	for (int i = 1; i < prices.size(); ++i) {
		// 更新最低买入价格
		if (prices[i] < minVal) {
			minVal = prices[i];
			dp[i] = dp[i - 1];
		}
		// 尝试卖出
		else
			dp[i] = std::max(dp[i - 1], prices[i] - minVal);
	}
	return dp[prices.size() - 1];
}

// 利用滚动数组的思路进行优化:
int maxProfit(vector<int>& prices) {
	int dp = 0;
	int minVal = prices[0];

	for (int i = 1; i < prices.size(); ++i) {
		if (prices[i] < minVal)
			minVal = prices[i];
		else
			dp = std::max(dp, prices[i] - minVal);
	}
	return dp;
}

动规写法,重点在于DP数组的定义

1、DP数组定义

        dp[i][j]为当前利润,买入则减,卖出则加
        · dp[i][0]表示如果当前持有股票,所能获得的最大利润(持有的股票可以是当天购入的也可以是之前购入的
        · dp[i][1]表示如果当前不持有股票,所能获得的最大利润(可以是还没有购入过也可以是购入后卖出了

2、DP数组初始化:dp[0]初始化为-prices[0],起步资金为0,所以相当于第一次买入,即 dp[0] = 0 - prices[0]

3、递推公式

        · 对于dp[i][0]:判断当日买入和前几日买入,哪个更便宜,即:

                        dp[i][0] = max(dp[i - 1][0], -prices[i])

        · 对于dp[i][1]:判断当日卖出和前几日卖出,哪个收益更高,即:

                        dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i])

4、遍历顺序:按时间顺序从前向后遍历

int maxProfit(vector<int>& prices) {
	dp[0][0] = -prices[0];		// 购入第一支股票
	dp[0][1] = 0;

	for (int i = 1; i < prices.size(); ++i) {
		dp[i][0] = std::max(dp[i - 1][0], -prices[i]);
		// 卖出:前一天的最大卖出利润 与 前一天持有+今日卖出所得 取较大值
		dp[i][1] = std::max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
	}
	return dp[prices.size() - 1][1];
}

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

之前用贪心写过这题

int maxProfit(vector<int>& prices) {
	vector<int> dp(prices.size(), 0);
	int curVal = prices[0];

	for (int i = 1; i < prices.size(); ++i) {
		if (prices[i] < curVal)
			dp[i] = dp[i - 1];
		else
			dp[i] = dp[i - 1] + prices[i] - curVal;
		curVal = prices[i];
	}
	return dp[prices.size() - 1];
}

// 用滚动数组思路进行写法优化(完全变成了之前的贪心写法)
int maxProfit(vector<int>& prices) {
	int dp = 0;
	int curVal = prices[0];

	for (int i = 1; i < prices.size(); ++i) {
		if (prices[i] > curVal)
			dp += prices[i] - curVal;
		curVal = prices[i];
	}
	return dp;
}

延续 买卖股票I 思路的动规写法:

与 I 相比,差异在于可以反复买入卖出,即每次买入时的启动资金不是0,而是之前卖出所得的资金总量

差异仅在于dp[i][0]的递推公式:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i])

int maxProfit(vector<int>& prices) {
	vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
	dp[0][0] = -prices[0];

	for (int i = 1; i < prices.size(); ++i) {
		// 是否选择今天买入
		dp[i][0] = std::max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
		// 是否选择今天卖出
		dp[i][1] = std::max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
	}
	return dp[prices.size() - 1][1];
}
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值