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的两个数字,但是这种思想只有在有序的情况下才能使用。

  • 相关阅读:
    hdu 5224 Tom and paper 水题
    2015 UESTC 搜索专题N题 韩爷的梦 hash
    2015 UESTC 搜索专题M题 Palindromic String 马拉车算法
    2015 UESTC 搜索专题K题 秋实大哥の恋爱物语 kmp
    2015 UESTC 搜索专题J题 全都是秋实大哥 kmp
    2015 UESTC 搜索专题F题 Eight Puzzle 爆搜
    2015 UESTC 搜索专题E题 吴队长征婚 爆搜
    2015 UESTC 搜索专题D题 基爷的中位数 二分
    2015 UESTC 搜索专题C题 基爷与加法等式 爆搜DFS
    2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
  • 原文地址:https://www.cnblogs.com/gzshan/p/11127130.html
Copyright © 2011-2022 走看看