当前位置:网站首页>【动态规划--买卖股票的最佳时期系列3】
【动态规划--买卖股票的最佳时期系列3】
2022-07-28 05:26:00 【步步高升b】
力扣链接
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
实例 1:
输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票
示例 3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这个情况下, 没有交易完成, 所以最大利润为0。
示例 4:
输入:prices = [1]
输出:0
分析
1.确定dp数组以及下标的含义
一天一共就有五个状态:
0.没有操作
1.第一次买入
2.第一次卖出
3.第二次买入
4.第二次卖出
dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。
2.确定递推公式
达到dp[i][1]状态,有两个具体操作:
操作一:第i天买入股票了,那么
dp[i][1] = dp[i-1][0] - prices[i]
操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]
那么dp[i][1]究竟选 dp[i-1][0] - prices[i],还是dp[i - 1][1]呢?
一定是选最大的,所以 dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1]);
同理dp[i][2]也有两个操作:
操作一:第i天卖出股票了,那么
dp[i][2] = dp[i - 1][1] + prices[i]
操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]
所以 dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])
同理可推出剩下状态部分:
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
3.dp数组如何初始化
第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;
第0天做第一次买入的操作,dp[0][1] = -prices[0];
第0天做第一次卖出的操作,这个初始值应该是多少呢?
首先卖出的操作一定是收获利润,整个股票买卖最差情况也就是没有盈利即全程无操作现金为0,
从递推公式中可以看出每次是取最大值,那么既然是收获利润如果比0还小了就没有必要收获这个利润了。
所以dp[0][2] = 0;
第0天第二次买入操作,初始值应该是多少呢?应该不少同学疑惑,第一次还没买入呢,怎么初始化第二次买入呢?
第二次买入依赖于第一次卖出的状态,其实相当于第0天第一次买入了,第一次卖出了,然后在买入一次(第二次买入),那么现在手头上没有现金,只要买入,现金就做相应的减少。
所以第二次买入操作,初始化为:dp[0][3] = -prices[0];
同理第二次卖出初始化dp[0][4] = 0;
4.确定遍历顺序
从递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值。
5.举例推导dp数组
以输入[1,2,3,4,5]为例:
代码如下:
#include<iostream>
#include<vector>
using namespace std;
class Solution{
public:
int Maxprofit(vector<int> &prices) {
vector<vector<int>> dp(prices.size(),vector<int>(5));
dp[0][0] = 0;
dp[0][1] = -prices[0];
dp[0][2] = 0;
dp[0][3] = -prices[0];
dp[0][4] = 0;
for (int i = 1; i < prices.size(); i++) {
dp[i][0] = dp[i-1][0];
dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i]);
dp[i][2] = max(dp[i-1][2],dp[i-1][1] + prices[i]);
dp[i][3] = max(dp[i-1][3],dp[i-1][2] - prices[i]);
dp[i][4] = max(dp[i-1][4],dp[i-1][3] + prices[i]);
}
return dp[prices.size()-1][4];
}
};
int main() {
vector<int> price = {
3,3,5,0,0,3,1,4};
Solution Q;
cout<<Q.Maxprofit(price);
}
问题2
力扣链接
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1: 输入:k = 2, prices = [2,4,1] 输出:2 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2
天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2。示例 2: 输入:k = 2, prices = [3,2,6,5,0,3] 输出:7 解释:在第 2 天 (股票价格 = 2)
的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后,在第 5 天 (股票价格 =
0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3。
使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]
j的状态表示为:
0 表示不操作
1 第一次买入
2 第一次卖出
3 第二次买入
4 第二次卖出
…
大家应该发现规律了吧 ,除了0以外,偶数就是卖出,奇数就是买入。
达到dp[i][1]状态,有两个具体操作:
操作一:第i天买入股票了,那么dp[i][1] = dp[i - 1][0] - prices[i]
操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1] 选最大的,所以 dp[i][1] =
max(dp[i - 1][0] - prices[i], dp[i - 1][1]);同理dp[i][2]也有两个操作:
操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2] 所以dp[i][2] =
max(dp[i - 1][1] + prices[i], dp[i - 1][2])
代码如下
#include<iostream>
#include<vector>
using namespace std;
class Solution{
public:
int maxProfit(int k, vector<int> &price) {
if (price.size() == 0) return 0;
vector<vector<int>> dp(price.size(),vector<int>(2*k+1));
for (int j = 1; j < 2 * k; j+= 2) {
//dp[i][j]:第i天的状态为j,所剩下的最大现金是dp[i][j]。
dp[0][j] = -price[0];
}
for (int i = 1; i < price.size(); i++) {
for (int j = 0; j < 2 * k - 1; j+=2) {
dp[i][j+1] = max(dp[i-1][j+1],dp[i-1][j] - price[i]);
dp[i][j+2] = max(dp[i-1][j+2],dp[i-1][j+1] + price[i]);
}
}
return dp[price.size()-1][2*k];
}
};
int main() {
Solution Q;
int k;
int n;
vector<int> prices(n);
cin>>n;
for (int i = 0; i < n; i++) {
cin>>prices[i];
}
cin>>k;
cout<<Q.maxProfit(k,prices);
}
边栏推荐
猜你喜欢

VI and VIM commands
![[untitled]](/img/de/746832bfb3bb79b090215b135b8917.jpg)
[untitled]
![OpenGL development environment configuration [vs2017] + frequently asked questions](/img/29/cefa8601310caf56ae9605cbf7fbbf.png)
OpenGL development environment configuration [vs2017] + frequently asked questions

【详解如何一步步实现三子棋】

2021-11-10

Pytorch learning notes 3 - datasets & dataloaders & transforms

C语言的编译和预处理

C语言memcpy库函数与memmove的作用

Solve the problem that the memory occupation is higher than that of the application process

自定义组件--纯数据字段&组件的生命周期
随机推荐
qt批量操作控件,并设置信号槽
1、 Ffmpeg record audio as PCM file
scrapy 命令
Listener
What's a good gift for your girlfriend on Chinese Valentine's day? Boys who can't give gifts, look!
JSP实现文件上传功能的同时还要向后台传递参数
Find the network address and broadcast address of the host according to the IP address and subnet mask
Five categories of IP addresses
Icc2 (IV) routing and postroute optimization
【实现简易版扫雷小游戏】
刷题记录----反转链表(反转整个链表)
Perl introductory learning (XI) file operation
Servlet
【C语言】字符串库函数介绍及模拟
2022年七夕礼物推荐!好看便宜又实用的礼物推荐
相对路径和绝对路径
2022-05-15 基于jwt令牌token
做气传导耳机最好的是哪家、最好的气传导耳机盘点
set_ multicycle_ path
error: redefinition of ‘xxx‘