# 18. 四数之和 - 力扣题解最佳实践 访问原文链接:[18. 四数之和 - 力扣题解最佳实践](https://leetcoder.net/zh/leetcode/18-4sum),体验更佳! 力扣链接:[18. 四数之和](https://leetcode.cn/problems/4sum), 难度:**中等**。 ## 力扣“18. 四数之和”问题描述 给你一个由 `n` 个整数组成的数组 `nums` ,和一个目标值 `target` 。请你找出并返回满足下述全部条件且**不重复**的四元组 `[nums[a], nums[b], nums[c], nums[d]]` (若两个四元组元素一一对应,则认为两个四元组重复): - `0 <= a, b, c, d < n` - `a`、`b`、`c` 和 `d` **互不相同** - `nums[a] + nums[b] + nums[c] + nums[d] == target` 你可以按 **任意顺序** 返回答案 。 ### [示例 1] **输入**: `nums = [1,0,-1,0,-2,2], target = 0` **输出**: `[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]` ### [示例 2] **输入**: `nums = [2,2,2,2,2], target = 8` **输出**: `[[2,2,2,2]]` ### [约束] - `1 <= nums.length <= 200` - `-10^9 <= nums[i] <= 10^9` - `-10^9 <= target <= 10^9` ## 思路 1. 本题思路同[15. 三数之和](15-3sum.md), 请点链接查看。 2. 区别是`三数`变`四数`,处理`四数`,只需要**多加一重嵌套的循环**。 3. 另外增加了`target`参数,计算时需要把它做为条件带入。 4. 你可能已经看出来了,不管它是`两数`、`三数`还是`四数`,都可以用`双指针技术`。 ## 复杂度 - 时间复杂度: `O(N^3)`. - 空间复杂度: `O(N)`. ## Python ```python # If you want the program to run faster, uncomment the two places in the code. class Solution: def fourSum(self, nums: List[int], target: int) -> List[List[int]]: nums.sort() # nums_2 = [] # for i, num in enumerate(nums): # if i >= 4 and num == nums[i - 1] == nums[i - 2] == nums[i - 3] == nums[i - 4]: # continue # nums_2.append(num) # nums = nums_2 results = set() for i in range(len(nums) - 3): for j in range(i + 1, len(nums) - 2): num = nums[i] + nums[j] # if num > target / 2: # break left = j + 1 right = len(nums) - 1 while left < right: sum_ = nums[left] + nums[right] if sum_ == target - num: results.add((nums[i], nums[j], nums[left], nums[right])) left += 1 elif sum_ > target - num: right -= 1 else: left += 1 return list(results) ``` ## JavaScript ```javascript /** * @param {number[]} nums * @param {number} target * @return {number[][]} */ var fourSum = function(nums, target) { nums.sort((a, b) => a - b); // Uncomment to speed up // let nums2 = []; // for (let i = 0; i < nums.length; i++) { // if (i >= 4 && nums[i] === nums[i-1] && nums[i-1] === nums[i-2] && nums[i-2] === nums[i-3] && nums[i-3] === nums[i-4]) { // continue; // } // nums2.push(nums[i]); // } // nums = nums2; const results = new Set(); for (let i = 0; i < nums.length - 3; i++) { for (let j = i + 1; j < nums.length - 2; j++) { const num = nums[i] + nums[j]; // Uncomment to speed up // if (num > target / 2) { // break; // } let left = j + 1; let right = nums.length - 1; while (left < right) { const sum = nums[left] + nums[right]; if (sum === target - num) { results.add([nums[i], nums[j], nums[left], nums[right]].join(',')); left++; } else if (sum > target - num) { right--; } else { left++; } } } } return Array.from(results).map(str => str.split(',').map(Number)); }; ``` ## Ruby ```ruby # @param {Integer[]} nums # @param {Integer} target # @return {Integer[][]} def four_sum(nums, target) nums.sort! # Uncomment to speed up # nums2 = [] # nums.each_with_index do |num, i| # next if i >= 4 && num == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4] # nums2 << num # end # nums = nums2 results = Set.new (0..nums.length-4).each do |i| (i+1..nums.length-3).each do |j| num = nums[i] + nums[j] # Uncomment to speed up # break if num > target / 2 left = j + 1 right = nums.length - 1 while left < right sum = nums[left] + nums[right] if sum == target - num results.add([nums[i], nums[j], nums[left], nums[right]]) left += 1 elsif sum > target - num right -= 1 else left += 1 end end end end results.to_a end ``` ## Java ```java class Solution { public List> fourSum(int[] nums, int target) { List> results = new ArrayList<>(); Arrays.sort(nums); Set> seen = new HashSet<>(); for (int i = 0; i < nums.length - 3; i++) { for (int j = i + 1; j < nums.length - 2; j++) { int left = j + 1; int right = nums.length - 1; while (left < right) { long sum = (long) nums[i] + nums[j] + nums[left] + nums[right]; if (sum == target) { List quadruplet = Arrays.asList(nums[i], nums[j], nums[left], nums[right]); if (!seen.contains(quadruplet)) { results.add(quadruplet); seen.add(quadruplet); } left++; } else if (sum < target) { left++; } else { right--; } } } } return results; } } ``` ## C++ ```cpp class Solution { public: vector> fourSum(vector& nums, int target) { vector> results; sort(nums.begin(), nums.end()); set> seen; for (int i = 0; i < nums.size() - 3; i++) { for (int j = i + 1; j < nums.size() - 2; j++) { int left = j + 1; int right = nums.size() - 1; while (left < right) { long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right]; if (sum == target) { vector quadruplet = {nums[i], nums[j], nums[left], nums[right]}; if (seen.find(quadruplet) == seen.end()) { results.push_back(quadruplet); seen.insert(quadruplet); } left++; } else if (sum < target) { left++; } else { right--; } } } } return results; } }; ``` ## Go ```go // If you want the program to run faster, uncomment the two places in the code. func fourSum(nums []int, target int) [][]int { sort.Ints(nums) // nums2 := make([]int, 0) // for i := 0; i < len(nums); i++ { // if i >= 4 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4] { // continue // } // nums2 = append(nums2, nums[i]) // } // nums = nums2 results := make([][]int, 0) seen := make(map[string]bool) for i := 0; i < len(nums)-3; i++ { for j := i + 1; j < len(nums)-2; j++ { num := nums[i] + nums[j] // if num > target/2 { // break // } left := j + 1 right := len(nums) - 1 for left < right { sum := nums[left] + nums[right] if sum == target-num { quadruplet := []int{nums[i], nums[j], nums[left], nums[right]} key := fmt.Sprintf("%d,%d,%d,%d", quadruplet[0], quadruplet[1], quadruplet[2], quadruplet[3]) if !seen[key] { results = append(results, quadruplet) seen[key] = true } left++ } else if sum > target-num { right-- } else { left++ } } } } return results } ``` ## C# ```csharp // If you want the program to run faster, uncomment the two places in the code. public class Solution { public IList> FourSum(int[] nums, int target) { Array.Sort(nums); // List nums2 = new List(); // for (int i = 0; i < nums.Length; i++) { // if (i >= 4 && nums[i] == nums[i-1] && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] && nums[i-3] == nums[i-4]) { // continue; // } // nums2.Add(nums[i]); // } // nums = nums2.ToArray(); var results = new List>(); var seen = new HashSet(); for (int i = 0; i < nums.Length - 3; i++) { for (int j = i + 1; j < nums.Length - 2; j++) { long num = (long)nums[i] + nums[j]; // if (num > target / 2) { // break; // } int left = j + 1; int right = nums.Length - 1; while (left < right) { long sum = (long)nums[left] + nums[right]; if (sum == target - num) { var quadruplet = new[] { nums[i], nums[j], nums[left], nums[right] }; string key = string.Join(",", quadruplet); if (!seen.Contains(key)) { results.Add(quadruplet); seen.Add(key); } left++; } else if (sum > target - num) { right--; } else { left++; } } } } return results; } } ``` ## Other languages ```java // Welcome to create a PR to complete the code of this language, thanks! ``` 亲爱的力扣人,为了您更好的刷题体验,请访问 [leetcoder.net](https://leetcoder.net/zh)。 本站敢称力扣题解最佳实践,终将省你大量刷题时间! 原文链接:[18. 四数之和 - 力扣题解最佳实践](https://leetcoder.net/zh/leetcode/18-4sum). GitHub 仓库: [f*ck-leetcode](https://github.com/fuck-leetcode/fuck-leetcode).