买卖股票问题

119 阅读3分钟

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

题目描述

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

注意:

  • 0 < prices.length <= 50000.
  • 0 < prices[i] < 50000.
  • 0 <= fee < 50000.

题目解析

动态规划

  1. 状态定义:dp[i][0]表示第i天不持有股票的最大利润,dp[i][1]表示第i天持有股票的最大利润
  2. 状态转移方程: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])
  3. 初始状态:dp[0][0] = 0, dp[0][1] = -prices[0]
  4. 返回值: dp[n-1][0]

代码

java

  
class Solution {  
public int maxProfit(int[] prices, int fee) {  
int n = prices.length;  
int[][] dp = new int[n][2];  
dp[0][0] = 0;  
dp[0][1] = -prices[0];  
for (int i = 1; i < n; i++) {  
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i] - fee);  
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]);  
}  
return dp[n-1][0];  
}  
}  
  

复杂度分析

  • 时间复杂度:O(n),n为数组长度
  • 空间复杂度:O(n),n为数组长度

python

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

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

题目描述

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​

设计一个算法计算出最大利润。在满足以下约束条件下,​你可以尽可能地完成更多的交易(多次买卖一支股票):

  • 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)
  • 卖出股票后,你无法在第二天买入股票 (即冷冻期为1天)

示例:

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

解题思路

  1. 状态定义:dp[i][j]表示第i天的状态为j时的最大利润,j=0表示持有股票,j=1表示不持有股票且处于冷冻期,j=2表示不持有股票且不处于冷冻期
  2. 状态转移方程:
  • dp[i][0] = max(dp[i-1][0], dp[i-1][2] - prices[i])
dp[i-1][0] 表示第i-1天就持有股票  
dp[i-1][2] - prices[i] 表示第i-1天不持有股票且不处于冷冻期,第i天买入股票  
  • dp[i][1] = dp[i-1][0] + prices[i]
dp[i-1][0] + prices[i] 表示第i-1天持有股票,第i天卖出股票  
  • dp[i][2] = max(dp[i-1][1], dp[i-1][2])
dp[i-1][1] 表示第i-1天不持有股票且处于冷冻期,第i天不操作  
dp[i-1][2] 表示第i-1天不持有股票且不处于冷冻期,第i天不操作  
  1. 初始状态:dp[0][0] = -prices[0],dp[0][1] = 0,dp[0][2] = 0
dp[0][0] = -prices[0] 表示第0天持有股票,只能是第0天买入股票  
dp[0][1] = 0 表示第0天不持有股票且处于冷冻期,只能是第0天卖出股票  
dp[0][2] = 0 表示第0天不持有股票且不处于冷冻期,只能是第0天不操作  
  1. 返回值: max(dp[n-1][1], dp[n-1][2])
因为持有股票的状态不可能是最大利润,  
所以只需要比较不持有股票且处于冷冻期和不持有股票且不处于冷冻期的最大利润即可  
  
dp[n-1][1] 表示第n-1天不持有股票且处于冷冻期,第n天不操作  
dp[n-1][2] 表示第n-1天不持有股票且不处于冷冻期,第n天不操作  

代码

Java

  
public class Solution {  
public int maxProfit(int[] prices) {  
if (prices == null || prices.length == 0) {  
return 0;  
}  
int n = prices.length;  
int[][] dp = new int[n][3];  
dp[0][0] = -prices[0];  
dp[0][1] = 0;  
dp[0][2] = 0;  
for (int i = 1; i < n; i++) {  
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2] - prices[i]);  
dp[i][1] = dp[i - 1][0] + prices[i];  
dp[i][2] = Math.max(dp[i - 1][1], dp[i - 1][2]);  
}  
return Math.max(dp[n - 1][1], dp[n - 1][2]);  
}  
}  
  

复杂度分析

  • 时间复杂度:O(n),n为数组长度
  • 空间复杂度:O(n),n为数组长度

Python3

  
class Solution:  
def maxProfit(self, prices: List[int]) -> int:  
if not prices:  
return 0  
n = len(prices)  
dp = [[0] * 3 for _ in range(n)]  
dp[0][0] = -prices[0]  
dp[0][1] = 0  
dp[0][2] = 0  
for i in range(1, n):  
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][1], dp[i - 1][2])  
return max(dp[n - 1][1], dp[n - 1][2])