【LeetCode-Java实现】15. 3Sum

题目描述

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.

给一个整数数组,找出其中三个元素组成三元组,使得三个元素之和为0
找出所有符合条件的三元组,且不可以重复
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]

思路

对比第一题Two Sum的思路:先假定已经确定了其中一个数,再去寻找另一个数
本题也可以借鉴一点这个思想:先将数组从小到大排序,
假定一个基数base作为第一个元素,再在剩下的数组元素中通过双指针找到符合条件的另外两个元素,
以这个基数为第一个元素的情况都找出来后,再移动base指针,继续上述步骤,知道找到所有可能的三元组
注意:

  1. base指针的范围是[0 , nums.lengh-2)
  2. 双指针指的是:左指针初始是base的下一个元素,右指针初始是数组最后一个元素。
    左右指针根据对三元素之和与0的关系的判断,决定如何移动:
    (1)三元素和等于0:则左右指针都可以移动一步(左指针向右移动,右指针向左移动)
    (2)三要素和大于0:需要把和调小点,所以只移动右指针
    (3)三要素和小于0:需要把和调大点,所以只移动左指针
    该base的所有情况都找完后,向右移动base,继续上述操作
  3. 双指针和base移动时都要注意排除重复情况,即如果移动一步后和上一步的元素值相同,要接着移动!!!

实现

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //res用来存放最终三元组列表
        ArrayList<List<Integer>> res=new ArrayList<List<Integer>>();
        //边界情况,直接返回空列表
        if(nums.length<=2 || nums==null) return res;
        
        //先将数组排序(小到大)
        Arrays.sort(nums);
        
        int i=0;
        while(i<nums.length-2){
            int base=nums[i];         //base基数
            int left=i+1;             //基数之后的第一个,左指针
            int right=nums.length-1;  //数组最后一个,右指针
            
            while(left<right){
                int sum=base+nums[left]+nums[right];
                
                //若sum正好等于0,符合条件,把三个元素插入三元组,再插入到结果列表。再移动指针查找下一个三元组
                if(sum==0){
                    //存放三元组的列表
                    LinkedList<Integer> list=new LinkedList<Integer>();
                    list.add(base);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    res.add(list);
                    //移动指针,查找下一个符合条件的三元组
                    left=moveRight(nums,left+1);
                    right=moveLeft(nums,right-1);
                }
                //若sum大于0,需要调小,右指针向左移动
                else if(sum>0){
                    right=moveLeft(nums,right-1);
                }
                //若sum小于0,需要调大,左指针向右移动
                else{
                    left=moveRight(nums,left+1);
                }
        }
        //找完一个基数,换下一个,向后移动基数指针
        i=moveRight(nums,i+1);
    }
    return res;
}
    
    //指针右移函数
    public int moveRight(int[] nums,int left){
        while(left==0 || (left<nums.length && nums[left]==nums[left-1])){
            left++;
        }
        return left;
    }
    //指针左移函数
    public int moveLeft(int[] nums,int right){
        while(right==nums.length-1 || (right>=0 && nums[right]==nums[right+1])){
            right--;
        }
        return right;
    }
}

提交结果:
Time Submitted Status Runtime Memory Language
2 minutes ago Accepted 48 ms 46.6 MB java
时间复杂度O(n^2),好像有点慢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值