目录
前言:
15. 三数之和 - 力扣(LeetCode)
18. 四数之和 - 力扣(LeetCode)
结束:
前言:
今天两道题类型相似,解法思路一致,都利用了双指针技术。
15. 三数之和 - 力扣(LeetCode)
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
解法1:哈希表法:
我们仍然可以建立一个map表来存储a+b的值以及a和b的值,再次遍历整个数组,如果利用find函数能找到一个c等于(-(a+b)),那么我们就往数组中存储这三个数字,但是这种方法对于去重来讲太过于复杂因此我们不推荐使用这种方法。
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> result;sort(nums.begin(), nums.end());// 找出a + b + c = 0// a = nums[i], b = nums[j], c = -(a + b)for (int i = 0; i < nums.size(); i++) {// 排序之后如果第一个元素已经大于零,那么不可能凑成三元组if (nums[i] > 0) {break;}if (i > 0 && nums[i] == nums[i - 1]) { //三元组元素a去重continue;}unordered_set<int> set;for (int j = i + 1; j < nums.size(); j++) {if (j > i + 2&& nums[j] == nums[j-1]&& nums[j-1] == nums[j-2]) { // 三元组元素b去重continue;}int c = 0 - (nums[i] + nums[j]);if (set.find(c) != set.end()) {result.push_back({nums[i], nums[j], c});set.erase(c);// 三元组元素c去重} else {set.insert(nums[j]);}}}return result;}
};
解法2:双指针法
我们可以先对数组进行排序,然后以此遍历这个数组,每一次遍历的时候建立两个指针:left指针和right指针,left指针指向遍历数组的后一位元素,right指针指向末尾元素:
此时我们固定住遍历指针,对left指针和right指针进行以下操作:
1.计算nums[遍历指针]+nums[left]+nums[right]的和。
2.如果三者的和大于零,因为已经进行了排序,我们就移动right指针,使和减小。
3.如果三者的和小于零,就移动left指针,使和增大。
如此操作之下,我们最终无非得到两个结果
1.得到了两个left和right指针指向的值使得其加上遍历指针指向的值为0,则为我们要寻找的答案。
2.无法找到left和right指针能使其值加上遍历指针指向值后的结果为0,则该值没有答案。
去重操作:
因为我们在之前已经进行过排序,因此重复的数字一定是在一起的。如果遇到了重复的数字,我们就让指针向后指,直到指针指向的值与指针+1指向的值不相等(因为相同的数字会放在一起,所以如果nums[i]!=nums[i+1],那么nums[i]在数组中肯定没有重复元素)。
对遍历指针去重:
if (i > 0 && nums[i] == nums[i - 1]){continue;}
对left和right指针去重:
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
完整代码:
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> result;sort(nums.begin(),nums.end());for(int i=0;i<nums.size();i++){if(nums[i]>0){return result;}int left=i+1;int right=nums.size()-1;int sums=0;if (i > 0 && nums[i] == nums[i - 1]){continue;}while(left<right){if(nums[i]+nums[left]+nums[right]>0){right--;}else if(nums[i]+nums[left]+nums[right]<0){left++;}else if(nums[i]+nums[left]+nums[right]==0){result.push_back(vector<int>{nums[i], nums[left], nums[right]});while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;right--;left++;}}}return result;}
};
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
你可以按 任意顺序 返回答案 。
双指针解法:
与上一题思路解法一致,只不过又多了一个外层循环,也就是说我们这次要固定两个遍历指针
class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {sort(nums.begin(),nums.end());vector<vector<int>> result;for(int k=0;k<nums.size();k++){ if(nums[k]>target && nums[k]>0&&target>0){continue;} if (k > 0 && nums[k] == nums[k - 1]){continue;}for(int i=k+1;i<nums.size();i++){if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {break;}// 对nums[i]去重if (i > k + 1 && nums[i] == nums[i - 1]) {continue;}int left=i+1;int right=nums.size()-1;int sums=0;while(left<right){if((long)nums[k]+nums[i]+nums[left]+nums[right]>target){right--;}else if((long)nums[k]+nums[i]+nums[left]+nums[right]<target){left++;}else if((long)nums[k]+nums[i]+nums[left]+nums[right]==target){result.push_back(vector<int{nums[i],nums[left],nums[right],nums[k]);while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;right--;left++;}}}}return result;}
};
结束:
今天的内容到这里就结束了,感谢大家的阅读。
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!