1、Description
2、题解思路
该题是在121. Best Time to Buy and Sell Stock的基础上进行改进的,在121中每一次至多只能进行一笔交易,但在该问题中交易次数是不限制的,因此也加大了难度,但其思路仍然与121类似,一样可以把所有的数值看做还是二维平面上的点,该时刻的数值就是点的高度。以用例[7,1,5,3,6,4]为例。可以画出如下的图像。
在图中我们可以定义两类点,一类为down点,一类为top点。down点为比右边的点还低的点,top点为比右边的点还高的点。在下图中down点用绿色进行标记,top点用紫色进行标记。要使得总的收益最大应该满足最近的一堆(top-down)点进行交易,累计获取收益。显然在下图中我们也可以得出看到prices[5]−prices[2]<(prices[5]−prices[4])+(prices[3]−prices[2])prices[5]-prices[2]<(prices[5]-prices[4])+(prices[3]-prices[2])prices[5]−prices[2]<(prices[5]−prices[4])+(prices[3]−prices[2]),即图中两条蓝线的长度之和大于黄线的长度。
因此最终会的最大收益值为最近的所有top点与down点对的收益值的累加。
3、代码实现(java)
该算法只需要遍历一遍便可以找到所有的down-top点对,因此时间复杂度为O(n),没有开辟额外的空间,空间复杂度为O(1)。
class Solution {
public int maxProfit(int[] prices) {
if(prices.length==0)return 0;
int maxProfit = 0;
int top = prices[0];
int down = prices[0];
int i =0;
while(i<prices.length-1){
//find the down point
//attwntion,the equal sign can not ignore,because it will cause the death loop with the case prices=[3,3]
while(i<prices.length-1&&prices[i]>=prices[i+1]){
i++;
}
down = prices[i];
//find the top point
while(i<prices.length-1&&prices[i]<=prices[i+1]){
i++;
}
top = prices[i];
maxProfit += (top - down);
// System.out.println("i="+i);
}
return maxProfit;
}
}
4、反思与改进
考虑下图,我们发现最终的最大收益就是橙色线段的长度,其刚好为以下的各个彩色线段的长度之和,那么和上述的方法进行类比,我们可以发现其实最大收益就是各个线段的累加,在上述的例子中就是两条蓝色线段的累加,而在该例子中便是黄、绿、蓝和紫四条线段的累加。在上述的方法中,该例子在i=2时是一个down点,i=6是一个down点(结束点)他们都遵循这样的规律,即只要prices[i+1]>prices[i],那么就把prices[i+1]-prices[i]的值累加到最大收益的结果当中。
因此可以得到以下代码,时间复杂度和空间复杂端均不变,但采用等价的方法使得代码更加清晰和直观。
class Solution {
public int maxProfit(int[] prices) {
int maxprofit = 0;
for (int i = 0; i < prices.length-1; i++) {
if (prices[i+1] > prices[i])
maxprofit += prices[i+1] - prices[i];
}
return maxprofit;
}
}