zoukankan      html  css  js  c++  java
  • LeeCode数组第15题三数之和

    题目:三数之和

    内容

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

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

    例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
    
    满足要求的三元组集合为:
    [
      [-1, 0, 1],
      [-1, -1, 2]
    ]
    思路
    题目实现可分为两个步骤,分别是(1)寻找三个满足条件的元素(2)去重复
    对于第一个小问题,首先考虑三个for循环,直接寻找
    1.第一个数字(num1)选取范围1~n
    2.第二个数字(num2)选取范围num1+1~n
    3.第三个数字(num3)选取范围num2+1~n
    代码如下:
     1 //寻找三数之和为0的数 C++
     2             vector<int> vec(3);
     3             unsigned int num1 = 0, num2 = 0, num3 = 0;
     4             for (num1; num1 < nums.size() - 2; num1++){
     5                 for (num2 = num1 + 1; num2 < nums.size() - 1; num2++){
     6                     for (num3 = num2 + 1; num3 < nums.size(); num3++){
     7                         if (nums[num1] + nums[num2] + nums[num3] == 0){
     8                             vec[0] = nums[num1];
     9                             vec[1] = nums[num2];
    10                             vec[2] = nums[num3];
    11                             vecs.push_back(vec);
    12                         }
    13                     }
    14                 }
    15             }

    第二个小问题去重复

    C++ 的STL提供有去重算法unique,直接去重即可

    1.在寻找满足条件的三个数字之前要先排序,防止相同的vec因为内部元素顺序不同去不了重复,如[1,2,3]和[2,1,3]会判定为不重复

    2.对于vecs结果进行去重,去重之前一定要再次排序,因为unique函数只是比较相邻的两个元素是否重复,如果重复就将重复的放到尾部,如果不限排序,对于vecs[[1,2,3],[0,0,0],[1,2,3]],因为相邻的元素都不想等([1,2,3]≠[0,0,0]),系统会去重失败

    去重代码如下:

    1 //先排序,方便去重
    2             sort(nums.begin(), nums.end());
    3 //寻找三个满足条件的数字代码省略。。。。
    4 //去重
    5             sort(vecs.begin(), vecs.end());
    6             vecs.erase(unique(vecs.begin(), vecs.end()), vecs.end());
    7 
    8             return vecs;

    此外,还要考虑异常的情况,当传入的数组长度小于3时,无法给出满足条件的解,应返回空的容器

    完整代码如下:

     1 vector<vector<int>> threeSum(vector<int>& nums) {
     2             vector<vector<int>> vecs;
     3             //异常判断
     4             if (nums.size() < 3)
     5                 return vecs;
     6 
     7             //先排序,方便去重
     8             sort(nums.begin(), nums.end());
     9 
    10             //寻找三数之和为0的数
    11             vector<int> vec(3);
    12             unsigned int num1 = 0, num2 = 0, num3 = 0;
    13             for (num1; num1 < nums.size() - 2; num1++){
    14                 for (num2 = num1 + 1; num2 < nums.size() - 1; num2++){
    15                     for (num3 = num2 + 1; num3 < nums.size(); num3++){
    16                         if (nums[num1] + nums[num2] + nums[num3] == 0){
    17                             vec[0] = nums[num1];
    18                             vec[1] = nums[num2];
    19                             vec[2] = nums[num3];
    20                             vecs.push_back(vec);
    21                         }
    22                     }
    23                 }
    24             }
    25 
    26             //去重
    27             sort(vecs.begin(), vecs.end());
    28             vecs.erase(unique(vecs.begin(), vecs.end()), vecs.end());
    29 
    30             return vecs;
    31     }

    对于较短的输入,能给出合适的结果,然后对于巨长的数组,系统提示运算时间过长,因此需要优化代码。

    根据题目所给的条件,可以看出三个数字之和是定值,因此,当我们选取第一个数字num1后,问题变为寻找和为0-num1的两个数字。

    可以观察到,因为数组是有序的,我们可以设置两个指针从两边同时选取

     1 int targetSum = 0 - nums[num1];
     2             while (pLeft < pRight ){
     3                 int sum = nums[pLeft] + nums[pRight];
     4                 if (sum > targetSum || nums[pRight] == nums[pRight-1]){
     5                     pRight--;
     6                 }
     7                 else if (sum < targetSum || nums[pLeft] == nums[pLeft - 1]){
     8                     pLeft++;
     9                 }
    10                 else{
    11                     vec[0] = nums[num1];
    12                     vec[1] = nums[pLeft];
    13                     vec[2] = nums[pRight];
    14                     vecs.push_back(vec);
    15                     pLeft++;
    16                     pRight--;
    17                 }
    18             }

    也因为数组是排序的,为了如果我们选取的第一个数子大于0,则后两个必然大于0,可以跳出循环

    对于重复的数字,我们可以选择跳过

    完整代码如下:

     1 vector<vector<int>> threeSum(vector<int>& nums) {
     2         vector<vector<int>> vecs;
     3         //异常判断
     4         if (nums.size() < 3)
     5             return vecs;
     6 
     7         //先排序,方便去重
     8         sort(nums.begin(), nums.end());
     9         
    10         //寻找三数之和为0的数
    11         vector<int> vec(3);
    12         unsigned int num1 = 0, num2 = 0, num3 = 0;
    13         for (num1; num1 < nums.size() - 2; num1++){
    14             if (nums[num1] * 3 > 0)//数组是从小到大排序
    15                 break;
    16             if (num1 != 0 && nums[num1] == nums[num1 - 1])
    17                 continue;
    18 
    19             int pLeft, pRight;
    20             pLeft = num1+1;
    21             pRight = nums.size() - 1;
    22             
    23             int targetSum = 0 - nums[num1];
    24             while (pLeft < pRight ){
    25                 int sum = nums[pLeft] + nums[pRight];
    26                 if (sum > targetSum || nums[pRight] == nums[pRight-1]){
    27                     pRight--;
    28                 }
    29                 else if (sum < targetSum || nums[pLeft] == nums[pLeft - 1]){
    30                     pLeft++;
    31                 }
    32                 else{
    33                     vec[0] = nums[num1];
    34                     vec[1] = nums[pLeft];
    35                     vec[2] = nums[pRight];
    36                     vecs.push_back(vec);
    37                     pLeft++;
    38                     pRight--;
    39                 }
    40             }
    41         }
    42 
    43         //去重
    44         sort(vecs.begin(), vecs.end());
    45         vecs.erase(unique(vecs.begin(), vecs.end()), vecs.end());
    46 
    47 
    48         return vecs;
    49     }

    对于复杂测试案例的运行时间是60ms,通过题目!



  • 相关阅读:
    scikit-learn一般实例之四:使用管道和GridSearchCV选择降维
    scikit-learn一般实例之四:管道的使用:链接一个主成分分析和Logistic回归
    scikit-learn一般实例之三:连接多个特征提取方法
    scikit-learn一般实例之一:保序回归(Isotonic Regression)
    scikit-learn一般实例之一:绘制交叉验证预测
    weblogic控制台定制不同权限的用户
    jquery给input域赋值和取值
    键盘对应的ASCII码
    js控制键盘只能输入数字和退格键,delete键
    mysql创建用户及授权相关命令
  • 原文地址:https://www.cnblogs.com/feichangnice/p/9025491.html
Copyright © 2011-2022 走看看