目录
题目来源
题目描述
示例
提示
题目解析
算法源码
题目来源
18. 四数之和 - 力扣(LeetCode)
题目描述
给你一个由 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
题目解析
本题是LeetCode - 15 三数之和_伏城之外的博客-CSDN博客的拓展题。
本题是需要找出所有和为target的四元组,且四元组不能重复。看本题前,建议先将前面链接的三数之和看明白。
四数之和,相当于比三数之和多了一个数。
前面求解三数之和时,我们是固定三元组中的最小值,然后通过双指针来找匹配该最小值的其他两个数。
而四数之和的解法,和三数之和类似,只是四数之和,我们需要固定四元组中最小的两个值,然后通过双指针来找匹配这两个最小值得其他两个数。
大家和对比下面四数之和,和前面三数之和得代码,其实就是多了套了一层for循环。
本题的去重逻辑也和三数之和一样。
具体解析可以看前面链接博客。
关于本题的剪枝优化:
三数之和那题的target=0,而本题四数之和的target为一个任意值,可正,可负,可0。
前面三数之和的剪枝优化,是三元组的最小值nums[i] > 0时,则此时三元组之和必然也是>0,且后续的nums[i+1]对应的三元组之和也肯定大于0,因此当nums[i] > 0时,可以直接break掉三指针运动,达到剪枝优化效果。
但是本题四数之和,我们不能说
四元组的最小值nums[i] > target,那么此时的四元组之和也是>target
比如nums = [-4, -3, -2, -1],target = -10
四元组[-4,-3,-2,-1]中nums[i] > target的,但是此时我们不能直接break掉四指针运动,因为后续的nums[j],nums[l],nums[r]也可能是负数,即nums[i] 加上后续三个数,不一定使得i,j,l,r四元组之和变大,因此nums[i] > target,但是四元组之和也有可能 == target。
本题的剪枝优化其实也可以做,但是又局限性,即只有nums[i] > 0,即i,j,l,r指向数都是正数时,此时num[i] > target可以进行剪枝优化。
同理如果nums[j] > 0 && nums[i] + nums[j] > target,也一样可以剪枝。
JS算法源码
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function (nums, target) {
const ans = [];
nums.sort((a, b) => a - b);
for (let i = 0; i < nums.length; i++) {
// 去重
if (i > 0 && nums[i] == nums[i - 1]) continue;
for (let j = i + 1; j < nums.length; j++) {
// 去重
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
let l = j + 1;
let r = nums.length - 1;
while (l < r) {
const sum = nums[i] + nums[j] + nums[l] + nums[r];
if (sum > target) {
r--;
} else if (sum < target) {
l++;
} else {
ans.push([nums[i], nums[j], nums[l], nums[r]]);
// 去重
while (l + 1 < r && nums[l] == nums[l + 1]) l++;
// 去重
while (r - 1 > l && nums[r] == nums[r - 1]) r--;
l++;
r--;
}
}
}
}
return ans;
};
四数之和 - 提交记录 - 力扣(LeetCode)
Java算法源码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> ans = new ArrayList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
// 剪枝
if (nums[i] > 0 && nums[i] > target) break;
// 去重
if (i > 0 && nums[i] == nums[i - 1]) continue;
for (int j = i + 1; j < nums.length; j++) {
// 剪枝
if (nums[j] > 0 && nums[i] + nums[j] > target) break;
// 去重
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
int l = j + 1;
int r = nums.length - 1;
while (l < r) {
long sum = (long) nums[i] + nums[j] + nums[l] + nums[r];
if (sum > target) {
r--;
} else if (sum < target) {
l++;
} else {
ArrayList<Integer> tmp = new ArrayList<>();
Collections.addAll(tmp, nums[i], nums[j], nums[l], nums[r]);
ans.add(tmp);
// 去重
while (l + 1 < r && nums[l] == nums[l + 1]) l++;
// 去重
while (r - 1 > l && nums[r] == nums[r - 1]) r--;
l++;
r--;
}
}
}
}
return ans;
}
}
四数之和 - 提交记录 - 力扣(LeetCode)
Python算法源码
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
ans = []
nums.sort()
for i in range(len(nums)):
# 剪枝
if nums[i] > 0 and nums[i] > target:
break
# 去重
if i > 0 and nums[i] == nums[i - 1]:
continue
for j in range(i + 1, len(nums)):
# 剪枝
if nums[j] > 0 and nums[i] + nums[j] > target:
break
# 去重
if j > i + 1 and nums[j] == nums[j - 1]:
continue
l = j + 1
r = len(nums) - 1
while l < r:
total = nums[i] + nums[j] + nums[l] + nums[r]
if total > target:
r -= 1
elif total < target:
l += 1
else:
ans.append([nums[i], nums[j], nums[l], nums[r]])
# 去重
while l + 1 < r and nums[l] == nums[l + 1]:
l += 1
# 去重
while r - 1 > l and nums[r] == nums[r - 1]:
r -= 1
l += 1
r -= 1
return ans
四数之和 - 提交记录 - 力扣(LeetCode)