Skip to content

Commit 67aba24

Browse files
committed
sequence DP
1 parent bb4922d commit 67aba24

13 files changed

+1263
-865
lines changed

GenerateCodeTable.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ private static String calculateLevel(final String level) {
272272
return "Hard";
273273
case "S" :
274274
return "Super";
275+
case "R" :
276+
return "Review";
275277
}
276278
return "";
277279
}

Java/Best Time to Buy and Sell Stock I.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
E
2+
1517372448
23

3-
理解意思是关键
4+
理解意思是关键:
45
每天都就交易价格n天只让买卖一次那就找个最低价买进找个最高价卖出
56
记录每天最小值Min是多少O(n)
67
每天都算和当下的Min买卖profit最大多少.
@@ -17,7 +18,8 @@
1718
/*
1819
Say you have an array for which the ith element is the price of a given stock on day i.
1920
20-
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.
21+
If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock),
22+
design an algorithm to find the maximum profit.
2123
2224
Example 1:
2325
Input: [7, 1, 5, 3, 6, 4]

Java/Best Time to Buy and Sell Stock II.java

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
E
2-
2+
1517373801
33
和Stock I 的区别可以买卖多次求总和的最大盈利
44

5+
这道题有几种其他不同的思路:
6+
1. Greedy, 每次有相邻的diff符合profit条件, 就卖了, 最后把所有的diff加在一起. 计算delta, 其实简单粗暴, 也还不错.
7+
2. 如下, 从低谷找peek, sell.
8+
3. 繁琐一点的DP. BuyOn[], SellOn[] 从末尾看起
9+
4. DFS计算所有(timeout).Improvement on DFS -> DP -> calculate sellOn[i] and buyOn[i], and then return buyOn[i]. 有点难想, 但是代码简单, 也是O(n)
10+
511
找涨幅最大的区间买卖
612
找到低谷买进:peek = start + 1 时候就是每次往前走一步;若没有上涨趋势继续往低谷前进
713
涨到峰顶卖出:一旦有上涨趋势进一个while loop涨到底, 再加个profit.
@@ -11,11 +17,6 @@
1117

1218
O(n)
1319

14-
这道题有几种其他不同的思路:
15-
1. 如上, 从低谷找peek, sell.
16-
2. Greedy, 每次有相邻的diff符合profit条件, 就卖了, 最后把所有的diff加在一起. 计算delta, 其实简单粗暴, 也还不错.
17-
3. DFS计算所有(timeout).Improvement on DFS -> DP -> calculate sellOn[i] and buyOn[i], and then return buyOn[i]. 有点难想, 但是代码简单, 也是O(n)
18-
1920
```
2021
/*
2122
Say you have an array for which the ith element is the price of a given stock on day i.
@@ -30,6 +31,34 @@ at the same time (ie, you must sell the stock before you buy again).
3031
Tags Expand
3132
Greedy Enumeration Array
3233
*/
34+
35+
/*
36+
Thoughts:
37+
Draw a curve and realize that, only when prices[i] > prices[i - 1], we complete buy/sell and take the profit.
38+
Adding more slopes can be greater than 0~N overall height diff.
39+
*/
40+
class Solution {
41+
public int maxProfit(int[] prices) {
42+
if (prices == null || prices.length == 0) {
43+
return 0;
44+
}
45+
int profit = 0;
46+
for (int i = 1; i < prices.length; i++) {
47+
if (prices[i] > prices[i - 1]) {
48+
profit += prices[i] - prices[i - 1];
49+
}
50+
}
51+
return profit;
52+
}
53+
}
54+
/*
55+
Previous notes about the above solution:
56+
Greedy: when seeing a increase, sell, accumulate the delta benefits.
57+
For instance, at a inclining slope, the sum of delta changes between (i-1, i) equals to the increase of (0 , n), so it's okay to do greedy.
58+
But this is less inteligent, and not very applicable
59+
*/
60+
61+
3362
/*
3463
Thought:
3564
In this case, since we know the entire stock price for all days in the array, we want to this:
@@ -64,27 +93,6 @@ public int maxProfit(int[] prices) {
6493
}
6594
}
6695

67-
/*
68-
Thoughts:
69-
Greedy: when seeing a increase, sell, accumulate the delta benefits.
70-
For instance, at a inclining slope, the sum of delta changes between (i-1, i) equals to the increase of (0 , n), so it's okay to do greedy.
71-
But this is less inteligent, and not very applicable
72-
*/
73-
class Solution {
74-
public int maxProfit(int[] prices) {
75-
if (prices == null || prices.length <= 1) {
76-
return 0;
77-
}
78-
int profit = 0;
79-
for (int i = 1; i < prices.length; i++) {
80-
if (prices[i] > prices[i - 1]) {
81-
profit += prices[i] - prices[i - 1];
82-
}
83-
}
84-
return profit;
85-
}
86-
}
87-
8896
/*
8997
Thoughts:
9098
Optimize the DFS (since it times out)

Java/Best Time to Buy and Sell Stock III .java

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
M
1+
H
2+
1517376279
23

3-
比stock II 多了一个限制只有2次卖出机会也就是找峰头然后往下再找一个峰头
4+
比stock II 多了一个限制只有2次卖出机会
5+
6+
方法1:
7+
DP加状态: 只卖2次, 把买卖分割成5个状态模块.
8+
在模块index 0, 2, 4: 没有持有股票. 1. 一直在此状态, max profit不变; 2. 刚卖掉, dp[i][前状态] + profit
9+
在模块index 1, 3: 持有股票. 1. 一直在此状态, daily profit. 2. 刚刚买进, 状态改变, 但是没有profit yet: dp[i][前状态]
10+
11+
注意: 把每天的partial profit (diff)加在一起, 最终的overall profit是一样的. 唯一更好的是, 不需要记录中间买入的时间点.
12+
13+
方法2:
14+
也就是找峰头然后往下再找一个峰头
415

516
怎么样在才能Optimize两次巅峰呢
617

@@ -28,6 +39,54 @@ You may not engage in multiple transactions at the same time (ie, you must sell
2839
Enumeration Forward-Backward Traversal Array
2940
3041
*/
42+
/*
43+
Thoughts:
44+
DP: calculate the
45+
Able to sell 2 times. Consider the last position dp[i], is it sold 2 times? sold 1 time? before buying 1st stock? before buying 2nd stock? or right in between 1st and 2nd transaction, having 0 stock?
46+
The status of the problem should be recorded, which leads to 2nd dimension to record these status:
47+
0 stock, before buying | having 1st stock | sold 1st stock, having 0, before buying | having 2nd stock| sold 2nd stock
48+
dp[i][4]: max profit at index i, where both are sold.
49+
Move the status from 0 ~ 4, and break when reached the end.
50+
51+
equations are a bit complicated:
52+
- status index 0, 2, 4:
53+
dp[i][j]: dp[i - 1][j - 1] + price[i] - price[i - 1] (status changed from yesterday, and profiting)
54+
OR: dp[i - 1][j] (status didn't change from yesterday)
55+
- status index 1, 3
56+
dp[i][3]: dp[i - 1][j] + price[i] - prices[i - 1] (status didn't change from yesterday, keep profiting)
57+
OR: dp[i - 1][j - 1] (status changed from yesterday, just bought)
58+
59+
init:
60+
dp[0][0] = 0;
61+
62+
One note:
63+
Consider incremental profit sum = overall profit sum. Sum of price[i] - price[i - 1] = price[0~N]
64+
*/
65+
class Solution {
66+
public int maxProfit(int[] prices) {
67+
if (prices == null || prices.length == 0) {
68+
return 0;
69+
}
70+
int profit = 0;
71+
int n = prices.length;
72+
int[][] dp = new int[n][5];
73+
74+
dp[0][0] = 0; // No transaction on day 0
75+
for (int i = 1; i < n; i++) {
76+
for (int j = 1; j < 5; j++) {
77+
int dailyPartialProfit = prices[i] - prices[i - 1];
78+
if (j % 2 == 0) {
79+
dp[i][j] = Math.max(dp[i - 1][j - 1] + dailyPartialProfit, dp[i - 1][j]);
80+
// Find best profit when not having stock
81+
profit = Math.max(profit, dp[i][j]);
82+
} else {
83+
dp[i][j] = Math.max(dp[i - 1][j] + dailyPartialProfit, dp[i - 1][j - 1]);
84+
}
85+
}
86+
}
87+
return profit;
88+
}
89+
}
3190

