双指针之三数求和

165 阅读2分钟

这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

前言

  • 为了准备的目标,现在还是要多刷刷LeetCode滴 !-_-!
  • 这次看了LeetCode上一道 三数之和 算法题,题如下:
15. 三数之和
给你一个包含 n 个整数的数组nums,判断nums中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:
输入:nums = []
输出:[]

示例 3:
输入:nums = [0]
输出:[]

解题

  • 根据题干和示例知道,这是一个无序且元素存在重复的整数数组.
  • 三个数相加等于0,那必然其中有数字小于等于0才可满足,所以依次遍历数组时,可以将其作为判断跳出条件.
  • 算法基本实现流程大致如下:
    • 先判断特殊场景,例如元素个数不足三个,或者满足三个元素但累加不为0.
    • 然后把数组进行排序操作,并依次遍历数组.
    • 当前节点右边剩余元素的左右节点,并依次累加判断.
    • 移动左右节点位置,遇到相同元素就跳过。
  • 最后编码如下:
/**
 * 三数之和
 * 给你一个包含 n 个整数的数组nums,判断nums中是否存在三个元素 a,b,c ,使得a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
 * 注意:答案中不可以包含重复的三元组。
 *
 * @Author: ZRH
 * @Date: 2022/2/9 10:23
 */
public class Num15 {


    public static void main (String[] args) {

        System.out.println(JSON.toJSONString(threeSum(new int[]{-2, -1, 0, 1, 2})));
        System.out.println(JSON.toJSONString(threeSum(new int[]{-1, 0, 1, 2, -1, -4})));
        System.out.println(JSON.toJSONString(threeSum(new int[]{-2, 0, 0, 2, 2})));
        System.out.println(JSON.toJSONString(threeSum(new int[]{0, 0, 0})));
    }

    public static List<List<Integer>> threeSum (int[] nums) {
        int length = nums.length;
        List<List<Integer>> result = new ArrayList<>();
        // 特殊情况判断
        if (length < 3 || (length == 3 && nums[0] + nums[1] + nums[2] != 0)) {
            return result;
        }
        // 排序
        Arrays.sort(nums);
        // 排序后数组最小值都大于0,就直接返回
        if (nums[0] > 0) {
            return result;
        }

        // 遍历所有节点
        for (int i = 0; i < length; i++) {
            if (nums[i] > 0) {
                return result;
            }
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            // 当前节点后面的两个左右节点
            int l = i + 1, r = length - 1;
            while (l < r) {
                int val = nums[i] + nums[l] + nums[r];
                if (val == 0) {
                    // 保存符合条件的元素
                    result.add(Arrays.asList(nums[i], nums[l], nums[r]));
                    // 依次右节点往左移动,左节点往右移动
                    r--;
                    l++;
                    // 如果移动后节点值相同,则再次移动
                    while (l < r && nums[r] == nums[r + 1]) {
                        r--;
                    }
                    while (l < r && nums[l] == nums[l - 1]) {
                        l++;
                    }
                } else if (val > 0) {
                    // 如果累加值大于0,因为数组已经排好序,所以把右节点往左移动就会慢慢减小累加值(下同)
                    // 此处不需要判断移动节点后的值与之前节点值是否相同,因为就算相同,那就说明后面累加的值也是不为0,最后还会走到这里进行重新移动节点
                    r--;
                } else {
                    l++;
                }
            }
        }
        return result;
    }
}

---------------- 打印结果:
[[-2,0,2],[-1,0,1]]
[[-1,-1,2],[-1,0,1]]
[[-2,0,2]]
[[0,0,0]]

最后

  • 虚心学习,共同进步-_-