写完这套题,再搞一台时光机,财务自由不是梦(Doge)

==================================

相关题目链接

121 买卖股票的最佳时机

122 买卖股票的最佳时机 II

123 买卖股票的最佳时机 III

188 买卖股票的最佳时机 IV

309 买卖股票的最佳时机含冷冻期

714 买卖股票的最佳时机含手续费

    • 买卖股票的最佳时机(仅一次交易)

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。

示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

分析

遍历每一天。用变量 minprice 记录已遍历天数的最小股价,初始值为第一天股价;

同时记录每天可以得到的最大利润 maxprofit,即前一天的最大利润 和(今日股价 - 历史最小值 minprice)的较大者,初始值为0。返回最后一天的maxprofit。

说明:下述动态规划只保存了全区间极值,没有用列表保存每天的极值

class Solution:def maxProfit(self, prices: List[int]) -> int:minprice = prices[0]maxprofit = 0for price in prices:minprice = min(minprice,price)maxprofit = max(maxprofit,price-minprice)return maxprofit

2. 买卖股票的最佳时机(可多次交易)

给你一个整数数组 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 。

方法一:所有上坡阶段求和

标志 flag 记录是否持有股票;

buy 和 sale 记录当前持有股票的交易价格,如果当前不持有股票则为0

遍历每日股价,每次买入股票后,更新buy、sale(持续更新)和flag ;

每次卖出股票后,更新buy、sale 和 flag(均为0);

最后一天需要检查 是否持有股票,持有需卖出

flag

ACTION

flag 更新

buy更新

sale更新

prices[i+1] > prices[i]

0

买入

1

prices[i]

prices[i+1]

prices[i+1] <= prices[i]

1

卖出

0

0

0

prices[i+1] > prices[i]

1

prices[i+1]

class Solution:def maxProfit(self, prices: List[int]) -> int:# flag 标记是否持有股票flag = 0# buy 记录当前持有股票的买入价格buy = 0# sale 记录当前股票价格,作为暂时的卖出价格sale = 0sum = 0for i in range(len(prices) - 1):#如果当前不持有股票,次日股价比今日高,买入股票(更新买入价格),记录次日股价,更新flag标志 持有if prices[i+1] > prices[i] and not flag:buy = prices[i]sale = prices[i+1]flag = 1#持有股票 且 次日股价不高于今日股价 --> 卖出股票,清空股票买卖价格,更新flag标志 不持有elif prices[i+1] <= prices[i] and flag:sum = sum + (sale - buy)buy = 0sale = 0flag = 0 #持有股票 且 次日股价高于今日股价 --> 继续持有股票,更新卖出价格    elif prices[i+1] > prices[i] and flag:sale = prices[i+1]if flag == 1:sum = sum + (sale - buy)return sum

方法二:贪心

每天都买卖股票(连续持有可以看作当天卖出后再买入),卖出如果收益为正就加入总和

class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)sum = 0for i in range(1,n):tmp = prices[i] - prices[i-1]if tmp > 0:sum += tmpreturn sum

方法三:动态规划

每天有两种状态,收盘后持有或不持有股票;

初始化一个 n x 2的二维数组 dp,求第 0~ n-1 天 持有 和 不持有股票的最大收入;

第n-1 天如果持有股票,卖出一定比继续持有收益大,所以最后返回第n-1天不持有股票的最大收入

dp[i][0] 代表第i天收盘后不持有股票的最大收益 --> 前日不持有今日无操作、前日持有今日卖出

dp[i][1] 代表第i天收盘后持有股票的最大收益 --> 前日已持有今日无操作 、前日不持有今日买入

初始状态,第一天不持有股票最大收益为0;持有即买入一股,最大收益为 -prices[0]

class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)dp= [[0,0]] * ndp[0][0] = 0dp[0][1] = -prices[0]for i in range(1,n):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. 买卖股票的最佳时机含手续费

给定一个整数数组 prices,其中 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

使用动态规划,和上述题2 一样,多了一个手续费,买入时算在开销里

class Solution:def maxProfit(self, prices: List[int], fee: int) -> int:n = len(prices)dp= [[0,0]] * ndp[0][0] = 0dp[0][1] = -prices[0]-feefor i in range(1,n):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]-fee)return dp[n-1][0]

4. 买卖股票的最佳时机含冷冻期

