当前位置:   article > 正文

OJ-leetcode-15. 三数之和(中等双指针)_oj 数组a b相加n2个数

oj 数组a b相加n2个数

目录

题目

思路

代码

结果

优秀题解

提升笔记

全部代码


题目

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]
链接:https://leetcode-cn.com/problems/3sum

思路

看示例可以看出,排序后比较合适。可以方便剪枝和去重。我们先排序,然后固定第一个数num[i],遍历一遍即可。

然后定义两个指针(下标),从i后面一个left=i+1向右,从最后一个right=len-1向左进行逼近。

left<right,若三数之和sums<0,那么向右移动left使三数之和增大,若sums>0,向左移动right使sums减小。相等时保存结果。

left>=right,继续下一个num[i]。

剪枝:由于nums[i]<nums[left]<nums[right],如果nums[i]>0,那么两个指针怎么移动也不可能找到了。

           我就写了上面的一个剪枝,当然如果nums[i]+nums[left]>0,right怎么移动也不可能找到了。

去重:由于已经排好序,若某个数字移动时相同就是重复三元组。例如,-4 -1 -1 0 1 2 ,三个标红的和为0,若移动第一个数一次,那么后序两个指针也会移动到0 1,-4 -1 -1 0 1 2,这样的三元组便是重复的,所以去重就是若相等继续后移。

代码

  1. // 双指针法
  2. class Solution {
  3. public:
  4. vector<vector<int>> three(vector<int>& nums,int target) {
  5. vector<vector<int>> ans;
  6. int len = nums.size();
  7. if (len < 3)return ans;
  8. sort(nums.begin(),nums.end());
  9. for (int i=0;i<len;++i)
  10. {
  11. if (nums[i] > target) break; // 剪枝:若第一个最小的数都大于target,就没必要从后面逼近选了
  12. if (i > 0 && nums[i] == nums[i - 1])continue; //去重
  13. int left = i + 1; //左指针
  14. int right = len - 1;//右指针
  15. //左右逼近
  16. while (left<right)
  17. {
  18. int sums = nums[i] + nums[left] + nums[right];
  19. //cout<< nums[i] <<" "<<nums[left]<<" "<<nums[right]<<" "<<sums<<endl;
  20. //cout << left << " " << right << endl;
  21. if (sums == target)
  22. {
  23. vector<int> res;
  24. res.emplace_back(nums[i]);
  25. res.emplace_back(nums[left]);
  26. res.emplace_back(nums[right]);
  27. ans.emplace_back(res);
  28. while (left < right&&nums[left] == nums[left+1])++left;//去重右移
  29. ++left;
  30. while (left < right&&nums[right] == nums[right-1])--right;//去重左移
  31. --right;
  32. }
  33. else if (sums < target)++left;
  34. else --right;
  35. }
  36. }
  37. return ans;
  38. }
  39. vector<vector<int>> threeSum(vector<int>& nums) {
  40. return three(nums, 0);
  41. }
  42. };

结果

结果

优秀题解

大力王-简洁代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int N = nums.size();
        vector<vector<int> > res;
        for (int i = 0; i < N - 2; ++i) {
            if (nums[i] > 0) break;
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            int l = i + 1;
            int r = N - 1;
            while (l < r) {
                int s = nums[i] + nums[l] + nums[r];
                if (s > 0) {
                    --r;
                } else if (s < 0) {
                    ++l;
                } else {
                    res.push_back({nums[i], nums[l], nums[r]});
                    while (l < r && nums[l] == nums[++l]);
                    while (l < r && nums[r] == nums[--r]);
                }
            }
        }
        return res;
    }
};

99.97%,可能不太准,但人家代码确实写得更简洁,值得学习。

提升笔记

1.push_back({nums[i], nums[l], nums[r]}),对于小的vector放入大的vector没必要再定义一个了,直接这样花括号。

2.nums[l] == nums[++l],先+1再比较,可以使代码更简洁。

全部代码

  1. //https://leetcode-cn.com/problems/3sum/
  2. /*
  3. Project:15. 三数之和
  4. Date: 2020/09/
  5. Author: Frank Yu
  6. 不重复指的是元组间不重复,不是元组内的数字不可重复
  7. */
  8. #include<vector>
  9. #include<algorithm>
  10. #include<iostream>
  11. using namespace std;
  12. void check(vector<vector<int>> ans)
  13. {
  14. cout << "元组为" << endl;
  15. for (auto nums:ans)
  16. {
  17. for (auto num : nums)
  18. {
  19. cout << num << " ";
  20. }
  21. cout << endl;
  22. }
  23. }
  24. // 双指针法
  25. class Solution {
  26. public:
  27. vector<vector<int>> three(vector<int>& nums,int target) {
  28. vector<vector<int>> ans;
  29. int len = nums.size();
  30. if (len < 3)return ans;
  31. sort(nums.begin(),nums.end());
  32. for (int i=0;i<len;++i)
  33. {
  34. if (nums[i] > target) break; // 剪枝:若第一个最小的数都大于target,就没必要从后面逼近选了
  35. if (i > 0 && nums[i] == nums[i - 1])continue; //去重
  36. int left = i + 1; //左指针
  37. int right = len - 1;//右指针
  38. //左右逼近
  39. while (left<right)
  40. {
  41. int sums = nums[i] + nums[left] + nums[right];
  42. cout<< nums[i] <<" "<<nums[left]<<" "<<nums[right]<<" "<<sums<<endl;
  43. //cout << left << " " << right << endl;
  44. if (sums == target)
  45. {
  46. vector<int> res;
  47. res.emplace_back(nums[i]);
  48. res.emplace_back(nums[left]);
  49. res.emplace_back(nums[right]);
  50. ans.emplace_back(res);
  51. while (left < right&&nums[left] == nums[left+1])++left;//去重右移
  52. ++left;
  53. while (left < right&&nums[right] == nums[right-1])--right;//去重左移
  54. --right;
  55. }
  56. else if (sums < target)++left;
  57. else --right;
  58. }
  59. }
  60. return ans;
  61. }
  62. vector<vector<int>> threeSum(vector<int>& nums) {
  63. return three(nums, 0);
  64. }
  65. };
  66. //主函数
  67. int main()
  68. {
  69. vector<int> nums{ -1, 0, 1, 2, -1, -4 };
  70. //vector<int> nums{ 0, 0, 0, 0, 0, 0 };
  71. //vector<int> nums{1,0};
  72. Solution s;
  73. check(s.threeSum(nums));
  74. return 0;
  75. }

更多内容:OJ网站题目分类,分难度整理笔记(leetcode、牛客网)

喜欢本文的请动动小手点个赞,收藏一下,有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/366059
推荐阅读
相关标签
  

闽ICP备14008679号