algorithm-base/animation-simulation/求和问题/四数之和.md

152 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈
>
> 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。
>
> 另外希望手机阅读的同学可以来我的 <u>[**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)</u> 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击<u>[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)</u>进入。
#### [18. 四数之和](https://leetcode-cn.com/problems/4sum/)
## 题目描述
> 给定一个包含 n 个整数的数组 nums 和一个目标值 target判断 nums 中是否存在四个元素 abc 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
>
> 注意:
>
> 答案中不可以包含重复的四元组。
示例:
> 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
>
> 满足要求的四元组集合为:
> [
> [-1, 0, 0, 1],
> [-2, -1, 1, 2],
> [-2, 0, 0, 2]
> ]
我们已经完成了两数之和和三数之和,这个题目应该就手到擒来了,因为我们已经知道这类题目的解题框架,两数之和呢,我们就先固定第一个数 ,然后移动指针去找第二个符合的,三数之和,固定一个数,双指针去找符合情况的其他两位数,那么我们四数之和,也可以先固定两个数,然后利用双指针去找另外两位数。所以我们来搞定他吧。
### 多指针:
#### 解析:
三数之和是,我们首先确定一个数,然后利用双指针去找另外的两个数,我们在这个题目里面的解题思路是需要首先确定两个数然后利用双指针去找另外两个数,和三数之和思路基本一致很容易理解。我们具体思路可以参考下图。
这里需要注意的是,我们的 target 不再和三数之和一样为 0 target 是不固定的,所以解题思路不可以完全照搬上面的题目。另外这里也需要考虑去重的情况,思路和上题一致。
![四数之和起始](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/四数之和起始.2mi8qclt1h40.png)
上图则为我们查找到一个符合条件的四元组的情况,查找成功之后,下一步移动蓝色指针,重新定义绿蓝指针,继续执行上面步骤。
![四数之和例子](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/四数之和例子.3xy3mil2rp40.png)
动图解析:
![四数之和](https://cdn.jsdelivr.net/gh/tan45du/tan45du.github.io.photo@master/photo/四数之和.337d5ffc7040.gif)
#### 题目代码:
```java
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
if(nums.length < 4){
return new ArrayList<>();
}
Arrays.sort(nums);
List<List<Integer>> arr = new ArrayList<>();
for (int i = 0; i < nums.length-3; ++i) {
if (i > 0 && nums[i] == nums[i-1]) {
continue;
}
for (int j = i+1; j < nums.length-2; j++) {
if (j > i+1 && nums[j] == nums[j-1]) {
continue;
}
int l = j+1;
int r = nums.length-1;
while (l < r) {
int sum = nums[i] + nums[j] + nums[l] + nums[r];
if (sum == target) {
//存入
arr.add(new ArrayList<>
(Arrays.asList(nums[i], nums[j], nums[l], nums[r])));
//去重
while (l < r && nums[l] == nums[l+1]) {
l++;
}
while (l < r && nums[r] == nums[r-1]) {
r--;
}
l++;
r--;
}
else if (sum > target) {
r--;
}
else {
l++;
}
}
}
}
return arr;
}
}
```
Go Code:
```go
func fourSum(nums []int, target int) [][]int {
res := [][]int{}
length := len(nums)
if length < 4 {
return res
}
sort.Ints(nums)
for i := 0; i < length - 3; i++ {
// 去重
if i != 0 && nums[i] == nums[i - 1] {
continue
}
for j := i + 1; j < length - 2; j++ {
// 去重
if j != i + 1 && nums[j] == nums[j - 1] {
continue
}
l, r := j + 1, length - 1
for l < r {
/*
// 下面两个for循环的去重也可以用下面的代码替换
if l != i + 1 && nums[l] == nums[l - 1] {
l++
continue
}
*/
sum := nums[i] + nums[j] + nums[l] + nums[r]
if sum == target {
res = append(res, []int{nums[i], nums[j], nums[l], nums[r]})
for l < r && nums[l] == nums[l + 1] {
l++
}
for l < r && nums[r] == nums[r - 1] {
r--
}
l++
r--
} else if sum < target {
l++
} else {
r--
}
}
}
}
return res
}
```