leetcode15:三数之和

46 阅读2分钟

在数组有序的情况下,参考两数之和,使用双指针找到三元组。 对我来说,难点在于如何去重

详细解释:

由于输入数组可能包含重复元素,直接遍历可能会得到重复的答案。例如,数组 [0,0,0,0],如果不去重,可能会得到多个 [0,0,0]

去重主要分为三处:第一层循环(第一个数),第二层循环(第二个数),第三层循环(第三个数)。具体如下:

  1. 第一个数的去重(外层循环)

    if (i > 0 && nums[i] == nums[i - 1]) continue;
    
    • 目的:跳过当前数与前一个数相同的情况,避免以同样的数为起点重复计算。
    • 原理:排序后,相同的数会相邻。如果前一个数已经作为第一个数处理过,当前数就不需要再处理。

  1. 第二、第三个数的去重(双指针部分)

    当找到一个三元组后,需要跳过后续可能重复的元素:

    while (left < right && nums[left] == nums[left + 1]) left++;
    while (left < right && nums[right] == nums[right - 1]) right--;
    
    • 目的:跳过和当前 left 或 right 指针所指元素相同的后续元素。
    • 原理:如果当前 left 或 right 与下一个元素相同,说明下一个三元组会和当前三元组重复,因此需要直接跳过。

    完整流程:

    • 找到一个三元组后,先移动 left 和 right 跳过重复元素,然后再移动到下一个不同的元素,继续查找。

整体代码java版:

    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);//排序,方便后续判断指针位置
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        for(int i =0;i<nums.length;i++){
            int target = -nums[i];//三数之和,先标记target,从而拆分为两数之和
            int left = i+1,right = nums.length-1;
            if(i>0&&nums[i]==nums[i-1]){//第一个数去重
                continue;
            }
            while(left<right){
                List<Integer> list1 = new ArrayList<Integer>();
                if(nums[left]+nums[right]==target){
                    list1.add(nums[i]);
                    list1.add(nums[left]);
                    list1.add(nums[right]);
                    list.add(list1);
                    //双指针部分去重
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    left++;
                    right--;
                }else if(nums[left]+nums[right]>target){
                    right--;
                }else{
                    left++;
                }
            }
        }

        return list;
        
    }
}