给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。​

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:
输入: prices = [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]

示例 2:
输入: prices = [1]
输出: 0

动态规划分析

每天有三种状态,收盘后股票持有、不持有(在冷冻期)、不持有(不在冷冻期)

初始化一个 n x 3的二维数组 dp,求第 0~ n-1 天 上述三种状态的最大收入;

说明:如果第i天有卖出,则收盘后进入冷冻期,第i+1天不能买入,我们把这个冷冻期的状态记在第i天

dp[i][0] 代表第i天收盘后不持有股票、且不在冷冻期的最大收益

收盘后不在冷冻期 ==> 今日没有卖出股票

+收盘后不持有股票 ==> 前日就不持有股票(前日在 或 不在冷冻期)

状态转移方程:dp[i][0] = max(dp[i-1][0], dp[i-1][1])

dp[i][1] 代表第i天收盘后不持有股票、且在冷冻期的最大收益

收盘后在冷冻期 ==> 今日卖出股票

+收盘后不持有股票 ==> 昨日持有股票 且 今日卖出股票

状态转移方程:dp[i][1] = dp[i-1][2] + prices[i]

dp[i][2] 代表第i天收盘时持有股票的最大收益

收盘时持有股票 ==> 昨日已经持有股票 或 昨日不持有不在冷冻期、今日买入

状态转移方程:dp[i][2] = max(dp[i-1][2], dp[i-1][0] - prices[i])

初始状态:

dp[0][0] = 0 #第一天不持有股票最大收益为0

dp[0][1] = 0 #第一天不持有股票最大收益为0

dp[0][2] = -prices[0] #第一天持有即买入一股,最大收益为 -prices[0]

class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)if n == 1:return 0#dp= [[0,0,0]] * ndp= [[0] * 3  for _ in range(n)]#dp[0][0] = 0#dp[0][1] = 0dp[0][2] = -prices[0]# 1+ (n-1)行#dp = [[0, 0, -prices[0]]] + [[0] * 3 for _ in range(n - 1)]for i in range(1,n):#不持有股票,且不在冷冻期的最大收益dp[i][0] = max(dp[i-1][0], dp[i-1][1])#不持有股票,且在冷冻期的最大收益dp[i][1] = dp[i-1][2] + prices[i]#持有股票的最大收益dp[i][2] = max(dp[i-1][2], dp[i-1][0] - prices[i])return max(dp[n-1][0],dp[n-1][1])

5. 买卖股票的最佳时机(最多可以完成两笔交易)

给定一个数组,它的第 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

方法一:动态规划

每天有五种状态,初始化一个 n x 5的二维数组 dp,求第 0~ n-1 天下述五种状态的最大收入

dp[i][0] 收盘后不持有股票,未交易过的最大收益 --> 0

dp[i][1] 收盘后是首次持有股票的最大收益 --> 昨天同状态,或前序状态 + 今日为首次买入

dp[i][2] 收盘后不持有股票,已交易过一次的最大收益 --> 昨天同状态,或前序状态 + 今日为首次卖出

dp[i][3] 收盘后是第二次持有股票的最大收益 --> 昨天同状态,或前序状态 + 今日为二次买入

dp[i][4] 收盘后不持有股票,已交易过两次的最大收益 --> 昨天同状态,或前序状态 + 今日为二次卖出

初始状态:

dp[0][0],dp[0][2],dp[0][4] 归为第一天不持有股票的情况,最大收益为0

dp[0][1],dp[0][3] 归为第一天持有股票的情况,最大收益为 -prices[0]

class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)dp = [[0]*5 for _ in range(n)]     #dp[i][0] 不持有股票,未交易过的最大收益#dp[i][1] 首次持有股票状态的最大收益#dp[i][2] 不持有股票,已交易过一次的最大收益#dp[i][3] 第二次持有股票状态的最大收益#dp[i][4] 不持有股票,已交易过两次的最大收益dp[0][1] = -prices[0]dp[0][3] = -prices[0]if n == 1:return 0for i in range(1,n):dp[i][0] = 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 max(dp[n-1][0], dp[n-1][2], dp[n-1][4])

方法二:遍历的同时分为两个区间动态规划(运行超时)

将prices分为两个区间,各自找到两个区间一次交易的最大值(使用上述题1的动态规划方法),相加即为当前区间分段方法的最大收益。遍历每种区间分段的最大值,但是这样提交超出了时间限制。

