Skip to content

Commit 972d1f7

Browse files
committed
partition, backpack
1 parent 250ebf1 commit 972d1f7

15 files changed

Lines changed: 1271 additions & 916 deletions

Java/Backpack II.java

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
M
2-
1518497606
3-
tags: DP
2+
1524202756
3+
tags: DP, Backpack DP
44

5-
做了Backpack I, 这个就如出一辙, 只不过: dp存的不是w可否存成功true/false. dp存的是加上sum value的最大值.
6-
想法还是选了A[i - 1] 或者没选A[i - 1]时候不同的value值.
5+
#### Backpack DP
6+
- 做了Backpack I, 这个就如出一辙, 只不过: dp存的不是max weight, 而是 value的最大值.
7+
- 想法还是选了A[i - 1] 或者没选A[i - 1]时候不同的value值.
8+
- 时间空间O(mn)
9+
- Rolling Array, 空间O(m)
710

8-
O(m)的做法:
9-
想想的确我们只care 最后一行所以一个存value的就够了.
10-
注意和bakcpackI的 O(m)一样的j是倒序的如果没有更好的j就不要更新就是这个道理.
11-
12-
注意: 如果无法达到的w, 应该mark as impossible. 一种简单做法是mark as -1 in dp.
13-
如果有负数value, 就不能这样, 而是要开一个can[i][w]数组, 也就是backpack I 的原型.
11+
#### Previous DP Solution
12+
- 如果无法达到的w, 应该mark as impossible. 一种简单做法是mark as -1 in dp.
13+
- 如果有负数value, 就不能这样, 而是要开一个can[i][w]数组, 也就是backpack I 的原型.
14+
- 这样做似乎要多一些代码, 好像并不是非常需要
1415

1516

