LeetCode解题笔记 34 —— 188. 买卖股票的最佳时机 IV
题目
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [2,4,1], k = 2 输出: 2 解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
示例 2:
输入: [3,2,6,5,0,3], k = 2 输出: 7 解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。 随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
解法
class Solution {
public int maxProfit(int k, int[] prices) {
if(prices==null || prices.length<=1 || k<1){
return 0;
}
List<Integer> listIn = new ArrayList<>();//记录有利润的买入价
List<Integer> listOut = new ArrayList<>();//记录有利润的卖出价
int p = -1;
for(int i = 0; i < prices.length - 1; i++){
if(prices[i]<prices[i+1]){
if(p == -1){
p = prices[i];
listIn.add(p);
}
}else if(prices[i]>prices[i+1]){
if(p != -1){
p = -1;
listOut.add(prices[i]);
}
}
}
if(p!=-1){
listOut.add(prices[prices.length-1]);
}
if(k < listIn.size()){ //可交易次数小于有利润的交易次数
while(listIn.size()> k){//移除或合并交易直到剩下最佳的k次交易
removeOne(listIn,listOut);
}
}
int sum = 0;
for(int i = 0; i < listIn.size(); i++){
sum = sum + listOut.get(i) - listIn.get(i);
}
return sum;
}
//移除一次利润最小的交易或合并两个相邻的交易
private void removeOne(List<Integer> listIn,List<Integer> listOut){
int fromIndex = 0;//要移除或合并的交易买入下标
int toIndex = 0;//要移除或合并的交易卖出下标
int price = Integer.MAX_VALUE;
for(int i = 0; i < listIn.size();i++){
if(listOut.get(i) - listIn.get(i) < price){
fromIndex = i;
toIndex = i;
price = listOut.get(i) - listIn.get(i);
}
if(i < listIn.size() - 1){
// (listOut.get(i) - listIn.get(i)) + (listOut.get(i+1) - listIn.get(i+1)) - (listOut.get(i+1) - listIn.get(i))
int p = listOut.get(i) - listIn.get(i+1);
if(p < price){
fromIndex = i;
toIndex = i + 1;
price = p;
}
}
}
listIn.remove(toIndex);
listOut.remove(fromIndex);
}
}