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 }