1617
```
@@ -33,6 +34,57 @@
3334
LintCode Copyright Dynamic Programming Backpack
3435
*/
3536

37+
/**
38+
Thoughts:
39+
dp[i][j]: 前i item, 放进weight/size = j 的袋子里的最大value.
40+
constraint: weight
41+
result: aggregate item value
42+
*/
43+
public class Solution {
44+
public int backPackII(int m, int[] A, int V[]) {
45+
if (A == null || V == null || A.length != V.length) {
46+
return 0;
47+
}
48+
int n = A.length;
49+
int[][] dp = new int[n + 1][m + 1];
50+
51+
for (int i = 1; i <= n; i++) {
52+
for (int j = 0; j <= m; j++) {
53+
dp[i][j] = dp[i - 1][j];
54+
if (j - A[i - 1] >= 0) {
55+
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + V[i - 1]);
56+
}
57+
58+
}
59+
}
60+
61+
return dp[n][m];
62+
}
63+
}
64+
65+
// Rolling array:
66+
public class Solution {
67+
public int backPackII(int m, int[] A, int V[]) {
68+
if (A == null || V == null || A.length != V.length) {
69+
return 0;
70+
}
71+
int n = A.length;
72+
int[][] dp = new int[2][m + 1];
73+
74+
for (int i = 1; i <= n; i++) {
75+
for (int j = 0; j <= m; j++) {
76+
dp[i % 2][j] = dp[(i - 1) % 2][j];
77+
if (j - A[i - 1] >= 0) {
78+
dp[i % 2][j] = Math.max(dp[i % 2][j], dp[(i - 1) % 2][j - A[i - 1]] + V[i - 1]);
79+
}
80+
81+
}
82+
}
83+
84+
return dp[n % 2][m];
85+
}
86+
}
87+
3688
/*
3789
Thoughts:
3890
Dealing with value, the dp[i][w] = max value that can be formed over i tems at weight w.

Java/Backpack V.java

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,22 @@
11
M
2-
1518416934
3-
tags: DP
4-
5-
与背包1不同: 这里不是check可能性(OR)或者最多能装的size是多少; 而是计算有多少种正好fill的可能性.
6-
7-
对于末尾, 还是两种情况:
8-
1. i-1位置没有加bag
9-
2. i-1位置加了bag
10-
11-
两种情况可以fill满w的情况加起来, 就是我们要的结果.
12-
13-
如常: dp[n + 1][w + 1]
14-
15-
方法1:
16-
Space: O(MN)
17-
Time: O(MN)
18-
19-
方法2:
20-
空间优化, 滚动数组
21-
Space: O(M) * 2 = O(M)
22-
Time: O(MN)
23-
24-
方法3:
25-
降维打击, 终极优化: 分析row(i-1)的规律, 发现所有row(i)的值, 都跟row(i-1)的左边element相关, 而右边element是没用的.
26-
所以可以被override.
27-
Space: O(M), *一维啊!
28-
Time: O(MN)
2+
1524205822
3+
tags: DP, Backpack DP
4+
5+
#### Backpack DP
6+
- 与背包1不同: 这里不是check可能性(OR)或者最多能装的size是多少; 而是计算有多少种正好fill的可能性.
7+
- 对于末尾, 还是两种情况:
8+
- 1. i-1位置没有加bag
9+
- 2. i-1位置加了bag
10+
- 两种情况可以fill满w的情况加起来, 就是我们要的结果.
11+
- 如常: dp[n + 1][w + 1]
12+
- Space, time: O(MN)
13+
- Rolling array, 空间优化, 滚动数组. Space: O(M)
14+
15+
#### 降维打击, 终极优化
16+
- 分析row(i-1)的规律, 发现所有row(i)的值, 都跟row(i-1)的左边element相关, 而右边element是没用的.
17+
- 所以可以被override.
18+
- Space: O(M), *一维啊!
19+
- Time: O(MN)
2920

3021
```
3122
/*

Java/Backpack.java

Lines changed: 91 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,39 @@
11
M
2-
1517903196
3-
tags: DP
4-
5-
考虑: 用i个item (可跳过地取), 是否能装到weight w?
6-
需要从'可能性'的角度考虑, 不要搞成单一的最大值问题.
7-
8-
1. 背包可装的物品大小和总承重有关.
9-
2. 不要去找dp[i]前i个物品的最大总重, 找的不是这个.
2+
1524200994
3+
tags: DP, Backpack DP
4+
5+
给i本书, 每本书有自己的重量 int[] A, 背包有自己的大小M, 看最多能放多少重量的书?
6+
7+
#### Backpack DP 1
8+
- 简单直白的思考 dp[i][m]: 前i本书, 背包大小为M的时候, 最多能装多种的书?
9+
- **注意**: 背包问题, 重量weight一定要是一维.
10+
- dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + A[i - 1]);
11+
- 每一步都track 最大值
12+
- 最后return dp[n][m]
13+
- 时间空间 O(mn)
14+
- Rolling array, 空间O(m)
15+
16+
#### Backpack DP 2
17+
- true/false求解, 稍微曲线救国: 重点是, 最后, 按照weight从大到小遍历, 第一个遇到true的, index就是最大值.
18+
- 考虑: 用i个item (可跳过地取), 是否能装到weight w?
19+
- 需要从'可能性'的角度考虑, 不要搞成单一的最大值问题.
20+
- 1. 背包可装的物品大小和总承重有关.
21+
- 2. 不要去找dp[i]前i个物品的最大总重, 找的不是这个.
1022
dp[i]及时找到可放的最大sum, 但是i+1可能有更好的值, 把dp[i+1]变得更大更合适.
1123

12-
boolean[][] dp[i][j]表示: 有前i个item, 用他们可否组成size为j的背包? true/false.
13-
(反过来考虑了不是想是否超过size j, 而是考虑是否能拼出exact size == j)
14-
**注意**: 虽然dp里面一直存在i的位置, 实际上考虑的是在i位置的时候, 看前i-1个item.
15-
16-
多项式规律:
17-
1. picked A[i-1]: 就是A[i-1]被用过, weight j 应该减去A[i-1]. 那么dp[i][j]就取决于dp[i-1][j-A[i-1]]的结果.
18-
2. did not pick A[i-1]: 那就是说, 没用过A[i-1], 那么dp[i][j]就取决于上一行d[i-1][j]
19-
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - A[i - 1]]
24+
##### 做法
25+
- boolean[][] dp[i][j]表示: 有前i个item, 用他们可否组成size为j的背包? true/false.
26+
- (反过来考虑了不是想是否超过size j, 而是考虑是否能拼出exact size == j)
27+
- **注意**: 虽然dp里面一直存在i的位置, 实际上考虑的是在i位置的时候, 看前i-1个item.
2028

21-
结尾:
22-
跑一遍dp 最下面一个row. 从末尾开始找, 最末尾的一个j (能让dp[i][j] == true), 就是最多能装的大小 :)
29+
##### 多项式规律
30+
- 1. picked A[i-1]: 就是A[i-1]被用过, weight j 应该减去A[i-1]. 那么dp[i][j]就取决于dp[i-1][j-A[i-1]]的结果.
31+
- 2. did not pick A[i-1]: 那就是说, 没用过A[i-1], 那么dp[i][j]就取决于上一行d[i-1][j]
32+
- dp[i][j] = dp[i - 1][j] || dp[i - 1][j - A[i - 1]]
2333

24-
时间空间都是O(mn)
34+
##### 结尾
35+
- 跑一遍dp 最下面一个row. 从末尾开始找, 最末尾的一个j (能让dp[i][j] == true), 就是最多能装的大小 :)
36+
- 时间空间都是O(mn)
2537

2638

2739
```
@@ -49,6 +61,66 @@
4961
5062
5163
*/
64+
65+
/*
66+
Thoughts:
67+
Backpack problem, always consider a dimension with weight/size.
68+
int dp[i][j]: with i items and backpack size/weight-limit of j, what's max weight can we put in?
69+
70+
dp[i][j] depends on last item's size && what's the state with [i-1] items.
71+
72+
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + A[i - 1]);
73+
74+
dp[0][0] = 0; no book, 0 weight limit
75+
dp[0][j] = 0; no book, can't fill bag
76+
dp[i][0] = 0; i books, but weight-limit = 0, can't fill
77+
*/
78+
public class Solution {
79+
public int backPack(int m, int[] A) {
80+
if (A == null || A.length < 0) {
81+
return 0;
82+
}
83+
int n = A.length;
84+
int[][] dp = new int[n + 1][m + 1];
85+
86+
// Calculcate possibility for i items to fill up w weight
87+
for (int i = 1; i <= n; i++) {
88+
for (int j = 0; j <= m; j++) {
89+
// default: item(i-1) not used:
90+
dp[i][j] = dp[i - 1][j];
91+
if (j - A[i - 1] >= 0) { // possible to use item(i-1)
92+
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - A[i - 1]] + A[i - 1]); // use item(i-1)
93+
}
94+
}
95+
}
96+
97+
return dp[n][m];
98+
}
99+
}
100+
101+
// Rolling array
102+
public class Solution {
103+
public int backPack(int m, int[] A) {
104+
if (A == null || A.length < 0) {
105+
return 0;
106+
}
107+
int n = A.length;
108+
int[][] dp = new int[2][m + 1];
109+
110+
// Calculcate possibility for i items to fill up w weight
111+
for (int i = 1; i <= n; i++) {
112+
for (int j = 0; j <= m; j++) {
113+
// default: item(i-1) not used:
114+
dp[i % 2][j] = dp[(i - 1) % 2][j];
115+
if (j - A[i - 1] >= 0) { // possible to use item(i-1)
116+
dp[i % 2][j] = Math.max(dp[i % 2][j], dp[(i - 1) % 2][j - A[i - 1]] + A[i - 1]); // use item(i-1)
117+
}
118+
}
119+
}
120+
return dp[n % 2][m];
121+
}
122+
}
123+
52124
/*
53125
Thoughts:
54126
DO NOT try to find the maxSum using given values: this approach f[i] only returns max sum,

Java/Copy Books.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
1518424818
33
tags: DP, Binary Search, Partition DP
44

5+
给一串书pages[i], k个人, pages[i] 代表每本书的页数. k个人从不同的点同时开始抄书.
6+
7+
, 最快什么时候可以抄完?
8+
59
#### Partition DP
610
- 第一步, 理解题目要求的问题: 前k个人copy完n本书, 找到最少的用时; 也可以翻译成, n本书, 让k个人来copy, 也就是分割成k段.
711
- 最后需要求出 dp[n][k]. : int[n+1][k+1].

Java/Perfect Squares.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
M
22
1518159874
3-
tags: Math, DP, BFS, Partion DP
3+
tags: Math, DP, BFS, Partition DP
44

55
给一个数字n, 找到这个数字 最少能用多少个 平方数组成.
66

KnowledgeHash.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,26 @@ MaxTree, Largest Rectangle In Histogram, Maximal Rectangle (in 2D array)
479479
- 如果不指定段数, 用dp[i]表示前i个元素分段后的最值/可行性/ways. Perfect Squares, Palindrome Partition II
480480
- 入股指定段数, 用dp[i][j]表示前i个元素分成j段后的最值/可行性/ways. Copy Books
481481

482+
### 博弈类
483+
- 常常问: 先手必胜的情况
484+
- 通常从第一步分析, 从简单的来分析
485+
- 必胜: 在当下局面走出一步, 让对手无路可逃. 只要对手有一种输的可能, 就是我必胜.
486+
487+
### 背包类
488+
489+
#### 多种问法
490+
- 填一个什么包, 有一个条件, 重量不超过M
491+
- 不撑爆背包的前提下:
492+
- 装下最多重量物品
493+
- 装下最大价值的物品
494+
- 有多少种方式带走满满一书包物品
495+
496+
#### 方法策略
497+
- 还有几个物品
498+
- 还剩多少跟**总承重**有关
499+
- 用总承重M的大小来开数组.
500+
- 不管几维数组, 总有一维是总承重M
501+
- 比如: dp[i][w] = 能否用前i个物品, 拼出重量W (true/false)
482502

483503

484504
### 区间类(range DP)
@@ -560,6 +580,10 @@ Track queue size, use the queue as in rotation
560580
- always find the entry point or terminating point
561581
- watch out for the return or result of recursed function
562582

583+
### 特征
584+
- "compute nth ...", "list the first n ...", "compute all ..." 常常是recursive solution.
585+
- space inefficient. 占用空间, at least O(n)
586+
563587
# Design
564588

565589
# BigO

0 commit comments

Comments
 (0)