动态规划股票交易
Posted 桃陉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划股票交易相关的知识,希望对你有一定的参考价值。
文章目录
1.买卖股票的最佳时机
1.1 题目
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
∙
\\bullet
∙ 1 <= prices.length <= 105
∙
\\bullet
∙ 0 <= prices[i] <= 104
来源:力扣(LeetCode)
链接:题目来源
1.2 分析
∙ \\bullet ∙ 我们只需要进行一次交易,即买入一次卖出一次。当数组中只有一个数字时返回0,当数组中数字倒序时无法买卖返回0。
∙
\\bullet
∙ 在编写时我们需要一个变量ans来指向第一个数字(ans表示买入的时刻,我们要保证它尽量的小),然后从下标为1的地方遍历数组,当遍历元素小于ans时,我们就更新ans。每次都将最终返回结果res与当前元素减去ans的值进行比较,取其中较大的值。
r
e
s
=
m
a
x
(
r
e
s
,
p
r
i
c
e
s
[
i
]
−
a
n
s
)
;
res = max(res,prices[i]-ans);
res=max(res,prices[i]−ans);
1.3 代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
int ans=prices[0],res=0;
for(int i=1;i<n;i++)
{
if(prices[i]<ans) ans=prices[i];
res=max(res,prices[i]-ans);
}
return res;
}
};
2.买卖股票的最佳时机 II
2.1 题目
给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 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。
提示:
∙
\\bullet
∙ 1 <= prices.length <= 3 * 104
∙
\\bullet
∙ 0 <= prices[i] <= 104
来源:力扣(LeetCode)
链接:题目来源
2.2 分析
∙ \\bullet ∙ 我们注意到与第一问不同,这次可以多次的买入与卖出,然后找到最大的利润。
∙ \\bullet ∙ 在这里我们需要设置两个状态,dp[i][0] 表示当前不持有股票,dp[i][1] 表示当前持有股票。那么最后返回dp[n-1][0]。
∙
\\bullet
∙ 对于dp[i][0] 来说,可能昨天也不持有(dp[i-1][0])或者昨天持有今天卖出(dp[i-1][1]+prices[i]),取两者的较大值。
d
p
[
i
−
1
]
[
0
]
=
m
a
x
(
d
p
[
i
−
1
]
[
0
]
,
d
p
[
i
−
1
]
[
1
]
+
p
r
i
c
e
s
[
i
]
)
;
dp[i-1][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
dp[i−1][0]=max(dp[i−1][0],dp[i−1][1]+prices[i]);
∙
\\bullet
∙ 对于dp[i][1] 来说,可能昨天也持有(dp[i-1][1])或者昨天不持有今天买入(dp[i-1][0]-prices[i]),取两者的较大值。
d
p
[
i
−
1
]
[
1
]
=
m
a
x
(
d
p
[
i
−
1
]
[
1
]
,
d
p
[
i
−
1
]
[
0
]
−
p
r
i
c
e
s
[
i
]
)
;
dp[i-1][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
dp[i−1][1]=max(dp[i−1][1],dp[i−1][0]−prices[i]);
2.3 代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
if(n==1) return 0;
//dp[i][0]表示当前不持有股票,dp[i][1]表示当前持有股票
vector<vector<int>>dp(n,vector<int>(2,0));
dp[0][1]=-prices[0];
for(int i=1;i<n;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[n-1][0];
}
};
3.最佳买卖股票时机含冷冻期
3.1 题目
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
来源:力扣(LeetCode)
链接:题目来源
3.2 分析
∙ \\bullet ∙ 本题相对于上一题增加了一个冷冻期,此时持有股票的状态得分成两部分,一个为今天持有股票且不卖出(dp[i][0]),一个为今天持有且今天卖出(明天为冷冻期) (dp[i][1])。不持有股票的状态不变(dp[i][2])。最后返回 max(dp[n-1][1],dp[n-1][2]);
∙
\\bullet
∙ 对于dp[i][0]来说,可能昨天也持有(dp[i-1][0])或者昨天不持有今天买入(dp[i-1][2]-prices[i]),取二者较大值。
d
p
[
i
]
[
0
]
=
m
a
x
(
d
p
[
i
−
1
]
[
0
]
,
d
p
[
i
−
1
]
[
2
]
−
p
r
i
c
e
s
[
i
]
)
;
dp[i][0]=max(dp[i-1][0],dp[i-1][2]-prices[i]);
dp[i][0]=max(dp[i−1][0],dp[i−1][2]−prices[i]);
∙
\\bullet
∙ 对于dp[i][1]来说,昨天必须持有股票今天才可以卖出。
d
p
[
i
]
[
1
]
=
d
p
[
i
−
1
]
[
0
]
+
p
r
i
c
e
s
[
i
]
;
dp[i][1]=dp[i-1][0]+prices[i];
dp[i][1]=dp[i−1][0]+prices[i];
∙
\\bullet
∙ 对于dp[i][2]来说,可能昨天也不持有股票(dp[i-1][2])或者昨天持有并卖出(dp[i-1][1]),取二者较大值。
d
p
[
i
]
[
2
]
=
m
a
x
(
d
p
[
i
−
1
]
[
2
]
,
d
p
[
i
−
1
]
[
1
]
)
;
dp[i][2]=max(dp[i-1][2],dp[i-1][1]);
dp[i][2]=max(dp[i−1][2],dp[i−1][1]);
3.3 代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
if(n==0) return 0;
/*
dp[i][0] 表示当天持有一支股票
dp[i][1] 表示当天卖出股票(意思就是第i+1天是冷冻期)
dp[i][2] 表示当天不持有股票
*/
vector<vector<int>>dp(n,vector<int>(3,0));
dp[0][0]=-prices[0];
for(int i=1;i<n;i++)
{
dp[i][0]= max(dp[i-1][0],dp[i-1][2]-prices[i]); //可能是昨天就持有或者昨天不持有今天买入
dp[i][1]=dp[i-1][0]+prices[i]; //昨天必须持有今天才可以卖出
dp[i][2]=max(dp[i-1][2],dp[i-1][1]);
}
return max(dp[n-1][1],dp[n-1][2]);
}
};
4.买卖股票的最佳时机含手续费
4.1 题目
给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:
这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
示例 1:
输入:prices = [1, 3, 2, 8, 4, 9], fee = 2
输出:8
解释:能够达到的最大利润:
在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8
示例 2:
输入:prices = [1,3,7,5,10,3], fee = 3
输出:6
提示:
∙
\\bullet
∙ 1 <= prices.length <= 5 * 104
∙
\\bullet
∙ 1 <= prices[i] < 5 * 104
∙
\\bullet
∙ 0 <= fee < 5 * 104
来源:力扣(LeetCode)
链接:题目来源
4.2 分析
∙ \\bullet ∙ 本题其实与第二题十分相似,只是在卖出的基础上添加了小费,所以我们只需要在每次卖出的基础上补充小费即可。
∙ \\bullet ∙ 同样设置两个状态,dp[i][0] 表示当前不持有股票,dp[i][1] 表示当前持有股票。那么最后返回dp[n-1][0]。
∙
\\bullet
∙ dp[i][1] 不变,对于dp[i][0]加上小费fee。
d
p
[
i
]
[
0
]
=
m
a
x
(
d
p
[
i
−
1
]
[
0
]
,
d
p
[
i
−
1
]
[
1
]
+
p
r
i
c
e
s
[
i
]
−
f
e
e
)
;
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]-fee);
dp[i][0]=max(dp[i−1][0],dp[i−1][1]+prices[i]−fee);
4.3 代码
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int n=prices.size();
if(n==1) return 0;
//dp[i][0]表示当前不持有股票,dp[i][1]表示当前持有股票
vector<vector<int>>dp(n,vector<int>(2,0));
dp[0][1]=-prices[0];
for(int i=1;i<n;i++)
{
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]-fee);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
}
return dp[n-1][492,动态规划和贪心算法解买卖股票的最佳时机 II
Leetcode No.188 买卖股票的最佳时机 IV(动态规划)