-
Notifications
You must be signed in to change notification settings - Fork 46
/
_1049.java
155 lines (153 loc) · 3.72 KB
/
_1049.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import java.util.stream.IntStream;
/**
* LeetCode 1049 - Last Stone Weight II
*
* Knapsack
* This problem is equivalent to find a subset of stones with sum closest to half of the total sum.
*
* Thinking this problem in terms of the following way:
* 1. The entire merging process can be expressed using a FULL binary tree, where the root is the "minus"
* operator and is computing the subtraction of right subtree from left subtree.
*
* For instance, taking the following tree as an example.
* -
* / \
* A -
* / \
* _ B
* / \
* C D
*
* This indicated
* (a) C - D
* (b) (C - D) - B
* (c) A - [(C - D) - B]
* which can be expanded as A - C + D + B, which partitions A, B, D as a group and C as the other group.
*
* 2. The second question is given an arbitrary partition can we always construct a tree corresponding to it?
* The answer is YES, and we can do this by a greedy contruction approach. I will explain this via an example.
*
* Say (A, B, C, D, E) as the positive group, and (F, G) as the negative group.
*
* We construct the tree in a top-down manner, and prefer to create a leaf w.r.t. the larger group.
*
* Step 1:
* +: A, B, C, D, E
* -: F, G
*
* Positive group is bigger, so I will make a leaf to A.
* -
* / \
* A ?
*
* Now, my positive group becomes [B, C, D, E], and my negative group is still [F, G].
* However, when we recursively construct the tree ?, we need to SWAP both groups as ? is on the negative
* branch, i.e., in next round, my positive group is indeed [F, G] and negative group becomes [B, C, D, E].
*
*
* Step 2:
* +: F, G
* -: B, C, D, E
*
* Negative group is larger, so let us make a leaf for (say) B.
* -
* / \
* A _
* / \
* ? B
*
* This time ? is on the left branch, so we don't need to swap two groups.
*
*
* Step 3:
* +: F, G
* -: C, D, E
*
* Negative group is still larger, so we make a leaf for (say) C.
* -
* / \
* A _
* / \
* - B
* / \
* ? C
*
*
* Step 4:
* +: F, G
* -: D, E
*
* Now we have a tie, we can go either way. Say we want to handle F in the positive group.
* -
* / \
* A _
* / \
* - B
* / \
* - C
* / \
* F ?
*
* Before we advance to next round, remember to remove F from positive group and swap two groups!
*
*
* Step 5:
* +: D, E
* -: G
*
* Positive group is larger, say we pick D.
* -
* / \
* A _
* / \
* - B
* / \
* - C
* / \
* F _
* / \
* D ?
*
* (Don't forget to swap the groups again!)
*
*
* Step 6:
* +: G
* -: E
*
* As two groups both have only one element left, we can now make a terminating step.
*
* -
* / \
* A _
* / \
* - B
* / \
* - C
* / \
* F _
* / \
* D -
* / \
* G E
*
* We are DONE!
* One can try to expand the tree and verify this indeed matches the given partition.
*/
public class _1049 {
public int lastStoneWeightII(int[] stones) {
int sum = IntStream.of(stones).sum();
boolean[] f = new boolean[sum + 1];
f[0] = true;
int ans = sum;
for (int stone : stones) {
for (int j = sum; j - stone >= 0; j--) {
f[j] = f[j] || f[j - stone];
if (f[j]) {
ans = Math.min(ans, Math.abs(j - (sum - j)));
}
}
}
return ans;
}
}