题目1:买卖股票的最佳时机 I
来源:leetcode63 股票的最大利润 和 LC121. 买卖股票的最佳时机
描述:给定数组 prices ,prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。如果你不能获取任何利润,返回 0 。
标签:一次买卖
分析:动态规划
状态: dp[i]代表第i天能获得的最大利润
状态转移方程: dp[i] =max(不做任何操作即前i-1天的最大值, 第i天卖出股票的最大值) =max(dp[i-1],prices[i] - minval)
改进: 为了节省空间,可以将维护d[]改为维护最大利润 profit
复杂度: 时间复杂度:O(n) 空间复杂度:O(1)
代码:
# LC63 LC121
def maxprofitOneSale(prices):
minval, profit = int(1e9), 0
for i in range(len(prices)):
minval = min(prices[i], minval)
profit = max(profit, prices[i] - minval)
return profit
题目2:买卖股票的最佳时机 II
来源:LC 122. 买卖股票 的最佳时机 II 和 百度面试
描述:给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
标签:多次买卖
分析:
贪心:只要能获利 就进行买卖
如果 prices[i]>prices[i-1],就将该差值加入表示邻近的两天有股票的买卖
复杂度: 时间复杂度:O(n) 空间复杂度:O(1)
动态规划:
状态
d[i][0]:代表第i天交易完成后,手中不持股票时的最大利润 (不持股票包括第i-1天没有股票 以及 第i-1天有股票并在第i天将股票卖掉)
d[i][1]:代表第i天交易完成后,手中持有股票时的最大利润(持有股票包括第i-1天有股票 以及 第i-1天没有股票并在第i天买到了新股票)
状态方程
d[i][0]=max(d[i-1][0],d[i-1][1]+prices[i])
d[i][1]=max(d[i-1][0],d[i-1][0]-prices[i])
初始状态:
d[0][0] 第0天(对应prices的第一天 下标为0)交易结束时,没有持有股票,即没有买股票 为0.
d[0][1] 第0天(对应prices的第一天 下标为0)交易结束时,持有股票,即买了第一个股票,为-prices[0]
改进: 为减少时间复杂度,可以用变量sale 代表d[·][0],用变量buy代表d[·][1]
返回:最终返回 sale (手中不含股票)
复杂度: 时间复杂度:O(n) 空间复杂度:O(1)
代码:
# 贪心
def maxprofitManySale1(prices):
profit = 0
for i in range(1, len(prices)):
if prices[i]>prices[i-1]:
profit += prices[i]-prices[i-1]
return profit
# 动态规划
def maxprofitManySale2(prices):
sale, buy = 0, -prices[0]
for i in range(1, len(prices)):
sale, buy = max(sale, buy+prices[i]), max(buy, sale-prices[i])
return sale
题目3:买卖股票的最佳时机 III(多次买卖股票含手续费)
来源:714. 买卖股票的最佳时机含手续费 和 虾皮笔试
描述:给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。你可以无限次地完成交易,但是你每次交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。返回获得利润的最大值。
输入:prices = [1, 3, 2, 8, 4, 9], fee = 2 输出:8
标签:多次买卖含手续费
分析:动态规划
同题目2的动态规划的解法,当含手续费时 在买入股票时候多减手续费即可。
状态:
d[i][0]:代表第i天交易完手里没有股票的最大收益 (第i天不持有股票包括:第i-1天就不持有股票 和 第i天将股票卖掉(第i-1天持有股票) )
d[i][1]:代表第i天交易完手里有股票的最大收益(第i天持有股票包括:第i-1天就持有股票 和 第i天买股票(第i-1天不持有股票))
动态方程:
d[i][0]=max(d[i-1][0], d[i-1][1]+prices[i])
d[i][1]=max(d[i-1][1], d[i-1][0]-prices[i]-fee)
改进:为节省空间开销,可以用 sell代替d[~][0] buy代替d[~][1] 最后返回 sell
复杂度: 时间复杂度:O(n) 空间复杂度:O(1)
代码:
def maxprofitManySaleWithFee(prices, fee):
sale, buy = 0, -prices[0]-fee
for i in range(1, len(prices)):
sale, buy = max(sale, buy + prices[i]), max(buy, sale-prices[i]-fee)
return sale
题目4:多次买卖股票含冷冻期
题目:多次买卖股票含冷冻期
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
输入: [1,2,3,0,2] 输出: 3 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
分析:
状态:
d[i][0]:第i天交易结束后, 不持有股票的最大利润
(①第i天本身就没股票,即第i-1天结束后,不持有股票 d[i-1][0]
② 第i天有股票,即第i-1天结束后有股票,但是卖掉了 d[i-1][1]+prices[i]
③处于冷冻期,即第i-1天卖掉了股票,导致没有股票且冷冻 d[i-1][0] )
d[i][0] = max(d[i-1][0],d[i-1][1]+prices[i])
d[i][1]:第i天交易结束后,持有股票的最大利润
(① 第i天没买票,第i-1天就有股票 d[i-1][1]
② 第i天买的股票,此时第i-1天一定不能卖票,即d[i-1][0] = d[i-2][0],此时我们取值为 d[i-2][0]-prices[i])
d[i][1] = max(d[i-1][1],d[i-2][0]-prices[i])
状态转移方程:
d[i][0] = max(d[i-1][0],d[i-1][1]+prices[i])
d[i][1] = max(d[i-1][1],d[i-2][0]-prices[i])
初始状态:
需要初始化两天的状态(i=0 i=1)
d[0][0]:第0天(对应prices[0])结束后,不持有股票的最大利润 = 0
d[0][1]:第0天(对应prices[0])结束后,持有股票的最大利润 = -prices[0]
d[1][0]:第1天(对应prices[1])结束后,不持有股票的最大利润 = max(d[0][0], d[0][1]+prices[1])
d[1][1]:第1天(对应prices[1])结束后,持有股票的最大利润=max(d[0][1], -prices[1]) # 第1天没买票 或 第1天买票,第0天没买
改进:
salepre, sale, buy代替上述遍历。
复杂度:时间复杂度 O(n) 空间复杂度 O(1)
代码:
def maxprofitManySaleWithFreeze(prices):
# 当天数小于1时
n = len(prices)
if n <= 1:
return 0
# 初始化两天的
salepre, buy = 0, -prices[0]
sale, buy = max(salepre, buy + prices[1]), max(buy, -prices[1])
# 节省空间进行遍历
for i in range(2, len(prices)):
sale, buy, salepre = max(sale, buy + prices[i]), max(buy, salepre - prices[i]), sale
return sale
print(maxprofitManySaleWithFreeze([4,2,7,1,11]))
题目5:两次买卖一只股票
描述:一只股票的价格在4天的波动分别是 [1, 3, 1, 4] 求买卖该股票二次的最大收益(不可以同时买入同时卖出两只股 即 可以完成一次买卖后进行下一次买卖)
分析:动态规划+分治法
本题和一次买卖股票是同一个题型 只不过本题是买卖两次且两次买卖没有关系
可以考虑使用分治法 即 总共的最大利润 = 第一次买卖股票的获利 + 第二次买卖股票的获利
可以设置dp[i]中i来表示一个节点 即两次买卖的分界点 如 dp[1]代表 [1,3]第1-2天的获利 + [3,1,4] 2-3天的获利
ps:思考好分界点 以及边界
复杂度: 时间复杂度:O(n^2) 空间复杂度:O(1) dp可以使用原来的nums的空间
'''
股票的最大利润(2)
题目简介:一只股票的价格在4天的波动分别是 [1, 3, 1, 4] 求买卖该股票二次的最大收益(不可以同时买入同时卖出两只股 即 可以完成一次买卖后进行下一次买卖)
结果: 买卖两次 可以在第一天买 第二天卖 第三天卖 第四天卖
分析:
本题和上一题是同一个题型 只不过本题是买卖两次且两次买卖没有关系
所以可以考虑使用分治法 即 总共的最大利润 = 第一次买卖股票的获利 + 第二次买卖股票的获利
所以可以设置dp[i]中i来表示一个节点 即两次买卖的分界点 如 dp[1]代表 [1,3]第1-2天的获利 + [3,1,4] 2-3天的获利
ps:思考好分界点 以及边界
复杂度:
时间复杂度:O(n^2)
空间复杂度:O(1)
'''
def maxProfit2(nums):
maxpro = 0
for i in range(len(nums)):
maxpro = max(maxpro, maxProfit1(nums[:i]) + maxProfit1(nums[i:]))
return maxpro
题目6:两次买卖一只股票
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。