day7 三数之和 | 四树之和
三数之和
区别于两数之和,这题使用哈希表就比较麻烦了,如果要使用哈希得存一个pair对吧,因为这个时候是三元了。
如何找到三元组呢?先固定一个,剩下变成了两数之和了,问题转化为,确定一个数字,在后面的区间寻找两个数字之和等于这个数字的相反数。
我们可以使用先排序后用双指针的方法去寻找这两个数字
另一个难点是去重,因为我们要找到是三元组i, j, k 也就是要保证i, j, k是不重复的
- 第一个方面是针对原数组,也就是i,碰到相同的元素就跳过;
- 第二个方面是针对j的如果nums[j]==nums[j+1]就跳过
- 第三个方面是针对k的如果nums[k]==nums[k-1]就跳过
- 一个剪枝,如果第一个指针指向的数字已经大于零了,则说明它后面的元素都是大于零的,不可能相加还等于0,提前break
if(nums[i] > 0 break;
while(l < r && nums[l] == nums[l + 1]) l++;
while(l < r && nums[r] == nums[r - 1]) r--;
注意这个时候跳出循环是nums[l]!=nums[l+1] 这个时候在nums[l]==nums[l-1],也就是我们加入{l,r}的那个l,下一轮查找我们要排除这个l, r所以两个while去重之后我们还要继续调整一下指针,l++, r--,这里是为了区别于上一次我们已经加入的点集
完整代码+注释
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
int n = nums.size();
for(int i = 0; i < n; ++i) {
if(i > 0 && nums[i] == nums[i - 1]) continue;
if(nums[i] > 0) break;
int l = i + 1, r = n - 1;
int ta = -nums[i];
while(l < r) {
// [l, r)
// find nums[l]+nums[r] == -nums[i]
int sum = nums[l] + nums[r];
if(sum > ta) {
r--;
}
else if(sum < ta) {
l++;
}
else {
// erase repeated element
ans.push_back({nums[i], nums[l], nums[r]});
while(l < r && nums[l] == nums[l + 1]) l++;
while(l < r && nums[r] == nums[r - 1]) r--;
l++, r--; // skip the tuple that we already used
}
}
}
return ans;
}
};
可以看到剪枝的效果还是不错的
四数之和
思路上依然是先排序,但是剪枝操作需要调整。
先固定两个数字,然后使用双指针去寻找下面的两个数字:
class Solution {
public:
typedef long L;
vector<vector<int>> fourSum(vector<int>& nums, int target) {
if(nums.size() < 4) {
return {};
}
sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> ans;
for(int a = 0; a < n;++a) {
if(nums[a] > target && target > 0) {
break; // if nums[a] > taget > 0 then nums[b] ... > taget > 0
}
if(a > 0 && nums[a] == nums[a - 1]) {
continue; // erase reduplicate nums[a]
}
for(int b = a + 1; b < n; ++b) {
if(nums[a] + nums[b] > target && target > 0) {
break; // nums[a]+nums[b]>target>0 then all nums that behind nums[b] is bigger than target
}
if(b > a + 1 && nums[b] == nums[b - 1]) continue;
int left = b + 1, right = n - 1;
L ta = (L)target - nums[a] - nums[b];
while(left < right) {
auto sum = L(nums[left])+L(nums[right]);
if(sum == ta) {
ans.push_back({nums[left], nums[right], nums[a], nums[b]});
// erase duplicate element
while(left < right && nums[left] == nums[left + 1]) left++;
while(left < right && nums[right] == nums[right - 1]) right--;
left++, right--;
}
else if(sum > ta) {
right--;
}
else {
left++;
}
}
}
}
return ans;
}
};

浙公网安备 33010602011771号