[leetcode] Best Time to Buy and Sell Stock I, II, III, with cool down

121. Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Example 1:

Input: [7, 1, 5, 3, 6, 4]
Output: 5

max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)

 

Example 2:

Input: [7, 6, 4, 3, 1]
Output: 0

In this case, no transaction is done, i.e. max profit = 0.

 

 

找到元素i之前的最小值,prices[i] 减去这个最小值就是在元素i是卖出的最大利润,最小值由DP得到,从0扫到length - 1不断更新最大值可以得到最终结果
122. Best Time to Buy and Sell Stock II

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 as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

最简单最快的办法,是result += Math.max(prices[i] - prices[i - 1], 0) 从i=0扫到i=length-1一旦有获利就买进卖出

但是这两种求解I II的方法不能沿用到III,VI和cooldown里

 

 

介绍一种可以沿用的方法

对于问题I

维护两个变量:release和hold,release表示如果在i或者i之前卖出的最大值(即i的时候不持有股票),hold表示在i时持有股票的最大值。

recurrent state是hold= Math.max(hold, - prices[i]), release= Math.max(release, hold+ prices[i])

这时有两个问题,一个是initial state是怎样的?另一个是先更新release还是先更新hold?

第二个问题:其实release和hold是同时更新的,因为release的值要借助前一个hold的值,所以先更新release再更新hold

初始的话,hold是Integer.MIN_VALUE, release是0

对于问题II

由于交易次数不限,所以

hold = Math.max(hold, release-prices[i]), release = Math.max(release, hold+prices[i])

这里的更新顺序就比较有意思了,先更新release再更新hold可以通过所有测试点,先储存他们的值每次都用上一次的值更新也可以通过所有测试(我觉得这种对的话很说的过去)

public class Solution {
    public int maxProfit(int[] prices) {
        int release = 0;
        int get = Integer.MIN_VALUE;
        int result = 0;
        for (int price : prices) {
            release = Math.max(release, get + price);
            get = Math.max(get, release - price);
            if (release > result)
                result = release;
        }
        return result;  
    }
}
public class Solution {
    public int maxProfit(int[] prices) {
        int release = 0;
        int get = Integer.MIN_VALUE;
        int result = 0;
        for (int price : prices) {
            int a = release;
            int b = get;
            release = Math.max(a, b + price);
            get = Math.max(b, a - price);
            if (release > result)
                result = release;
        }
        return result;  
    }
}

理解了对于问题I的解法,问题III就很好做了,就是多两个变量,代表第二次交易hold和第二次交易release,问题VI和问题III一样

with cool down也很好做了,就是要根据前天的数据来判断而不是昨天的数据来判断

 

如果都用这种方法来思考的话,所有这些题的答案如下:

I:

public class Solution {
    public int maxProfit(int[] prices) {
        int release = 0;
        int get = Integer.MIN_VALUE;
        for (int price : prices) {
            release = Math.max(release, get + price);
            get = Math.max(get, - price);
        }
        return release;  
    }
}

II:

public class Solution {
    public int maxProfit(int[] prices) {
        int release = 0;
        int get = Integer.MIN_VALUE;
        for (int price : prices) {
            int a = release;
            int b = get;
            release = Math.max(a, b + price);
            get = Math.max(b, a - price);
        }
        return release;  
    }
}
public class Solution {
    public int maxProfit(int[] prices) {
        int release = 0;
        int get = Integer.MIN_VALUE;
        for (int i = 0; i < prices.length; i++) {
            release = Math.max(release, get + prices[i]);
            get = Math.max(get, release - prices[i]);
        }
        return release;  
    }
}

III:

public class Solution {
    public int maxProfit(int[] prices) {
        int hold1 = Integer.MIN_VALUE;
        int release1 = 0;
        int hold2 = Integer.MIN_VALUE;
        int release2 = 0;
        for (int price : prices) {
            release2 = Math.max(hold2 + price, release2);
            hold2 = Math.max(release1 - price, hold2);
            release1 = Math.max(release1, hold1 + price);
            hold1 = Math.max(hold1, - price);
        }
        return release2;
    }
}

VI:

public class Solution {
    public int maxProfit(int k, int[] prices) {
        if (k >= prices.length / 2) {
            int hold = Integer.MIN_VALUE;
            int release = 0;
            for (int price : prices) {
                release = Math.max(release, hold + price);
                hold = Math.max(hold, release - price);
            }
            return release;
        }
        int[] hold = new int[k + 1];
        int[] release = new int[k + 1];
        Arrays.fill(hold, Integer.MIN_VALUE);
        Arrays.fill(release, 0);
        for (int price : prices) {
            for (int i = 1; i <= k; i++) {
                release[i] = Math.max(release[i], hold[i] + price);
                hold[i] = Math.max(hold[i], release[i - 1] - price);
            }
        }
        return release[k];
    }
}

with cool down:

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length < 2) return 0;
        int[] hold = new int[prices.length];
        int[] release = new int[prices.length];
        hold[0] = -prices[0];
        hold[1] = Math.max(-prices[0], -prices[1]);
        release[0] = 0;
        release[1] = Math.max(0, prices[1] - prices[0]);
        for (int i = 2; i < prices.length; i++) {
            release[i] = Math.max(hold[i - 1] + prices[i], release[i - 1]);
            hold[i] = Math.max(hold[i - 1], release[i - 2] - prices[i]);
        }
        return release[prices.length - 1];
    }
}

 

 

 

posted @ 2017-01-18 04:17  Gryffin  阅读(177)  评论(0编辑  收藏  举报