class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)maxProfit = 0# i 为分割点,在0~n-1范围遍历for i in range(n):maxProfit1, maxProfit2 = 0, 0#左区间右区间各自遍历求最大收益#如果i=0,只执行右区间的遍历;如果i=n-1,只执行左区间的遍历,这两种情况都对应只交易一次if i > 0:minPrice1 = 10**6for j in range(i):minPrice1 = min(minPrice1,prices[j])maxProfit1  = max(maxProfit1 ,prices[j] - minPrice1)if i < n-1:minPrice2 = 10**6for k in range(i,n):minPrice2 = min(minPrice2,prices[k])maxProfit2  = max(maxProfit2 ,prices[k] - minPrice2)maxProfit = max(maxProfit, maxProfit1 + maxProfit2)return maxProfit

方法三:从两端各自动态规划求最大收益

从prices左侧开始动态规划找每日收益最大值

从prices右侧开始动态规划找每日收益最小值(高买低卖,反过来就是低买高卖)

得到两个列表,前者减后者就是按天的最大值列表,该列表最大值即为所求

class Solution:def maxProfit(self, prices: List[int]) -> int:n = len(prices)dp = [0] * ndpR = [0] * nif n == 1:return 0dp[0] = 0minVal = prices[0]for i in range(n):                     minVal = min(minVal, prices[i])dp[i] = max(dp[i-1],prices[i]-minVal)dpR[n-1] = 0maxVal = prices[-1]for j in list(range(1,n))[::-1]:               maxVal = max(maxVal,prices[j])dpR[j-1] = min(dpR[j],prices[j-1]-maxVal)maxProfit = 0for i in range(n):maxProfit = max(maxProfit,dp[i] - dpR[i])return maxProfit

6. 买卖股票的最佳时机(最多可以完成k笔交易)

给定一个整数数组 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 。

其实就是将上述题5一般化,使用动态规划

两笔交易将prices分为五个区间 --> k笔交易将prices分为2k+1个区间,每天有2k+1种状态

初始化一个 n x (2k+1) 的二维数组 dp,求第 0~ n-1 天下述2k+1种状态的最大收入

dp[i][0] 收盘后不持有股票,未交易过的最大收益 --> 0

dp[i][1] 收盘后是首次持有股票的最大收益 --> 昨天同状态,或前序状态 + 今日为首次买入

dp[i][2] 收盘后不持有股票,已交易过一次的最大收益 --> 昨天同状态,或前序状态 + 今日为首次卖出

……

dp[i][2*k-1] 收盘后是第二次持有股票的最大收益 --> 昨天同状态,或前序状态 + 今日为第k次买入

dp[i][2*k] 收盘后不持有股票,已交易过两次的最大收益 --> 昨天同状态,或前序状态 + 今日为k次卖出

状态转移方程一般化:

j为奇数,收盘后持有 --> 昨日持有 或 昨日不持有、今日买入

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

j为偶数,收盘后不持有 --> 昨日不持有 或 昨日持有、今日卖出

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

初始状态:

dp[0][0],dp[0][2] ... dp[0][2*k] 归为第一天不持有股票的情况,最大收益为0

dp[0][1],dp[0][3]... dp[0][2*k-1] 归为第一天持有股票的情况,最大收益为 -prices[0]

class Solution:def maxProfit(self, k: int, prices: List[int]) -> int:n = len(prices)if n == 1:return 0dpLine0 = [ -prices[0] if x%2 == 1 else 0 for x in range(2*k+1) ] dp = [dpLine0] + [[0]*(2*k+1) for _ in range(n-1)]#dp[i][0] 不持有股票,未交易过的最大收益#dp[i][1] 首次持有股票状态的最大收益#dp[i][2] 不持有股票,已交易过一次的最大收益#dp[i][3] 第二次持有股票状态的最大收益#dp[i][4] 不持有股票,已交易过两次的最大收益#...for i in range(1,n):dp[i][0] = 0 for j in range(1,2*k+1):dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] - prices[i]) if j%2 == 1 else max(dp[i-1][j], dp[i-1][j-1] + prices[i])return dp[n-1][2*k]#return max(dp[n-1])

