三数之和Java实现(力扣15/1557)

力扣刷题小记

题目描述如下:

 

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

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

 

示例:

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

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

————————————————————————————————————————————————————————————————————————————————————————————————————————————————

思路描述:

核心计算 nums[i]+nums[j]+nums[k]=0 ?

暴力方法很容易想到,三重循环时间复杂度O(n^3),很明显提交后会超时。

不管用何种方法,我们必定先确定一个基准值,这里我们先确定nums[i] ,即把 i 作为外层循环的索引,只需要把 i 从0 遍历到 len-3。下面介绍一种头尾指针法,可以达到O(n^2)复杂度。这里必须先对原始数列进行排序,这也是能使用头尾指针进行移动的前提,如果不用头尾指针,那么必定根据双重循环对nums[j] 和 nums[k] 的值进行遍历,必定达到时间复杂度O(n^3)

下面画图帮助理解:

 

 

还有一个重点是去重问题,去除重复的结果序列,在下面的注释中给出了方法:要考虑去除重复的 j 和重复的 k

举例就是:原始数据 [ 0, 1, -2 ,1 ,-1 ]

                 排序后  [ -2, -1, 0, 1, 1]

取完 [ -1,0,1] 要避免再次取 [ -1, 0, 1]

代码及注释如下:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
         Arrays.sort(nums);//数组从小到大排序,快排
        int len=nums.length;
        List <List<Integer>> resL=new ArrayList<>();
        if(len<3||nums[0]>0||nums[len-1]<0)return resL;//长度不足或者最大值为负最小值为正返回空列表
        int i=0,j,k;
        for(;i<len-2;i++){//第一个基准值
            if(nums[i]>0)break;//基准值大于零,因为从小到大排序的,所以直接结束循环
            if(i>0&&nums[i-1]==nums[i])continue;//基准值重复,后面相同的的基准值不用判断
            j=i+1;//头指针
            k=len-1;//尾指针
            while(j<k){
                if(nums[i]+nums[j]+nums[k]==0){
                    List<Integer> tmpL=new ArrayList<>();//临时存储的列表
                    tmpL.add(nums[i]);
                    tmpL.add(nums[j]);
                    tmpL.add(nums[k]);                    
                    while(k-1>j&&nums[k]==nums[k-1])k--;//尾指针的值重复,后面相同的的尾指针值不用判断
                    resL.add(tmpL);
                    j++;//添加过后,头指针往里移
                    k--;//添加过后,尾指针往里移
                }else if(nums[i]+nums[j]+nums[k]<0){//和小于0,头指针往里移动
                    j++;
                }else{//和大于0,尾指针往里移动
                    k--;
                }
            }
        }
        return resL;
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值