解题思路来自:https://blog.csdn.net/u012501459/article/details/46514309
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most two transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
即是每天的股票价格,交易两次,问最大收益。
解法1:
这个问题可以转换成Best Time to Buy and Sell Stock I问题。
两次股票交易的核心是可以定义一个交易点,在这个交易点之前可以做一次交易(赚的最大数目的钱为firstProf),在这个交易点之后可以做一个交易(赚的最大数目的钱是secondProf)。那么要求的是max(firstProf+secondProf)。但是这个方法的时间复杂度是O(N^2),空间复杂度是O(1)。leetcode中显示超时。
可以使用两次扫描的方法避免上面的双重循环。
不同于Best Time to Buy and Sell Stock I中定义的初始状态A[i]表示第i天卖出挣的最大数目的钱,这个更进一步直接定义A[i]表示前i天赚的最大数目的钱。minPrice表示从第0天到第i-1天中的最低价格。
A[0]=0。(初始状态)
A[1]=max(prices[1]-prices[0],A[0])
A[2]=max(prices[2]-minPrice,A[1])
…..
即A[i]=max(price[i]-minPrice,A[i-1]).
A[0]=0
另外一次扫描从数组后向前扫描,定义B[i]表示从第i天到最后一天n能赚的最大数目的钱。maxPrice表示第i+1天到n天的最高价格。
B[n]=0。(初始状态)
B[n-1]=max(maxPrice-prices[n-1],B[n])
B[n-2]=max(maxPrice-prices[n-2],B[n-1])
…..
即B[i]=max(maxPrice-prices[i],B[i+1])
B[n]=0
那么以第i天为分割点能赚的最多数目的钱为A[i]+B[i]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__author__ = 'Zhang Shuai'
class Solution:
def maxProfit(self, prices):
if not prices:
return 0
#最大价格差
pre_maxPrices = 0
#价格最小值
minPrice = prices[0]
#A[0]为0
A = [pre_maxPrices]
for i in prices[1:]:
if i < minPrice:
minPrice = i
A.append(A[-1])
else:
A.append(max(i-minPrice,A[-1]))
post_maxPrices = 0
maxPrices = prices[-1]
#B[-1]为0
#B记录的是从当前位置到末尾的最大价格差
B = [post_maxPrices]
#从倒数第二位开始循环到0
for i in prices[-2::-1]:
if i > maxPrices:
maxPrices = i
#因为从后往前,所以每次在index=0插入
#因为当前位置比之后的最大值还要大,所以不可能在此买入,只能在此位置之后买入,所以此处相当于B[N-2]=B[N-1]
B.insert(0, B[0])
else:
B.insert(0,max(maxPrices-i,B[0]))
return max([A[i] + B[i] for i in range(len(prices))])
print(Solution().maxProfit([1,2,3,4,5]))
解题思路2:
这个比较厉害,就不写python代码了,了解一下就行了。
在Discuss中看到一种很棒的解法,代码只有10行左右,但是不是很好理解。
第二种解法的核心是假设手上最开始只有0元钱,那么如果买入股票的价格为price,手上的钱需要减去这个price,如果卖出股票的价格为price,手上的钱需要加上这个price。
它定义了4个状态:
Buy1[i]表示前i天做第一笔交易买入股票后剩下的最多的钱;
Sell1[i]表示前i天做第一笔交易卖出股票后剩下的最多的钱;
Buy2[i]表示前i天做第二笔交易买入股票后剩下的最多的钱;
Sell2[i]表示前i天做第二笔交易卖出股票后剩下的最多的钱;
那么Sell2[i]=max{Sell2[i-1],Buy2[i-1]+prices[i]}
Buy2[i]=max{Buy2[i-1],Sell[i-1]-prices[i]}
Sell1[i]=max{Sell[i-1],Buy1[i-1]+prices[i]}
Buy1[i]=max{Buy[i-1],-prices[i]}
可以发现上面四个状态都是只与前一个状态有关,所以可以不使用数组而是使用变量来存储即可。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int buy1=numeric_limits<int>::min();
int buy2=numeric_limits<int>::min();
int sell1=0;
int sell2=0;
for(int i=0;i<prices.size();i++)
{
sell2=max(sell2,buy2+prices[i]);
buy2=max(buy2,sell1-prices[i]);
sell1=max(sell1,buy1+prices[i]);
buy1=max(buy1,-prices[i]);
}
return sell2;
}
};