买卖股票的最佳时机Ⅰ~Ⅲ
一次搞定所有的买卖股票问题!!
买卖股票的最佳时机Ⅰ
原题地址:买卖股票的最佳时机Ⅰ
题目描述:
给定一个数组 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。
思路:
1.dp数组的构建
考虑使用动态规划来完成,首先进行dp数组的构建,即数组里需要存储的数字代表的含义,由于只有买入之后才能卖出,那么可以将数组的长度设置为1,然后在遍历数组的过程中只存储股票最小的价格。在每次遍历时,先判断当天价格是否小于dp数组中的值,若小于,则买入,然后继续循环;若大于,则计算卖出之后的利润是否大于历史利润的最大值,若大于,则保存当前利润,否则,继续循环;若等于,继续循环。
2.状态转移方程
d
p
[
0
]
=
m
i
n
(
d
p
[
0
]
,
p
r
i
c
e
s
[
i
]
)
dp[0] = min(dp[0], prices[i])
dp[0]=min(dp[0],prices[i])
代码如下:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
dp = [prices[0]]
max_Profit = 0
for i in range(len(prices)):
dp[0] = min(dp[0], prices[i])
max_Profit = max(max_Profit, prices[i]-dp[0])
return max_Profit
买卖股票的最佳时机Ⅱ
原题地址:买卖股票的最佳时机Ⅱ
题目描述:
给你一个整数数组 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 。
总利润为 4 + 3 = 7 。
示例2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
示例3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
思路:
相对于第一种情况而言,改变的只有交易次数,从限制1次变为无数次。在没有交易限制的情况下,只要有利可图,我们就出手。因此,考虑贪心算法解决上述问题。开始遍历数组,并取数组中的第一个元素作为最小值,在遍历过程中,如果当前列表中的元素比最小值小,最小值等于当前元素;若大于,则相当于卖出股票,计算获得利润并累加至总利润中;若等于,循环继续。
考虑如下情况,可以简化计算过程:
有三个数,大小分别为大,中,小
当排列顺序为大,中,小时,最大利润为0
当排列顺序为大,小,中时,最大利润为0
当排列顺序为小,中,大时,最大利润为中 - 小 + 大 - 中,即:
p
r
i
c
e
s
[
1
]
−
p
r
i
c
e
s
[
0
]
+
p
r
i
c
e
s
[
2
]
−
p
r
i
c
e
s
[
1
]
prices[1] - prices[0] + prices[2] - prices[1]
prices[1]−prices[0]+prices[2]−prices[1]
当排列顺序为小,大,中时,最大利润为大 - 小,即:
p
r
i
c
e
s
[
1
]
−
p
r
i
c
e
s
[
0
]
prices[1] - prices[0]
prices[1]−prices[0]
当排列顺序为中,大,小时,最大利润为大 - 中,即:
p
r
i
c
e
s
[
1
]
−
p
r
i
c
e
s
[
0
]
prices[1] - prices[0]
prices[1]−prices[0]
当排列顺序为中,小,大时,最大利润为大 - 小,即:
p
r
i
c
e
s
[
2
]
−
p
r
i
c
e
s
[
1
]
prices[2] - prices[1]
prices[2]−prices[1]
可将上述情况化简如下:
首先判断 p r i c e s [ i + 1 ] − p r i c e s [ i ] prices[i+1] - prices[i] prices[i+1]−prices[i]是否大于0,若大于, 总利润 + p r i c e s [ i + 1 ] − p r i c e s [ i ] 总利润+prices[i+1] - prices[i] 总利润+prices[i+1]−prices[i]否则,继续循环列表
代码如下:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
all_Profit = 0
for i in range(len(prices)-1):
if prices[i+1] - prices[i] > 0:
all_Profit += prices[i+1] - prices[i]
return all_Profit
买卖股票的最佳时机Ⅲ
原题地址:买卖股票的最佳时机Ⅲ
给定一个数组,它的第 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
思路:
当开始限制交易次数后,动态规划便成为最优解决方案。相对于第一种情况来说,就需要采取更为复杂的dp数组。
首先,由示例4,我们需要考虑列表中只有1种元素或者没有元素的情况。
if len(prices) <= 1:
return 0
1.dp数组的构建
首先根据买入和卖出两种操作方式,可以建立两个dp数组记录操作过程。设记录买入的情况为dp0列表,有记录卖出的情况为dp1列表。由此,列表的长度为交易的次数+1(从K=1开始循环,因为之后会用到K-1,K为交易次数)。dp数组的元素含义为截止到第K次交易时的总利润。
初始化:
对于dp0来说,刚开始并没有买入任何一支股票,因此0初始化即可
对于dp1来说,刚开始可以先买入第一天的股票,因此prices[0]初始化即可
2.状态转移方程
对于dp0列表,即买入的情况来说:
是否更新第K次买入的最大利润,取决于以下两种情况的最大值
(1)不更新,仍然维持原第K次买入的利润,即 d p 0 [ k ] dp0[k] dp0[k]
(2)进行更新,利润变为原K-1次卖出再减去当天股票的价格,即 d p 1 [ k − 1 ] − p r i c e s [ i ] dp1[k-1] - prices[i] dp1[k−1]−prices[i]
考虑到本题要求最大利润,即对上述两种情况进行最大值计算,即为dp0数组的状态转移方程:
d p 0 [ k ] = m a x ( d p 0 [ k ] , d p 1 [ k − 1 ] − p r i c e s [ i ] ) dp0[k] = max(dp0[k], dp1[k-1] - prices[i]) dp0[k]=max(dp0[k],dp1[k−1]−prices[i])
对于dp1列表,即买入的情况来说:
是否更新第K次卖出的最大利润,取决于以下两种情况的最大值
(1)不更新,仍然维持原第K次卖出的利润,即 d p 1 [ k ] dp1[k] dp1[k]
(2)进行更新,利润变为原K次买入再加上当天股票的价格,即 d p 0 [ k ] + p r i c e s [ i ] dp0[k] + prices[i] dp0[k]+prices[i]
考虑到本题要求最大利润,即对上述两种情况进行最大值计算,即为dp1数组的状态转移方程:
d p 1 [ k ] = m a x ( d p 1 [ k ] , d p 0 [ k ] + p r i c e s [ i ] ) dp1[k] = max(dp1[k], dp0[k] + prices[i]) dp1[k]=max(dp1[k],dp0[k]+prices[i])
当交易2次后结束循环,最后我们返回 d p 1 [ 2 ] dp1[2] dp1[2]即可
代码如下:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if len(prices) < 2:
return 0
dp0 = [-prices[0]] * (2 + 1)
dp1 = [0] * (2 + 1)
for i in range(1, len(prices)):
for j in range(1, 2+1):
dp0[j] = max(dp0[j], dp1[j-1] - prices[i])
dp1[j] = max(dp1[j], dp0[j] + prices[i])
return max(dp1[2], 0)
完结撒花~~~~~~~~~~~