LeetCode 123 Best Time to Buy and Sell Stock III

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).

思路:本人脑子比较笨,思路比较冷门,而且效率高。时间复杂度最大为O(n^2),最小为为O(n),并不固定,空间复杂度为O(n)。时间复杂度为什么不固定,下文再说。注意如果是分为两次购买,则第一次卖出而第二次买入之间的时间内,股票必定下跌,否则就不需要分两次购买了。假设他第一次是从a天购入,第b天卖出;第二次购买是从第c天购入。则从第b天至第c天之间至少股票价格下跌一次,甚至连续下跌,所以我们只需要找sub[i]<0的地方断开,分两次购买试试。所以当股票价格2i天上升,第2i+1天下降,或着第2i天下降,第2i+1天上升时,时间复杂度度为O(n^2)

1.用一个数组sub[n-1],(n为股票价格的天数)来存储当天与前一天股票的差价,即sub[i]=prices[i+1]-prices[i],从而将该题转化为一个或者两个最大子序列和的问题。

2.当股票从第2天到第m天一直下跌时,而第m+1天股票价格上涨,则将sub[0...m-1]置为0,当股票在k天上涨,而从从第k+1天到第n一直跌,则将sub[k+1....n]置为0(本步骤仅仅是为了优化,非必须)

3.计算出只购买一次的最大收益,与所有的当sub[i]<0时(这样的i有可能不止一个),分两次购买的收益做比较,取最大值即可。

版本1,用数组,快一些

public class Solution {
	public int maxsum(int[] num,int start,int end) {
		int sum = 0;
		int max = Integer.MIN_VALUE;
		for (int i = start; i <=end; i++) {
			sum += num[i];
			if (max < sum) {
				max = sum;
			}
			if (sum <= 0) {
				sum = 0;
			}
		}
		return max>>0?max:0;
	}
	public int maxProfit(int[] prices) {
		if (prices.length == 0 || prices.length == 1)
			return 0;
		int[] sub = new int[prices.length - 1];
		boolean flag=false;
		for (int i = 0; i < sub.length; i++){
			if(prices[i+1]-prices[i]>=0||flag){
				flag=true;
			    sub[i] = prices[i + 1] - prices[i];
			}else{
				sub[i]=0;
			}
		}
		for (int i = sub.length-1; 0 <= i; i--){
			if(prices[i+1]-prices[i]<0){
			    sub[i] = 0;
			}else{
				break;
			}
		}
		int result=maxsum(sub,0,sub.length-1);
		for (int i=0;i<sub.length;i++){
			if(sub[i]<0){
				int temp=maxsum(sub,0,i-1)+maxsum(sub,i+1,sub.length-1);
				result=result>temp?result:temp;
			}
		}

		return result;
	}
}

版本2,使用ArrayList,当股票从一开始持续下跌,或着从某时间到结束一直下跌,则删除这些sub值。

import java.util.ArrayList;

public class Solution {
    public int maxsum(ArrayList<Integer> num,int start,int end) {
		int sum = 0;
		int max = Integer.MIN_VALUE;
		for (int i = start; i <=end; i++) {
			sum += num.get(i);
			if (max < sum) max = sum;
			if (sum <= 0) sum = 0;
		}
		return max>0?max:0;
	}

	public int maxProfit(int[] prices) {
		if (prices.length==0||prices.length==1) return 0;
		
		ArrayList<Integer>  sub = new ArrayList<Integer>();
		boolean flag=false;
		
		for (int i = 0; i < prices.length-1; i++){
			if(prices[i+1]-prices[i]>=0||flag){
				flag=true;
			    sub.add(prices[i + 1] - prices[i]);
			}	
		}
		for (int i = prices.length-2; 0 <= i; i--){
			if(!sub.isEmpty()&&prices[i+1]-prices[i]<0) sub.remove(sub.size()-1);
			else break;	
		}
		
		if(sub.size()==0) return 0;
		
		int result=maxsum(sub,0,sub.size()-1);
		for (int i=0;i<sub.size();i++){
			if(sub.get(i)<0){
				int temp=maxsum(sub,0,i-1)+maxsum(sub,i+1,sub.size()-1);
				result=result>temp?result:temp;
			}
		}
		
		return result;
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值