四数之和一
给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
示例 1:
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
示例 2:
输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出:1
提示:
n == nums1.length
n == nums2.length
n == nums3.length
n == nums4.length
1 <= n <= 200
-228 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 228
思路一
这道题比较简单,我们直接分别遍历两个数组,使用map来存储两个数组元素和的出现次数(因为题目要求我们返回次数),然后遍历剩下两个数组,如果和等于0-nums1[a]-nums2[b],那么说明找到了一组合适的解,我们这种两两划分的思想和两数之和的解法基本上都是一样的,比较简单,下面直接贴出代码.
代码一
#include<vector>
#include<unordered_map>
using namespace std;
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> umap;
int count = 0;
int res = 0;
for (auto& a : nums1) {
for (auto& b : nums2) {
count = a + b;
umap[count]++;
}
}
for (auto& c : nums3) {
for (auto& d : nums4) {
if (umap.find(0 - c - d) != umap.end()) {
res += umap[0 - c - d];
}
}
}
return res;
}
};
题目二
给你一个由 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
-109 <= nums[i] <= 109
-109 <= target <= 109
思路二
排序,方便后续操作的去重!!! 总的来说就是设置两个指针遍历整个数组,第三个指针指向第二个指针的下一个,第四个指针指向末尾,判断四个指针的和是否等于sum,如果小于sum ,那么说明第三个指针指向的数小了,应该将第三个指针向后移动,同理如果sum>target,那么第四个指针应该向后回退.
细节!!!
这道题思路真就是不难,但是实现细节贼多....下面我就将自己想到的细节和遇到的困难一一列举:
1)细节一:数据大小,如果我们设置四个数和的数据类型是int的话,是会stackoverflow的,因为int只能存储两亿多,但是这道题有一个测试数据集和为四亿,所以我们应该设置两个temp分别保存和,判断时判断temp1?=target - temp2
困难--去重
这道题最值得提的就是如何去重--下面我们分别来看一下四个指针的去重方法.
1)第一去重:我们去重到底是和后面的元素比还是和前面的元素比呢?答案:都可以,但是一般都是和前面的比较,我这里其实也不是特别想得通为何是和前面的比较,欢迎大家讨论!但是既然是和前面的比较那么第一个一定是满足条件不能被continue的!
2)第二去重:同上,第一次指向是一定不能被continue的!
3)第三去重:我们此时第一指针和第二指针都是固定的,那么如果sum相等了,应该向后移动,那么判断时应该和nums[k+1]进行比较,直到不相等为止
4)第四去重:同上,因为要向前移动,判断前一个是否是一样的元素,直到不相等为止.
(补充)第三第四去重有一个细节---就是我们在res.push_back()之后去重相同的元素,但是第三第四指针最终还是会停留在同样的元素的位置,所以我们在push+while去重操作之后需要对第三第四指针分别进行++,--操作.
代码
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int size = nums.size();
if (size < 4) return {};
vector<vector<int>> res;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); ++i) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
for (int j = i + 1; j < nums.size(); ++j) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
int temp1 = nums[i] + nums[j];
int m = j + 1, n = size - 1;
while (m < n) {
int temp2 = nums[m] + nums[n];
if (temp2 == target - temp1) {
res.push_back({ nums[i],nums[j],nums[m],nums[n] });
while (m < n && nums[m] == nums[m + 1]) ++m;
while (m < n && nums[n] == nums[n - 1]) --n;
++m;
--n;
}
else if ( temp2 > target-temp1) --n;
else if ( temp2 < target-temp1) ++m;
}
}
}
return res;
}
};
//int main() {
// vector<int> vec({ -2,-1,0,0,1,2});
// Solution s;
// s.fourSum(vec,0);
// return 0;
//}