[Leetcode] 买卖股票合集(动态规划)相关推荐

  1. LeetCode买卖股票之一:基本套路(122)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<LeetCode买卖股票>系列 在L ...

  2. LeetCode买卖股票的最佳时机系列总结

    LeetCode买卖股票的最佳时机系列总结 此类动态规划从二维动规理解后优化到一维动规,部分题目还可以用到贪心. 目录: 121 买卖股票的最佳时机1 122 买卖股票的最佳时机2 123 买卖股票的 ...

  3. leetcode买卖股票问题(思路、方法、code)

    一文解决Leetcode买卖股票问题 对于前3个问题,均采用了比较巧妙的解法.由于第4个问题具有非常强的泛型,因此采用了DP,第4个问题的dp如果理解的话,实际上只需要稍加修改状态便可以用该dp思路应 ...

  4. leetcode 买卖股票问题

    leetcode 买卖股票问题 lc121 买卖股票最佳时机 lc122 买卖股票最佳时机II lc123. 买卖股票的最佳时机 III lc188. 买卖股票的最佳时机 IV lc121 买卖股票最 ...

  5. 买卖股票类问题动态规划解法(Leetcode题解-Python语言)

    在 Leetcode 中,关于买卖股票的问题共有6道,而这些题目是可以用相同的思维进行求解的,强烈推荐这篇总结,写得非常到位. 股票类问题的动态规划分三步走,1.首先明确方程的含义, T[i][k][ ...

  6. [LeetCode] 买卖股票

    先放一个题解合集:力扣 121题 买卖股票的最佳时机 1.暴力思路:两层循环,遍历所有可能的收益,时间复杂度O(n²). 2.官方题解思路:在某一天能够获得的最大收益,自然是用这天的股票价格 减去 历 ...

  7. leetcode 买卖股票系列题目总结

    总结:买卖股票系列题目 1.买卖股票的最佳时机(简单) 121. 买卖股票的最佳时机 难度简单1093 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易( ...

  8. LeetCode买卖股票问题集合(六种股票问题)

    一.买卖股票的最佳时机 (LeetCode 121) 简单的动态规划问题,只能完成一次买卖,定义二维 dp[i] [] 数组,dp [i] [0]表示没有股票的状态,dp [i] [1]表示持有股票的 ...

  9. LeetCode 买卖股票的最佳时机 - 超详细讲解系列题

    1.分析 使用通用方法,也即动态规划DP (1)LeetCode 121. 买卖股票的最佳时机 class Solution {public int maxProfit(int[] prices) { ...

最新文章

  1. 网页代码抓取工具_MAC网页颜色代码提取工具
  2. 自考计算机英语答题技巧,自考英语题型答题技巧-自考英语写作
  3. 汇编语言第二章知识梳理及思考
  4. 使用pssh进行并行批量操作
  5. oracle 11g的audit导致system表空间快速增长的问题
  6. java程序利用HttpSessionListener实现统计在线人数(示例代码)
  7. 利用阿里云容器服务打通TensorFlow持续训练链路
  8. 23 岁那年你正处在哪个状态?现在呢?
  9. vue数据层思路_vue层级关系的数据管理
  10. 【简单快捷教会你】如何正确使用animate.css,各种动态效果。
  11. 高质量解读《互联网企业安全高级指南》三部曲——实践篇
  12. [GKCTF2020]EZ三剑客-EzWeb
  13. Eclipse的下载、安装与汉化
  14. [转]详细解释数据挖掘中的 10 大算法
  15. Spring简介与IOC容器
  16. 三星直逼英特尔,半导体厂商排名起起伏伏
  17. 2016年10月9日 星期日 --出埃及记 Exodus 18:20
  18. C#开发BIMFACE系列1 BIMFACE 简介
  19. 2006-07-16蜡肉的吃法(不完全)
  20. 计算机桌面文件为何不能剪贴,告诉你电脑不能复制粘贴怎么办

热门文章

  1. 个人PC搭建自己的虚拟服务器
  2. 2022年PMI-ACP考试大纲是什么?快来看
  3. 曰期计算器java,日期计算器
  4. 设计模式(二)——创建型模式
  5. mount error(112): Host is down
  6. 进制转换(16转10)
  7. PAT 乙级 1036  跟奥巴马一起编程
  8. 【C语言刷LeetCode】2126. 摧毁小行星(M)
  9. 微积分的历史(一):起源之背景
  10. 无线通信设计秘密四:唤醒下发算法