力扣15.三数之和(java双指针解法)

题目描述:

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

力扣15.三数之和(java双指针解法)_第1张图片

解题思路:

我们将问题分解为两个待解决的问题:

1.如何实现不重复
2.如何更高效的实现输出和为0且不重复的三元组

1.如何实现不重复:

1.我们首先对数组进行一个排序,然后再实现三重循环。
2.在三重循环的大框架下,我们先利用第一层循环枚举a,在第二层循环中用来枚举b同时确保第二重循环枚举到的元素不小于当前第一层循环枚举的元素,同理第三层循环用来枚举c同时确保第三层循环枚举到的元素不小于第二层枚举到的元素

但我们应该注意:

**每一层循环中,相邻两次枚举的元素不能相同,否则也会造成重复!!!**例如:
[0, 1, 2 , 2, 2, 3]
当枚举出一个(0,1,2)后,第二层循环向后又会得到(0,1,2)
所以我们应该通过判断nums[i] 与 nums[i - 1]相等于否移动到于相邻元素第一个不相等的下标位置

如何更高效的实现输出和为0且不重复的三元组:

1.我们在实现第一层循环后立即选定当前的nums[first]的负数作为比较目标值(target)在开始第二层循环时我们定义third 指向数组的末尾,然后开始第三层循环运用双指针的思想保证second < third,对nums[second] + nums[third] 与target的大小进行比较,若nums[second] + nums[third] > target则表明third处的值大了,需要让已经排好序的数组中的third–
2.虽然我们是使用的三重循环的大框架,但是第二层和第三层时同时进行的,所以最后还是O(N^2)的复杂度

代码:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int length = nums.length;
        //对数组排序
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        //枚举a
        for (int first = 0; first < length; first++) {
            //first不能重复
            if (first > 0 && nums[first] == nums[first-1]) {
                continue;
            }
            //选定target
            int target = -nums[first];
            int third = length - 1;
            //枚举b
            for (int second = first + 1; second < length; second++) {
                //second不能重复
                if (second > first + 1 && nums[second] == nums[second-1]) {
                    continue;
                }
                while (second < third && nums[second] + nums[third] > target) {
                    third--;
                }
                //相等时退出
                if (second == third) {
                    break;
                }
                //添加合适元素
                if (nums[third] + nums[second] == target) {
                    List<Integer> temp = new ArrayList<>();
                    temp.add(nums[first]);
                    temp.add(nums[second]);
                    temp.add(nums[third]);
                    res.add(temp);
                }
            }
        }
        return res;
    }
}

注意事项:

对于以下两步我们应该注意:
1.

 	//first不能重复
 	if (first > 0 && nums[first] == nums[first-1]) {
 		continue;
 	}

我们之所以要在条件判断中加上first > 0就是防止索引越界

	//second不能重复
	if (second > first + 1 && nums[second] == nums[second-1]) {
	continue;
	}

我们先看一个例子,就可以明白为何在条件判断中加上second > first + 1

输入: [-1,0,1,2,-1,-4]
输出:[[-1,0,1]]
期望输出:[[-1,-1,2],[-1,0,1]]

过程:

1.排序后数组为[-4, -1, -1, 0, 1, 2]
2.若我们不加上second > first + 1,而是直接nums[second] == nums[second-1]的话就直接会跳过数组中第一个-1导致遗漏结果。

你可能感兴趣的:(力扣题目,leetcode,算法,数据结构)