1
1
## 四数之和
2
2
### 题目描述
3
3
4
- 给定一个包含 n 个整数的数组 nums 和一个目标值 target,
5
- 判断 nums 中是否存在四个元素 a,b,c 和 d ,
6
- 使得 a + b + c + d 的值与 target 相等?
7
- 找出所有满足条件且不重复的四元组。
4
+ 给定一个包含 n 个整数的数组 ` nums ` 和一个目标值 ` target ` ,判断 ` nums ` 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 ` target ` 相等?找出所有满足条件且不重复的四元组。
8
5
9
- 注意:
6
+ ** 注意:**
10
7
11
8
答案中不可以包含重复的四元组。
12
9
13
- 示例:
14
-
10
+ ** 示例:**
11
+ ```
15
12
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
16
13
17
14
满足要求的四元组集合为:
20
17
[-2, -1, 1, 2],
21
18
[-2, 0, 0, 2]
22
19
]
20
+ ```
23
21
24
22
25
23
### 解法
26
- 1 . 将数组排序
24
+
25
+ #### 解法一
26
+ 1 . 将数组排序;
27
27
2 . 先假设确定一个数 nums[ i] 将 4Sum 问题转换为 3Sum 问题;
28
28
3 . 再假设确定一个数将 3Sum 问题转换为 2Sum 问题;
29
29
4 . 对排序数组,用首尾指针向中间靠拢的思路寻找满足 target 的 nums[ l] 和 nums[ k]
30
30
31
31
``` java
32
32
class Solution {
33
33
public List<List<Integer > > fourSum (int [] nums , int target ) {
34
-
35
- List<List<Integer > > re = new ArrayList<> ();
36
- if (nums == null || nums. length < 4 ) {
37
- return re;
34
+
35
+ List<List<Integer > > re = new ArrayList<> ();
36
+ if (nums == null || nums. length < 4 ) {
37
+ return re;
38
38
}
39
39
Arrays . sort(nums);
40
40
for (int i = 0 ; i < nums. length - 3 ; i++ ) {
41
-
41
+
42
42
// 当 nums[i] 对应的最小组合都大于 target 时,后面大于 nums[i] 的组合必然也大于 target,
43
- if (nums[i] + nums[i+ 1 ] + nums[i+ 2 ] + nums[i+ 3 ] > target) {
43
+ if (nums[i] + nums[i + 1 ] + nums[i + 2 ] + nums[i + 3 ] > target) {
44
44
break ;
45
45
}
46
46
// 当 nums[i] 对应的最大组合都小于 target 时, nums[i] 的其他组合必然也小于 target
47
- if (nums[i] + nums[nums. length- 3 ] + nums[nums. length- 2 ] + nums[nums. length- 1 ] < target) {
47
+ if (nums[i] + nums[nums. length - 3 ] + nums[nums. length - 2 ] + nums[nums. length - 1 ] < target) {
48
48
continue ;
49
49
}
50
50
51
51
int firstNum = nums[i];
52
52
for (int j = i + 1 ; j < nums. length - 2 ; j++ ) {
53
53
54
54
// nums[j] 过大时,与 nums[i] 过大同理
55
- if (nums[i] + nums[j] + nums[j+ 1 ] + nums[j+ 2 ] > target) {
55
+ if (nums[i] + nums[j] + nums[j + 1 ] + nums[j + 2 ] > target) {
56
56
break ;
57
57
}
58
58
// nums[j] 过小时,与 nums[i] 过小同理
59
- if (nums[i] + nums[j] + nums[nums. length- 2 ] + nums[nums. length- 1 ] < target) {
59
+ if (nums[i] + nums[j] + nums[nums. length - 2 ] + nums[nums. length - 1 ] < target) {
60
60
continue ;
61
61
}
62
62
@@ -65,35 +65,89 @@ class Solution {
65
65
int k = nums. length - 1 ;
66
66
while (l < k) {
67
67
int tempSum = nums[l] + nums[k];
68
- if (tempSum == twoSum) {
68
+ if (tempSum == twoSum) {
69
69
ArrayList<Integer > oneGroup = new ArrayList<> (4 );
70
70
oneGroup. add(nums[i]);
71
71
oneGroup. add(nums[j]);
72
72
oneGroup. add(nums[l++ ]);
73
73
oneGroup. add(nums[k-- ]);
74
74
re. add(oneGroup);
75
75
while (l < nums. length && l < k && nums[l] == oneGroup. get(2 ) && nums[k] == oneGroup. get(3 )) {
76
- l++ ;k-- ;
76
+ l++ ;
77
+ k-- ;
77
78
}
78
- }
79
- else if (tempSum < twoSum) {
79
+ } else if (tempSum < twoSum) {
80
80
l++ ;
81
- }
82
- else {
81
+ } else {
83
82
k-- ;
84
83
}
85
84
}
86
85
// 跳过重复项
87
- while ((j < nums. length - 2 ) && (twoSum + nums[i] + nums[j+ 1 ] == target)) {
86
+ while ((j < nums. length - 2 ) && (twoSum + nums[i] + nums[j + 1 ] == target)) {
88
87
j++ ;
89
88
}
90
89
}
91
90
// 跳过重复项
92
- while (i < nums. length - 3 && nums[i+ 1 ] == firstNum){
91
+ while (i < nums. length - 3 && nums[i + 1 ] == firstNum) {
93
92
i++ ;
94
93
}
95
94
}
96
95
return re;
97
96
}
98
97
}
98
+ ```
99
+
100
+ #### 解法二
101
+ 对数组进行排序,利用指针 ` i ` , ` j ` 固定前两个数,` p ` , ` q ` 指向剩余数组的首尾,判断四数和是否为 ` target ` :
102
+ - 若是,添加到 ` list ` 中。此时 右移 ` p ` 直到 ` nums[p] != nums[p - 1] ` (为了去重)。同样,` q ` 左移,进行去重。
103
+ - 若四数和大于 ` target ` ,` q ` 指针左移;否则 ` p ` 指针右移。
104
+ - 对于外面的两层 ` for ` 循环,同样需要进行去重操作。
105
+
106
+ ``` java
107
+ class Solution {
108
+ public List<List<Integer > > fourSum (int [] nums , int target ) {
109
+ Arrays . sort(nums);
110
+ int n = nums. length;
111
+ List<List<Integer > > list = new ArrayList<> ();
112
+ int p = 0 ;
113
+ int q = 0 ;
114
+ for (int i = 0 ; i < n - 3 ; ++ i) {
115
+ for (int j = i + 1 ; j < n - 2 ; ++ j) {
116
+ p = j + 1 ;
117
+ q = n - 1 ;
118
+ while (p < q) {
119
+ int val = nums[i] + nums[j] + nums[p] + nums[q];
120
+ if (val == target) {
121
+ list. add(Arrays . asList(nums[i], nums[j], nums[p], nums[q]));
122
+ // p 指针右移,直到 nums[p] 与 nums[p - 1] 不等
123
+ ++ p;
124
+ while (p < q && nums[p] == nums[p - 1 ]) {
125
+ ++ p;
126
+ }
127
+ -- q;
128
+ while (p < q && nums[q] == nums[q + 1 ]) {
129
+ -- q;
130
+ }
131
+ } else if (val > target) {
132
+ -- q;
133
+ } else {
134
+ q = val > target ? q - 1 : q;
135
+ p = val < target ? p + 1 : p;
136
+ }
137
+ }
138
+
139
+ // j < n - 3:保证 j 不会溢出
140
+ while (j < n - 3 && nums[j] == nums[j + 1 ]) {
141
+ ++ j;
142
+ }
143
+ }
144
+
145
+ // i < n - 4:保证 i 不会溢出
146
+ while (i < n - 4 && nums[i] == nums[i + 1 ]) {
147
+ ++ i;
148
+ }
149
+ }
150
+ return list;
151
+ }
152
+ }
99
153
```
0 commit comments