基础版

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例1

1
2
3
4
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3

示例2

1
2
3
4
5
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例3

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

思路

贪心算法,通过计算局部最优,综合多个局部最优结果得到全局最优结果

一次循环,只要第二天股票价格比当天高,就买入,否则不买入。

计算当天买入跟第二天卖出的利润和,即为结果。

并不一定要在最低值买入,在最高点卖出。因为每次低买高卖的累积和等于最低点与最高点之间的收益。

代码

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public int maxProfit(int[] prices) {
int result = 0;
for(int i=0; i<=prices.length-2; i++){
if(prices[i]<prices[i+1]){
result += prices[i+1]-prices[i];
}
}
return result;
}
}

题目链接

有手续费版

给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每次交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。

示例 1:

1
2
3
4
5
6
7
8
输入: 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.

注意 :

1
2
3
0 < prices.length <= 50000.
0 < prices[i] < 50000.
0 <= fee < 50000.

思路

简单DP问题

当前的状态 i 共有两种,持有股票不持有股票

持有股票状态可能是 前一状态买入 或者 当前买入:

收益方程:$buy{profit}^i=max(buy{profit}^{i-1}, sell_{profit}^{i-1}-prices[i])$

不持有股票可能是 前一状态卖出 或者 当前卖出:

收益方程:$sell{profit}^i=max(sell{profit}^{i-1}, prices[i]+buy_{profit}^i-fee)$

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public int maxProfit(int[] prices, int fee) {
int len = prices.length;
if(len<2) return 0;

//没有stock的收益
int sell_profit = 0;
//拥有stock的收益
int buy_profit = -prices[0];

for(int i=1; i<len; i++){
//今天卖了或者之前卖了的收益
sell_profit = Math.max(sell_profit, prices[i]+buy_profit-fee);
//今天买了或者之前买了的收益
buy_profit = Math.max(buy_profit, sell_profit-prices[i]);
}
//卖了股票的收益肯定大于持有股票的收益,因为持有股票是负收益
return sell_profit;
}
}

题目链接

有冷冻期版

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

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

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

思路 + 代码

题目2类似,不过要增加一个状态 ———— 冻结状态

卖出状态只能由买入状态转来。

买入状态可由买入状态或者冻结状态转来。

冻结状态冻结状态或者买入状态转来。

注意状态的依赖关系,不要再依赖前一状态之前先改变当前状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public int maxProfit(int[] prices) {
if(prices==null || prices.length==0)
return 0;
int hold = -prices[0];
int sold = 0;
int freeze = 0;
int len = prices.length;
for(int i=1; i<len; i++){
int pre_sold = sold;
sold = hold + prices[i];
hold = Math.max(hold,freeze-prices[i]);
freeze = Math.max(freeze, pre_sold);
}
return Math.max(sold, freeze);
}
}

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

只允许买卖一次版本

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

注意你不能在买入股票前卖出股票。

示例1:

1
2
3
4
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

示例2:

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

思路

动态规划问题。

维护一个值,存储之前i-1天的最大利润,当前i天的最大利润为当前价格与前i-1天价格最小值的差值与i-1最大利润的较大值。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if(len<2)
return 0;
int result = -prices[0];
int min_price = prices[0];
for(int i=1; i<len; i++){
result = Math.max(result, prices[i]-min_price);
if(prices[i]<min_price)
min_price = prices[i];
}
return result<0?0:result;
}
}

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

只允许买卖两次版本

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

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

示例 1:

1
2
3
4
输入: [3,3,5,0,0,3,1,4]
输出: 6
解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3
  随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3

示例 2:
1
2
3
4
5
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。  
  注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。  
  因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

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

思路 + 代码

四个状态,即第一次买入与卖出,第二次买入与卖出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
if not prices: return 0
first_buy, first_sell = float('-inf'), 0
second_buy, second_sell = float('-inf'), 0
for price in prices:
if first_buy < -price:
first_buy = -price
if first_buy+price > first_sell:
first_sell = first_buy+price
if second_buy + price < first_sell:
second_buy = first_sell - price
if second_buy + price > second_sell:
second_sell = second_buy + price
return second_sell

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

允许买卖k次

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

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

示例 1:

1
2
3
输入: [2,4,1], k = 2
输出: 2
解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2

示例 2:
1
2
3
4
输入: [3,2,6,5,0,3], k = 2
输出: 7
解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4
  随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3

思路 + 代码

参考链接https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/yi-ge-tong-yong-fang-fa-tuan-mie-6-dao-gu-piao-wen/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution(object):
def maxProfitInf(self, prices):
buy, sell = -prices[0], 0
for i in range(1, len(prices)):
buy = max(buy, sell-prices[i])
sell = max(sell, buy+prices[i])
return sell
def maxProfit(self, k, prices):
"""
:type k: int
:type prices: List[int]
:rtype: int
"""
if not prices or k<=0: return 0
n = len(prices)
# 此时相当于可以无限交易
if k >= n//2: return self.maxProfitInf(prices)
# 0表示不持有股票,1表示持有股票
dp = [[[0]*2 for _ in range(k+1)] for _ in range(n)]
for i in range(n):
for j in range(1,k+1):
if i-1<0:
dp[i][j][0], dp[i][j][1] = 0, -prices[i]
continue
dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j][1]+prices[i])
# 表明交易是在k=1开始的
dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0]-prices[i])
return dp[-1][-1][0]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。