3291
/*
3392
Thoughts:

Java/Best Time to Buy and Sell Stock IV.java

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
H
2+
1517379489
23

4+
方法1:
5+
DP. 根据StockIII, 不难发现StockIV就是把状态划分为2k+1. 那么同样的代码, 移植.
6+
注意1: 如果k很大, k>n/2, 那么长度为n的数组里面, 最多也只能n/2个transaction,
7+
那么题目简化为stockII, 给n数组, 无限次transaction.
8+
注意2: n可以用滚动数组(prev/now)代替.
9+
注意3: 最后状态是'没有stock'的都该考虑, 做一个 for 循环比较max. 当然, 来一个profit variable,
10+
不断比较, 也是可以的.
11+
12+
方法2:
313
记得要理解为什么 i-1天的卖了又买可以和第 i 天的卖合成一次交易
414
因为每天交易的price是定的所以卖了又买等于没卖这就是可以合并的原因要对价格敏感啊少年
515

@@ -44,6 +54,106 @@
4454
Dynamic Programming
4555
*/
4656

57+
58+
/*
59+
Thoughts:
60+
Similar to StockIII, but able to make k transactions.
61+
K transactions divides leads to 2K + 1 different status: always have the two conditions 'before buying' and 'holding', plus the final sold status.
62+
63+
Equation:
64+
on j%2 == 0 days (not having stock):
65+
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + partialProfit);
66+
on j%2 == 1 days (holding stock)
67+
dp[i][j] = Math.max(dp[i - 1][j] + partialProfit, dp[i - 1][j - 1]);
68+
69+
O(n(2*k + 1)) = O(nk)
70+
space O(nk)
71+
time O(nk)
72+
*/
73+
class Solution {
74+
public int maxProfit(int k, int[] prices) {
75+
if (prices == null || prices.length == 0 || k <= 0) {
76+
return 0;
77+
}
78+
int profit = 0;
79+
int n = prices.length;
80+
int statusLength = 2 * k + 1;
81+
82+
// A side note: if k > n/2, the problem becomes easy: any n/2 number of transactions
83+
if (k >= n/2) {
84+
for (int i = 1; i < n; i++) {
85+
if (prices[i] > prices[i - 1]) {
86+
profit += prices[i] - prices[i - 1];
87+
}
88+
}
89+
return profit;
90+
}
91+
92+
int[][] dp = new int[n][statusLength];
93+
dp[0][0] = 0; // on day 0, having 0 stock, and with 0 transactions.
94+
95+
for (int i = 1; i < n; i++) {
96+
for (int j = 1; j < statusLength; j++) {
97+
//int partialProfit = prices[i] - prices[i - 1];
98+
if (j % 2 == 0) {
99+
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + prices[i] - prices[i - 1]);
100+
// Find best profit when not having stock
101+
profit = Math.max(profit, dp[i][j]);
102+
} else {
103+
dp[i][j] = Math.max(dp[i - 1][j] + prices[i] - prices[i - 1], dp[i - 1][j - 1]);
104+
}
105+
}
106+
}
107+
return profit;
108+
}
109+
}
110+
111+
112+
// optimization: rolling array
113+
// space: O(k), time: O(nk)
114+
class Solution {
115+
public int maxProfit(int k, int[] prices) {
116+
if (prices == null || prices.length == 0 || k <= 0) {
117+
return 0;
118+
}
119+
int profit = 0;
120+
int n = prices.length;
121+
int statusLength = 2 * k + 1;
122+
123+
// A side note: if k > n/2, the problem becomes easy: any n/2 number of transactions
124+
if (k >= n/2) {
125+
for (int i = 1; i < n; i++) {
126+
if (prices[i] > prices[i - 1]) {
127+
profit += prices[i] - prices[i - 1];
128+
}
129+
}
130+
return profit;
131+
}
132+
133+
int[][] dp = new int[2][statusLength];
134+
int prev, curr = 0;
135+
dp[0][0] = 0; // on day 0, having 0 stock, and with 0 transactions.
136+
137+
for (int i = 1; i < n; i++) {
138+
// reverse rolling digit
139+
prev = curr;
140+
curr = 1 - prev;
141+
for (int j = 1; j < statusLength; j++) {
142+
//int partialProfit = prices[i] - prices[i - 1];
143+
if (j % 2 == 0) {
144+
dp[curr][j] = Math.max(dp[prev][j], dp[prev][j - 1] + prices[i] - prices[i - 1]);
145+
// Find best profit when not having stock
146+
profit = Math.max(profit, dp[curr][j]);
147+
} else {
148+
dp[curr][j] = Math.max(dp[prev][j] + prices[i] - prices[i - 1], dp[prev][j - 1]);
149+
}
150+
}
151+
}
152+
return profit;
153+
}
154+
}
155+
156+
47157
/*
48158
Thoughts: http://liangjiabin.com/blog/2015/04/leetcode-best-time-to-buy-and-sell-stock.html
49159
local[i][j] = max(global[i – 1][j – 1] , local[i – 1][j] + diff). WHY????

Java/Decode Ways.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
M
1+
R
22
1517300631
33

44
确定末尾的2种状态: single letter or combos. 然后计算出单个letter的情况, 和双数的情况

Java/House Robber II.java

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
M
2+
1517368869
23

3-
和House Robber I 类似, DP.
4-
5-
根据dp[i-1]是否被rob来讨论dp[i]: dp[i] = Math.max(dp[i-1], dp[i - 2] + nums[i - 1]);
4+
和House Robber I 类似, DP. 根据dp[i-1]是否被rob来讨论dp[i]: dp[i] = Math.max(dp[i-1], dp[i - 2] + nums[i - 1]);
65

76
特别的是末尾的last house first house相连这里就需要分别讨论两种情况:
8-
1. 最后一个房子被rob
9-
2. 最后一个房子没被rob
7+
1. 第一个房子被rob
8+
2. 第一个房子没被rob
109

11-
两种情况做完综合对比一下.
10+
分出两个branch, 可以看做两种状态.
11+
可以考虑用两个DP array, 也可以加一维度, 补充这个状态.
1212

1313
```
1414
/*
@@ -31,9 +31,46 @@
3131
Dynamic Programming
3232
Hide Similar Problems (E) House Robber (M) Paint House (E) Paint Fence (M) House Robber III
3333
34+
*/
3435

