Skip to content

Commit 1b0c41b

Browse files
committed
sequence dp
1 parent a0c14ab commit 1b0c41b

29 files changed

+4155
-3699
lines changed

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
E
2-
1523511808
2+
1531717344
33
tags: Array, DP, Sequence DP
44

55
给个array of stock prices, 限制能交易(/)一轮, 问如何找到最大profit.
@@ -11,7 +11,8 @@
1111

1212
#### DP
1313
- Find min value for first i items, new dp[n + 1].
14-
- 然后用当天的price做减法算max profit.
14+
- dp[i]: 前i天, prices最小的price是多少: min cost of first i days
15+
- 然后用当天的price做减法dp[i]算max profit.
1516
- Time, Space: O(n)
1617
- 更进一步, 用一个min来表示min[i], 因为计算中只需要当下的min.
1718

@@ -27,7 +28,8 @@
2728
/*
2829
Say you have an array for which the ith element is the price of a given stock on day i.
2930
30-
If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock),
31+
If you were only permitted to complete at most one transaction
32+
(ie, buy one and sell one share of the stock),
3133
design an algorithm to find the maximum profit.
3234
3335
Example 1:
@@ -123,13 +125,12 @@ public int maxProfit(int[] prices) {
123125
if (prices == null || prices.length <= 1) {
124126
return 0;
125127
}
126-
int profit = 0;
127-
int min = prices[0];
128+
int profit = 0, min = prices[0];
128129
for (int i = 1; i < prices.length; i++) {
129-
if (prices[i] > min) {
130-
profit = Math.max(profit, prices[i] - min);
131-
} else {
130+
if (prices[i] < min) {
132131
min = prices[i];
132+
} else {
133+
profit = Math.max(profit, prices[i] - min);
133134
}
134135
}
135136
return profit;

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

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
E
2-
1523511814
3-
tags: Array, Greedy, DP, Sequence DP
2+
1531717353
3+
tags: Array, Greedy, DP, Sequence DP, Status DP
4+
time: O(n)
5+
space: O(1) greedy, O(n) dp
46

57
和Stock I 的区别可以买卖多次求总和的最大盈利.
68

@@ -11,7 +13,7 @@
1113
- DFS计算所有(timeout).Improvement on DFS -> DP -> calculate sellOn[i] and buyOn[i], and then return buyOn[i]. 有点难想, 但是代码简单, 也是O(n)
1214

1315
#### Greedy
14-
- 画图, 因为可以无限买卖, 所以只要有上升, 就卖
16+
- 画图, 因为可以无限买卖, 所以只要有上升, 就有profit
1517
- 所有卖掉的, 平移加起来, 其实就是overall best profit
1618
- O(n)
1719

@@ -21,13 +23,18 @@
2123
- profit += prices[peek - 1] - prices[start]; 挺特别的
2224
- 当没有上涨趋势时候peek-1也就是start, 所以这里刚好profit += 0.
2325

24-
#### DP
25-
- 想知道前i天的最大profit, 那么用sequence DP
26-
- 当天的是否能卖, 取决于昨天是否买进, 也就是昨天买了或者卖了的状态: 加状态, 2D DP
27-
- 如果今天是卖的状态, 那么昨天: 要么买进了, 今天 +price 卖出; 要么昨天刚卖, 今天不可能再卖, profit等同.
28-
- 如果今天是买的状态, 那么昨天: 要么卖掉了, 今天 -price 买入; 要么昨天刚卖, 今天不可能再买, profit等同.
29-
30-
#### Rolling Array
26+
#### DP, sequence dp + status
27+
- 想知道前i天的最大profit, 那么用sequence DP:
28+
- dp[i]: represents 前i天的最大profit
29+
- 当天的是否能卖, 取决于昨天是否买进, 也就是 `昨天买了或者卖了的状态`: 加状态, dp[i][0], dp[i][1]
30+
- ``的状态 `dp[i][0]` = 1. 今天买入, 昨天卖掉的dp[i-1][1]结果 - price[i]; 2. 今天不买, 跟昨天买的status dp[i-1][0] 结果 比较.
31+
- ``的状态 `dp[i][1]` = 1. 今天卖出, 昨天买进的dp[i-1][0]结果 + price[i]; 2. 今天不卖, 跟昨天卖的status dp[i-1][1] 结果 比较.
32+
- 注意init:
33+
- dp[0][0] = dp[0][1] = 0; // 0 days,
34+
- dp[1][0] = 0; // sell on 1st day, haven't bought, so just 0 profit.
35+
- dp[1][0] = -prices[0]; // buy on 1st day, with cost of prices[0]
36+
37+
##### Rolling Array
3138
- [i] [i - 1] 相关联, roll
3239

3340

@@ -53,6 +60,8 @@ at the same time (ie, you must sell the stock before you buy again).
5360
Draw a curve and realize that, only when prices[i] > prices[i - 1],
5461
we complete buy/sell and take the profit.
5562
Adding more slopes can be greater than 0~N overall height diff.
63+
64+
// Greedy
5665
*/
5766
class Solution {
5867
public int maxProfit(int[] prices) {
@@ -69,10 +78,7 @@ public int maxProfit(int[] prices) {
6978
}
7079
}
7180

72-
/*
73-
DP
74-
Thoughts: See details at notes above
75-
*/
81+
//DP: See details at notes above
7682
class Solution {
7783
public int maxProfit(int[] prices) {
7884
if (prices == null || prices.length == 0) {
@@ -81,6 +87,7 @@ public int maxProfit(int[] prices) {
8187
int n = prices.length;
8288
int[][] dp = new int[n + 1][2];
8389
dp[0][0] = dp[0][1] = 0;
90+
dp[1][1] = 0;
8491
dp[1][0] = - prices[0];// -2
8592
for (int i = 2; i <= n; i++) {
8693
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i - 1]);

Java/Climbing Stairs.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
- O(n) time, space
1212

1313
#### DP
14-
- 最后一步被前两种走法决定: dp[i] = dp[i - 1] + dp[i - 2]
14+
- 加法原理, 最后一步被前两种走法决定: dp[i] = dp[i - 1] + dp[i - 2]
1515
- 基础sequence DP, int[] dp = int[n + 1];
1616
- DP[]存的是以 1-based index的状态
17+
- dp[i]: count # of ways to finish 前i个 台阶
1718
- 需要知道dp[n] 的状态, 但是最大坐标是[n-1], 所以int[n+1]
1819
- dp[0]往往是有特殊状态的
1920
- O(n) space, time

Java/Coin Change 2.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
M
22
1522735311
3-
tags: DP, Sequence DP, Backpack DP
3+
tags: DP, Backpack DP
44

55
给串数字, target amount, 求总共多少种方式可以reach the amount.
66

Java/Coin Change.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
M
22
1516583739
3-
tags: DP, Sequence DP, Memoization
3+
tags: DP, Backpack DP, Memoization
44

55
给一串不同数额的coins, 和total amount to spent. 最少 用多少个coin可以组合到这个amount. 每种coins个数不限量.
66

Java/House Robber II.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
M
22
1523329114
3-
tags: DP, Sequence DP
3+
tags: DP, Sequence DP, Status DP
44

55
和House Robber I 类似, 搜刮房子, 相邻不能动. 特点是: 现在nums排成了圈, 首尾相连.
66

77
#### Sequence DP
8+
- dp[i][status]: status=[0,1] 情况下, 前i个 房子拿到的 max rob gain. status=0, 1st house robbed; status=1, 1st house skipped
89
- 根据dp[i-1]是否被rob来讨论dp[i]: dp[i] = Math.max(dp[i-1], dp[i - 2] + nums[i - 1]);
910
- 特别的是末尾的last house first house相连. 这里就需要分别讨论两种情况: 第一个房子被搜刮, 或者第一个房子没被搜刮
1011
- be careful with edge case nums = [0], only with 1 element.
@@ -55,13 +56,13 @@ public int rob(int[] nums) {
5556
dp[1][0] = 0; // not picking nums[0]
5657
dp[1][1] = nums[0]; // pick nums[0]
5758

58-
for (int i = 2; i < n; i++) { // spare the (i = n) case
59+
for (int i = 2; i < n; i++) { // skip the (i = n) case
5960
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 2][0] + nums[i - 1]);
6061
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 2][1] + nums[i - 1]);
6162
}
6263
// i = n;
6364
dp[n][0] = Math.max(dp[n - 1][0], dp[n - 2][0] + nums[n - 1]);
64-
dp[n][1] = dp[n - 1][1];
65+
dp[n][1] = dp[n - 1][1]; // because the next-connected dp[0][1] was picked
6566

6667
return (int) Math.max(dp[n][0], dp[n][1]);
6768
}

Java/House Robber.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
E
22
1523329104
33
tags: DP, Sequence DP
4+
time: O(n)
5+
space: O(n) or rolling array O(1)
46

57
搜刮房子, 相邻的不能碰. 每个房子里有value, 求max.
68

79
#### Sequence DP
10+
- dp[i]: 前i个房子拿到的max gain
811
- 看最后结尾状态的前一个或前两个的情况再综合考虑当下的
912
- 搞清楚当下[i]的和之前[i-x]的情况的关系: 不可以连着house, 那么就直接考虑 dp[i-2]的情况
1013
- Sequence DP, new dp[n + 1];

Java/Paint Fence.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- 最多2个fence 颜色相同
99
- 假设i是和 i-1不同那么结果就是 (k-1)*dp[i - 1]
1010
- 假设i是何 i-1相同那么根据条件i-1和i-2肯定不同那么所有的结果就是(k-1)*dp[i-2]
11+
- dp[i]: count # of ways to paint 前i个 fence
1112
- 加法原理
1213
- time, space: O(n)
1314
- rolling array: space O(1)

Java/Paint House II.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
H
22
1523336609
3-
tags: DP, Sequence DP
3+
tags: DP, Sequence DP, Status DP
4+
time: O(NK^2):
5+
space: (NK)
46

57
一排n个房子, 每个房子可涂成k种颜色, 涂每个房子的价钱不一样, 用costs[][]表示.
68

Java/Paint House.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
E
22
1522770984
3-
tags: DP, Sequence DP
3+
tags: DP, Sequence DP, Status DP
4+
time: O(nm), m = # of colors
5+
space: O(nm)
46

57
要paint n个房子, 还有 nx3的cost[][]. 求最少用多少cost paint 所有房子.
68

Java/Word Break.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
M
2-
1527828369
2+
1531713769
33
tags: DP, Sequence DP
4+
time: O(n^2)
5+
space: O(n)
46

57
给一个String word, 和一个字典, 检查是否word可以被劈开, 而所有substring都应该是dictionary里面的words.
68

79
#### Sequence DP
810
- true/false problem, think about dp
911
- 子问题: 前i个字母, 是否可以有valid break
10-
- 检查dp[j] && substring(j, i)
12+
- 检查dp[j] && substring(j, i), for all j = [0 ~ i]
1113
- dp = new boolean[n + 1]; dp[0] = true;
1214
- goal: if there is a j, `dp[j] == true && word[j, n] in dict`. Need iterate over i = [0 ~ n], also j = [0, i]
1315
- 注意, 用set代替list, 因为要用 contains().
@@ -64,10 +66,8 @@
6466
class Solution {
6567
public boolean wordBreak(String s, List<String> dict) {
6668
// check edge case
67-
if (s == null || s.length() == 0
68-
|| dict == null || dict.size() == 0) {
69-
return false;
70-
}
69+
if (s == null || s.length() == 0 || dict == null || dict.size() == 0) return false;
70+
7171
Set<String> words = new HashSet<>(dict);
7272
// init dp
7373
int n = s.length();
@@ -78,9 +78,7 @@ public boolean wordBreak(String s, List<String> dict) {
7878
for (int i = 1; i <= n; i++) {
7979
for (int j = 0; j < i; j++) {
8080
dp[i] |= dp[j] && words.contains(s.substring(j, i));
81-
if (dp[i]) {
82-
break;
83-
}
81+
if (dp[i]) break;
8482
}
8583
}
8684

0 commit comments

Comments
 (0)