【LeetCode】N数和

1. 3Sum

给定一个无序数组(可能存在重复元素),是否存在三个数之和为0,输出所有不重复的三元组

e.g. 给定数组 [-1, 0, 1, 2, -1, -4],

结果集为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

原理:

首先升序排序

----------------------------------------------------
^  ^                                               ^
|  |                                               |
|  j                                               k
i

j 往后扫,k 往前扫

三数和 < 0 就 j++,> 0 就 k--

直到 == 0 再取下一组

C++实现:

 1 vector<vector<int>> threeSum(vector<int>& nums) {
 2     vector<vector<int>> result;
 3     sort(nums.begin(), nums.end());
 4     for (int i = 0; i < nums.size(); i++) {
 5         // 控制i不重复,只指向一组重复数字的第一个
 6         if (i > 0 && nums[i] == nums[i-1])
 7             continue;
 8         int j = i + 1, k = nums.size() - 1;
 9         while (j < k) {
10             if (nums[i] + nums[j] + nums[k] < 0) {
11                 j++;
12             } else if (nums[i] + nums[j] + nums[k] > 0) {
13                 k--;
14             } else {
15                 result.push_back({nums[i], nums[j], nums[k]});
16                 // 控制j不重复,只指向一组重复数字的第一个
17                 while (j < k && nums[j] == nums[j+1])
18                     j++;
19                 // 控制k不重复,只指向一组重复数字的最后一个
20                 while (j < k && nums[k] == nums[k-1])
21                     k--;
22                 j++;
23                 k--;
24             }
25         }
26     }
27     return result;
28 }    

第4行如果写 i < nums.size() - 2会报 Runtime Error 错,不知道为什么?

2. 3Sum Closest

给定一个无序数组(可能存在重复元素),是否存在三个数之和最接近给定数target,输出这三个数的和。(假设每条输入只有唯一答案)

e.g. 给定数组 [-1, 2, 1, -4],target = 1

则最接近target的和为2 (-1 + 2 + 1 = 2)

C++实现:

 1 int threeSumClosest(vector<int>& nums, int target) {
 2     // 数组元素小于等于3个则直接返回数组和
 3     if (nums.size() <= 3) {
 4         return accumulate(nums.begin(), nums.end(), 0);
 5     }
 6     int close = nums[0] + nums[1] + nums[2];
 7     sort(nums.begin(), nums.end());
 8     for (int i = 0; i < nums.size(); i++) {
 9         if (i > 0 && nums[i] == nums[i-1])
10             continue;
11         int j = i + 1, k = nums.size() - 1;
12         while (j < k) {
13             int current = nums[i] + nums[j] + nums[k];
14             if (abs(current - target) < abs(close - target)) {
15                 close = current;
16                 if (current == target) {
17                     return current;
18                 }
19             }
20             (current < target) ? j++ : k--;
21         }
22     }
23     return close;
24 }

PS:

C++对应的Java代码

vector<vector<int>>                                            List<List<Integer>>
sort(nums.begin(), nums.end());                                Arrays.sort(nums);
result.push_back({nums[i], nums[j], nums[k]});                 result.add(Arrays.asList(nums[i], nums[j], nums[k]));
abs(n)                                                         Math.abs(n)

3. 4Sum

给定一个无序数组(可能存在重复元素),是否存在四个数之和为目标数target,输出所有不重复的四元组

e.g. 给定数组[1, 0, -1, 0, -2, 2],target = 0.

结果集为:
[
  [-1, 0, 0, 1],
  [-2, -1, 1, 2],
  [-2, 0, 0, 2]
]

原理与 3 Sum 相似,首先升序排序,i 从第一个扫到最后,j 从 i + 1 扫到最后。

两个指针为 p 和 k ,p 往后扫,k 往前扫,四数和 < 0 就 p++,> 0 就 k--;直到 == 0 再取下一组 p 和 k。

C++实现:

 1 vector<vector<int>> fourSum(vector<int>& nums, int target) {
 2     int n = nums.size();
 3     if (n < 4)    return {};
 4     vector<vector<int>> result;
 5     sort(nums.begin(), nums.end());
 6     for (int i = 0; i < n - 3; i++) {
 7         if (i > 0 && nums[i] == nums[i - 1])    continue;
 8         // 提高效率,本轮能取的最小的和与本轮能取的最大的和
 9         if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target)   break;
10         if (nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target)   continue;
11         for (int j = i + 1; j < n - 2; j++) {
12             if (j > i + 1 && nums[j] == nums[j - 1])    continue;
13             // 提高效率,本轮能取的最小的和与本轮能取的最大的和
14             if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
15             if (nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target) continue;
16             // 最后两个指针p和k在最内层while上面定义
17             // 如模仿三数和在上面定义k并在j循环体内控制条件写j < k会导致j扫不到最后
18             int p = j + 1, k = n - 1;
19             while (p < k) {
20                 if (nums[i] + nums[j] + nums[p] + nums[k] < target)  p++;
21                 else if (nums[i] + nums[j] + nums[p] + nums[k] > target)  k--;
22                 else {
23                     result.push_back({nums[i], nums[j], nums[p], nums[k]});
24                     while (p < k && nums[p] == nums[p + 1]) p++;
25                     while (p < k && nums[k] == nums[k - 1]) k--;
26                     p++;
27                     k--;
28                 }
29             }
30         }
31     }
32     return result;
33 }
原文地址:https://www.cnblogs.com/wayne793377164/p/7008811.html