35-
36+
/*
37+
Thougths:
38+
If there is a circle, which give 2 branches: index i == 0 was robbed, or index i == 0 was not robbed.
39+
Create the 2nd dimension for this status. dp[i][j], where j = 0 or 1.
40+
dp[i][0]: if index i = 0 was not robbed, what's the max at i.
41+
dp[i][1]: if index i = 0 was robbed, what's the max at i.
42+
Note:
43+
1. Deal with final position with extra care.
44+
2. Initialize the dp carefully
3645
*/
46+
class Solution {
47+
public int rob(int[] nums) {
48+
if (nums == null || nums.length == 0) {
49+
return 0;
50+
} else if (nums.length == 1) {
51+
return nums[0];
52+
}
53+
int n = nums.length;
54+
int[][] dp = new int[n][2];
55+
// index i = 0, not robbed
56+
dp[0][0] = 0;
57+
dp[1][0] = nums[1];
58+
// index i = 0, robbed
59+
dp[0][1] = nums[0];
60+
dp[1][1] = dp[0][1];
61+
62+
for (int i = 2; i < n; i++) {
63+
if (i == n - 1) {
64+
dp[i][0] = Math.max(dp[i - 1][0], dp[i -2][0] + nums[i]);
65+
dp[i][1] = dp[i - 1][1];
66+
} else {
67+
dp[i][0] = Math.max(dp[i - 1][0], dp[i -2][0] + nums[i]);
68+
dp[i][1] = Math.max(dp[i - 1][1], dp[i -2][1] + nums[i]);
69+
}
70+
}
71+
return Math.max(dp[n - 1][0], dp[n - 1][1]);
72+
}
73+
}
3774

3875
/*
3976
Each house depends on front and back houses

0 commit comments

Comments
 (0)