|
1 | 1 | package joshua.leetcode.dp;
|
2 | 2 |
|
3 | 3 | public abstract class BuySellStock3 {
|
4 |
| - |
5 |
| - /** |
6 |
| - * Say you have an array for which the ith element is the price of a given stock on day i. |
7 | 4 |
|
8 |
| - Design an algorithm to find the maximum profit. You may complete at most two transactions. |
9 |
| - * @param prices |
10 |
| - * @return |
11 |
| - */ |
12 |
| - public abstract int maxProfit(int[] prices); |
13 |
| - |
14 |
| - /** |
15 |
| - * a little verbose way. |
16 |
| - * @author joy |
17 |
| - * |
18 |
| - */ |
19 |
| - static class Solution1 extends BuySellStock3{ |
| 5 | + /** |
| 6 | + * Say you have an array for which the ith element is the price of a given stock on day i. |
| 7 | + * <p/> |
| 8 | + * Design an algorithm to find the maximum profit. You may complete at most two transactions. |
| 9 | + * |
| 10 | + * @param prices |
| 11 | + * @return |
| 12 | + */ |
| 13 | + public abstract int maxProfit(int[] prices); |
20 | 14 |
|
21 |
| - @Override |
22 |
| - public int maxProfit(int[] prices) { |
23 |
| - |
24 |
| - if(prices==null||prices.length<2) |
25 |
| - return 0; |
26 |
| - int[] endAt=new int[prices.length]; |
27 |
| - int[] endAtMax=new int[prices.length]; |
28 |
| - endAt[0]=endAtMax[0]=0; |
29 |
| - int[] startAt=new int[prices.length]; |
30 |
| - int[] startAtMax=new int[prices.length]; |
31 |
| - startAt[prices.length-1]=startAtMax[prices.length-1]=0; |
32 |
| - for(int i=1;i<prices.length;i++){ |
33 |
| - int spread=prices[i]-prices[i-1]; |
34 |
| - endAt[i]=Math.max(0, spread+endAt[i-1]); |
35 |
| - endAtMax[i]=Math.max(endAt[i], endAtMax[i-1]); |
36 |
| - } |
37 |
| - for(int j=prices.length-2;j>-1;j--){ |
38 |
| - int spread=prices[j+1]-prices[j]; |
39 |
| - startAt[j]=Math.max(0, spread+startAt[j+1]); |
40 |
| - startAtMax[j]=Math.max(startAt[j], startAtMax[j+1]); |
41 |
| - } |
42 |
| - /*for every time point, we know the maximum profit if we conduct one transaction ended at/before this point |
43 |
| - and the maximum profit if we conduct one transaction started at/after this point |
44 |
| - Since we at most can have two transactions. |
45 |
| - */ |
46 |
| - int max=Math.max(startAt[0],endAt[prices.length-1]); |
47 |
| - for(int k=0;k<prices.length-2;k++){ |
48 |
| - max=Math.max(endAtMax[k]+startAtMax[k+1],max); |
49 |
| - } |
50 |
| - return max; |
51 |
| - } |
52 |
| - } |
53 |
| - |
54 |
| - /** |
55 |
| - * |
56 |
| - * 这道题是Best Time to Buy and Sell Stock的扩展,现在我们最多可以进行两次交易。 |
57 |
| - * 我们仍然使用动态规划来完成,事实上可以解决非常通用的情况,也就是最多进行k次交易的情况。 |
58 |
| - 这里我们先解释最多可以进行k次交易的算法,然后最多进行两次我们只需要把k取成2即可。我们还是使用“局部最优和全局最优解法”。 |
59 |
| - 我们维护两种量,一个是当前到达第i天可以最多进行j次交易,最好的利润是多少(global[i][j]),另一个是当前到达第i天,最多可进行j次交易,并且最后一次交易在当天卖出的最好的利润是多少(local[i][j])。 |
60 |
| - 下面我们来看递推式,全局的比较简单, |
| 15 | + /** |
| 16 | + * a little verbose way. |
| 17 | + * |
| 18 | + * @author joy |
| 19 | + */ |
| 20 | + static class Solution1 extends BuySellStock3 { |
61 | 21 |
|
62 |
| - global[i][j]=max(local[i][j],global[i-1][j]), |
63 |
| - 也就是去当前局部最好的,和过往全局最好的中大的那个(因为最后一次交易如果包含当前天一定在局部最好的里面,否则一定在过往全局最优的里面)。对于局部变量的维护,递推式是 |
| 22 | + @Override |
| 23 | + public int maxProfit(int[] prices) { |
64 | 24 |
|
65 |
| - local[i][j]=max(global[i-1][j-1]+max(diff,0),local[i-1][j]+diff), |
66 |
| - 也就是看两个量,第一个是全局到i-1天进行j-1次交易,然后加上今天的交易,如果今天是赚钱的话(也就是前面只要j-1次交易,最后一次交易取当前天),第二个量则是取local第i-1天j次交易,然后加上今天的差值(这里因为local[i-1][j]比如包含第i-1天卖出的交易,所以现在变成第i天卖出,并不会增加交易次数,而且这里无论diff是不是大于0都一定要加上,因为否则就不满足local[i][j]必须在最后一天卖出的条件了)。 |
| 25 | + if (prices == null || prices.length < 2) |
| 26 | + return 0; |
| 27 | + int[] endAt = new int[prices.length]; |
| 28 | + int[] endAtMax = new int[prices.length]; |
| 29 | + endAt[0] = endAtMax[0] = 0; |
| 30 | + int[] startAt = new int[prices.length]; |
| 31 | + int[] startAtMax = new int[prices.length]; |
| 32 | + startAt[prices.length - 1] = startAtMax[prices.length - 1] = 0; |
| 33 | + for (int i = 1; i < prices.length; i++) { |
| 34 | + int spread = prices[i] - prices[i - 1]; |
| 35 | + endAt[i] = Math.max(0, spread + endAt[i - 1]); |
| 36 | + endAtMax[i] = Math.max(endAt[ i], endAtMax[i - 1]); |
| 37 | + } |
| 38 | + for (int j = prices.length - 2; j > -1; j--) { |
| 39 | + int spread = prices[j + 1] - prices[j]; |
| 40 | + startAt[j] = Math.max(0, spread + startAt[j + 1]); |
| 41 | + startAtMax[j] = Math.max(startAt[j], startAtMax[j + 1]); |
| 42 | + } |
| 43 | + /*for every time point, we know the maximum profit if we conduct one transaction ended at/before this point |
| 44 | + and the maximum profit if we conduct one transaction started at/after this point |
| 45 | + Since we at most can have two transactions. |
| 46 | + */ |
| 47 | + int max = Math.max(startAt[0], endAt[prices.length - 1]); |
| 48 | + for (int k = 0; k < prices.length - 2; k++) { |
| 49 | + max = Math.max(endAtMax[k] + startAtMax[k + 1], max); |
| 50 | + } |
| 51 | + return max; |
| 52 | + } |
| 53 | + } |
67 | 54 |
|
68 |
| - 如果上面不好理解,可以这样理解:对于局部变量,第i天最多进行j次交易,可以分两种情况: |
69 |
| - |
70 |
| - 1)一是这第j次交易就是当天买入当天卖出的,那么最大收益就是 global[i-1][j-1] + max(diff, 0), diff为第i天当天股价变化。 |
71 |
| - 2)另一种情况是:第j次交易早就买入了,但是拖到第i天当天才卖出。这种情况分析起来有点绕,但是可以视为:第i-1天卖出的收益 + 第i天当天的股价变化,所以就是local[i-1][j] + diff. |
72 |
| - 这样想就好懂了。 |
73 |
| - |
74 |
| - * @see <a href="http://www.cnblogs.com/EdwardLiu/p/4008162.html">Leetcode: Best Time to Buy and Sell Stock III</a> |
75 |
| - * |
76 |
| - */ |
77 |
| - static class Solution2 extends BuySellStock3{ |
| 55 | + /** |
| 56 | + * 这道题是Best Time to Buy and Sell Stock的扩展,现在我们最多可以进行两次交易。 |
| 57 | + * 我们仍然使用动态规划来完成,事实上可以解决非常通用的情况,也就是最多进行k次交易的情况。 |
| 58 | + * 这里我们先解释最多可以进行k次交易的算法,然后最多进行两次我们只需要把k取成2即可。我们还是使用“局部最优和全局最优解法”。 |
| 59 | + * 我们维护两种量,一个是当前到达第i天可以最多进行j次交易,最好的利润是多少(global[i][j]),另一个是当前到达第i天,最多可进行j次交易,并且最后一次交易在当天卖出的最好的利润是多少(local[i][j])。 |
| 60 | + * 下面我们来看递推式,全局的比较简单, |
| 61 | + * <p/> |
| 62 | + * global[i][j]=max(local[i][j],global[i-1][j]), |
| 63 | + * 也就是去当前局部最好的,和过往全局最好的中大的那个(因为最后一次交易如果包含当前天一定在局部最好的里面,否则一定在过往全局最优的里面)。对于局部变量的维护,递推式是 |
| 64 | + * <p/> |
| 65 | + * local[i][j]=max(global[i-1][j-1]+max(diff,0),local[i-1][j]+diff), |
| 66 | + * 也就是看两个量,第一个是全局到i-1天进行j-1次交易,然后加上今天的交易,如果今天是赚钱的话(也就是前面只要j-1次交易,最后一次交易取当前天),第二个量则是取local第i-1天j次交易,然后加上今天的差值(这里因为local[i-1][j]比如包含第i-1天卖出的交易,所以现在变成第i天卖出,并不会增加交易次数,而且这里无论diff是不是大于0都一定要加上,因为否则就不满足local[i][j]必须在最后一天卖出的条件了)。 |
| 67 | + * <p/> |
| 68 | + * 如果上面不好理解,可以这样理解:对于局部变量,第i天最多进行j次交易,可以分两种情况: |
| 69 | + * <p/> |
| 70 | + * 1)一是这第j次交易就是当天买入当天卖出的,那么最大收益就是 global[i-1][j-1] + max(diff, 0), diff为第i天当天股价变化。 |
| 71 | + * 2)另一种情况是:第j次交易早就买入了,但是拖到第i天当天才卖出。这种情况分析起来有点绕,但是可以视为:第i-1天卖出的收益 + 第i天当天的股价变化,所以就是local[i-1][j] + diff. |
| 72 | + * 这样想就好懂了。 |
| 73 | + * |
| 74 | + * @see <a href="http://www.cnblogs.com/EdwardLiu/p/4008162.html">Leetcode: Best Time to Buy and Sell Stock III</a> |
| 75 | + */ |
| 76 | + static class Solution2 extends BuySellStock3 { |
78 | 77 |
|
79 |
| - @Override |
80 |
| - public int maxProfit(int[] prices) { |
81 |
| - /* |
82 |
| - * at each price point T: |
| 78 | + @Override |
| 79 | + public int maxProfit(int[] prices) { |
| 80 | + /* |
| 81 | + * at each price point T: |
83 | 82 | * global[i] means the maximum profit if we have at most i transactions which all end before T;
|
84 | 83 | * local[i] means the maximum profit if we have at most i-1 transaction which all end before T-1 and one transaction ends at T;
|
85 | 84 | * i varies in 0,1,2
|
86 | 85 | * (at most 2 transactions, 0 case is counted in only for the convenience of calculating 1 case)
|
87 | 86 | */
|
88 |
| - int[] global=new int[]{0,0,0}; |
89 |
| - int[] local=new int[]{0,0,0}; |
90 |
| - for(int i=1;i<prices.length;i++){ |
91 |
| - int diff=prices[i]-prices[i-1]; |
92 |
| - /*for j, can only calculate it descendingly*/ |
93 |
| - for(int j=2;j>=1;j--){ |
94 |
| - local[j]=Math.max(global[j-1]+Math.max(0, diff), local[j]+diff);//update local[j] |
95 |
| - global[j]=Math.max(local[j], global[j]);//update global[j] |
96 |
| - } |
97 |
| - } |
98 |
| - return global[2]; |
99 |
| - } |
100 |
| - |
101 |
| - } |
| 87 | + int[] global = new int[]{0, 0, 0}; |
| 88 | + int[] local = new int[]{0, 0, 0}; |
| 89 | + for (int i = 1; i < prices.length; i++) { |
| 90 | + int diff = prices[i] - prices[i - 1]; |
| 91 | + /*for j, can only calculate it descendingly*/ |
| 92 | + for (int j = 2; j >= 1; j--) { |
| 93 | + local[j] = Math.max(global[j - 1] + Math.max(0, diff), local[j] + diff);//update local[j] |
| 94 | + global[j] = Math.max(local[j], global[j]);//update global[j] |
| 95 | + } |
| 96 | + } |
| 97 | + return global[2]; |
| 98 | + } |
| 99 | + |
| 100 | + } |
102 | 101 | }
|
0 commit comments