zoukankan      html  css  js  c++  java
  • 【LeetCode】15、三数之和为0

    题目等级:3Sum(Medium)

    题目描述:

    Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

    Note:

    The solution set must not contain duplicate triplets.

    Example:

    Given array nums = [-1, 0, 1, 2, -1, -4],
    
    A solution set is:
    [
      [-1, 0, 1],
      [-1, -1, 2]
    ]
    

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


    解题思路:

      看到这个题目,我们首先会联想到LeetCode的第一个题:两数之和:【LeetCode】1、Two Sum

      两数之和比较简单,解法是利用了HashMap的查找优势,空间换时间将时间复杂度降到了O(n),这里是三数之和,当然可以类比,我们很容易想到可以先固定一个元素a,由于a+b+c=0,那么b+c=-a,所以就可以将三数之和转化为两数之和的问题

      而两数之和的问题我们已经解决,这样就得到本题的解答,然而,在实现这种思路的过程中,发现一个稍微有些棘手的问题是如何去重复,另外这样做的时间复杂度当然为O(n^2),额外空间复杂度是O(n)。

      然后又在网上参考了一些其他人的解法,发现HashMap似乎并不是最好的解法,所以找到了另外一种解法。

      思路如下:同样是先固定一个元素a,找b+c=-a,而最优美的地方就在于如何找着另外两个数b和c,这里不用HashMap,而是先将整个数组进行排序(排序时间复杂度O(nlogn)),然后可以利用前后双指针解法去找这两个元素。

      这样做的好处有两个:一是不需要额外的空间,二是由于已经有序,去重简单。

      代码实现的过程中,重点还是要关注一下如何去掉重复的情况,具体看代码。

    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> res=new ArrayList<>();
            if(nums==null||nums.length==0)
                return res;
            int len=nums.length;
            Arrays.sort(nums);  //第一步:先排序
            
            for(int i=0;i<len-2;i++){ //依次遍历每一个元素,把它作为a,在后续的元素里找b+c=-a;
                if(i>0 && nums[i]==nums[i-1])
                    continue;     //重复元素直接跳过
                //找两数之和为-a,双指针法
                int low=i+1,high=len-1;
                while(low<high){
                    if(nums[low]+nums[high]==-nums[i]){ //找到了一个解
                        res.add(Arrays.asList(nums[i],nums[low],nums[high]));
                        //已经找到了,重复的去掉
                        while(low<high && nums[low+1]==nums[low])
                            low++;
                        while(low<high && nums[high-1]==nums[high])
                            high--;
                        low++;
                        high--;
                    }else if(nums[low]+nums[high]<-nums[i])
                        low++;
                    else
                        high--;
                }
            } 
            return res;
        }
    }
    

      时间复杂度:O(n^2),没有使用额外空间

    总结

      总结来说,本题的一个巧妙之处就是前后向两个指针同时遍历,实际上回顾一下,可以发现这种思想之前已经用过了:在《剑指Offer》第42题找和为S的两个数字使用的正是这样的解法:【剑指Offer】42、和为S的两个数字,但是这种思想只有在有序的情况下才能使用。

  • 相关阅读:
    Sql中CHARINDEX用法
    当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式
    Windows Server 2012 R2安装.NET4.7.2服务问题集合
    详细实例全面解析SQL存储过程
    MySQL 存储过程
    华为远程登陆配置
    数据平台环境部署(mysql、docker、nginx)
    ISIS的路由渗透
    华为模拟器的安装失败(出现40、41、42代码错误,Oracle VM VirtualBox安装出现严重错误以及一直处于开机状态)
    华为模拟器配置动态ospf--虚拟链路、rip重分布、static重分布
  • 原文地址:https://www.cnblogs.com/gzshan/p/11127130.html
Copyright © 2011-2022 走看看