-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy path4Sum.java
executable file
·228 lines (200 loc) · 7.98 KB
/
4Sum.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
M
1533626601
tags: Hash Table
#### Based on 2sum
- 1. 利用2Sum的原理,把4Sum分为连个2Sum。左一个pair,右一个pair,每个pair里面放2个数字。
- 2. 以一个点,i,作为分界口,也要列举出所有i之前的pair,作为基础。
- 3. 再尝试从所有i+1后面,找合适的2nd pair。
- Time: O(n^2 * x), where x = # of candidates, still slow
- 可以用HashSet<List>, 可以直接比较list里面每一个元素, 保证set不重复.
- Previous Notes: 在造class Pair时候,要做@override的function: hashCode(), equals(Object d). 平时不太想得起来用。
- 参见 http://lifexplorer.me/leetcode-3sum-4sum-and-k-sum/
#### Based on 3Sum
- 3Sum外面再加一层. 参考3Sum. 时间O(n^3)。 但此方法在k-sum时候,无疑过于费时间. O(n^k)
```
/*
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target?
Find all unique quadruplets in the array which gives the sum of target.
Example
Given array S = {1 0 -1 0 -2 2}, and target = 0. A solution set is:
(-1, 0, 0, 1)
(-2, -1, 1, 2)
(-2, 0, 0, 2)
Note
Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
The solution set must not contain duplicate quadruplets.
Tags Expand
Two Pointers Sort Hash Table Array
*/
/*
Thoughts:
Can't do for loop over 3sum, which is O(n^3), not doable.
We can break the nums into 2 major parts by index i.
1st part: from [0 ~ i], we'll try all possible ways to pair [x, i] and store the sum of nums[x]+nums[i] in map.
Note: key is sum, and the value is a hashSet of ArrayList. Where the hashset has itself functions to tell duplicate of pairs.
2nd part: try [i + 1, end], see if any combination sum that makes: target - sum exist in map. -> becomes same old 2sum problem.
O(n)
*/
/**
Why having below front-pair-building after previous for end-pair-checking for loop?
Here: we build [0 ~ i], and in next round, when we processs [i + 1, end], pairs built among [0~i] below will all be used.
Rather: if we have lift the for loop below to calculate [0~i] before the end-pair-checking of same [i~end],
there is one index at [i] will overlap, which turns to be incorrect.
Therefore, we build front-pairs aftwarwards: it's building [0~i] here, which aims to help next round of end-pair-checking on [i+1, end].
*/
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
if (nums == null || nums.length <= 3) return result;
int n = nums.length;
Arrays.sort(nums);
Map<Integer, HashSet<List>> map = new HashMap<>();
Set<String> cache = new HashSet<>();
for (int i = 0; i < n; i++) {
// Check if [i + 1, end] can be added up to target
for (int k = i + 1; k < n; k++) {
int sum = nums[i] + nums[k];
if (map.containsKey(target - sum)) {// Try to match up the 4 pairs
for (List<Integer> frontPair : map.get(target - sum)) {
List<Integer> list = Arrays.asList(frontPair.get(0), frontPair.get(1), nums[i], nums[k]);
String key = buildKey(list);
if (!cache.contains(key)) {
result.add(list);
cache.add(key);
}
}
}
}
// Build up the pair from [0 ~ i]
for (int j = 0; j < i; j++) {
int sum = nums[j] + nums[i];
map.putIfAbsent(sum, new HashSet<>());
map.get(sum).add(Arrays.asList(nums[j], nums[i]));
}
}
return result;
}
private String buildKey(List<Integer> list) {
StringBuffer sb = new StringBuffer();
for (int num : list) sb.append(num + "@");
return sb.toString();
}
}
/*
Thoughts
Perform another layer outside of 3SUM. O(n^3).
Note: If try to divide and perform two 2SUM, it will be a bit difficult. Refer to http://blog.csdn.net/linhuanmars/article/details/24826871
*/
public class Solution {
public ArrayList<ArrayList<Integer>> fourSum(int[] numbers, int target) {
ArrayList<ArrayList<Integer>> rst = new ArrayList<ArrayList<Integer>>();
if(numbers == null || numbers.length < 4) {
return rst;
}
Arrays.sort(numbers);
//Pick 1st element
for (int i = 0; i < numbers.length - 3; i++) {
if (i != 0 && numbers[i] == numbers[i - 1]) {//Check for duplicate of 1st element
continue;
}
//Pick 2nd element
for (int j = i + 1; j < numbers.length - 2; j++) {
if (j != i + 1 && numbers[j] == numbers[j - 1]) {//Check for duplicate of 2nd element
continue;
}
//Pick 3rd and 4th element
int third = j + 1;
int fourth = numbers.length - 1;
while (third < fourth) {
int sum = numbers[i] + numbers[j] + numbers[third] + numbers[fourth];
if (sum < target) {
third++;
} else if (sum > target) {
fourth--;
} else {//sum == target
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(numbers[i]);
list.add(numbers[j]);
list.add(numbers[third]);
list.add(numbers[fourth]);
rst.add(list);
third++;
fourth--;
while (third < fourth && numbers[third] == numbers[third - 1]) {
third++;
}
while (third < fourth && numbers[fourth] == numbers[fourth + 1]){
fourth--;
}
}
}
}
}
return rst;
}
}
/*
NOT Complete yet. Has a order issue in HashSet
http://lifexplorer.me/leetcode-3sum-4sum-and-k-sum/
Thoughts:
Utilize 2Sum.
Notes 2017: no need to create a new class Pair. We can just use list in HashSet<List>, which compairs the list element and eleminate duplicated list.
*/
public class Solution {
//Create class Pair for HashSet<Pair> to use
class Pair {
Integer x;
Integer y;
public Pair(int x, int y){
this.x = x;
this.y = y;
}
@Override
public int hashCode(){
return this.x.hashCode() + this.y.hashCode();
}
@Override
public boolean equals(Object d) {
if (!(d instanceof Pair)) {
return false;
}
Pair p = (Pair)d;
return (this.x == p.x) && (this.y == p.y);
}
}
public ArrayList<ArrayList<Integer>> fourSum(int[] numbers, int target) {
ArrayList<ArrayList<Integer>> rst = new ArrayList<ArrayList<Integer>>();
if (numbers == null || numbers.length < 4) {
return rst;
}
Arrays.sort(numbers);
HashMap<Integer, HashSet<Pair>> map = new HashMap<Integer, HashSet<Pair>>();
for (int i = 0; i < numbers.length; i++) {
for (int j = i + 1; j < numbers.length; j++) {
int sum = numbers[i] + numbers[j];
if (map.containsKey(target - sum)) {
for (Pair p : map.get(target - sum)) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(p.x);
list.add(p.y);
list.add(numbers[i]);
list.add(numbers[j]);
if (!rst.contains(list)) {
rst.add(list);
}
}
}
}
//Add all pairs up to i
for (int j = 0; j < i; j++) {
int sum = numbers[i] + numbers[j];
if (!map.containsKey(sum)) {
map.put(sum, new HashSet<Pair>());
}
map.get(sum).add(new Pair(numbers[j], numbers[i]));
}
}
return rst;
}
}
```