第五周_A-leetcode数组-三数之和

69 阅读2分钟

中等难度的题目:三数之和。有点开始饶了😥。所有的注释都在代码里面了

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

同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

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

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


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k
 * 同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
 * <p>
 * 你返回所有和为 0 且不重复的三元组。
 * <p>
 * 注意:答案中不可以包含重复的三元组。
 */
public class 三数之和 {
    public static void main(String[] args) {
        int[] nums = {-1, 0, 1, 2, -1,-1, -4};
        /**
         * 解题的重点是:如何去重。不然按照简单的三重循环即可解决(就如下面所示)
         */
        System.out.println(threeSum(nums));

        /**
         * 简单的三重循环 ;没有去重
         */
//        List list = new ArrayList<>();
//        List result = new ArrayList<>();
//        int length = nums.length;
//        for (int i = 0; i < length; i++) {
//            for (int j = i + 1; j < length; j++) {
//                for (int k = i + 2; k < length; k++) {
//                    if (nums[i] + nums[j] + nums[k] == 0) {
//                        list.add(nums[i]);
//                        list.add(nums[j]);
//                        list.add(nums[k]);
//                        result.add(list);
//                    }
//                }
//            }
//            break;
//        }
//        System.out.println(result.stream().distinct().collect(Collectors.toList()));
    }

    public static List<List<Integer>> threeSum(int[] nums) {
        //数组为空,或者长度小于3的直接返回空
        List<List<Integer>> lists = new ArrayList<>();
        if (nums == null || nums.length < 3) {
            return lists;
        }
        //先排序,再进行处理
        Arrays.sort(nums);

        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) {    //因为是排序的,第一个都大于0 ,那么后面的和更加大于0;所以直接返回
                return lists;
            }
            //这里 i>0 是因为我们循环的第一个元素的下标是0
            if (i > 0 && nums[i] == nums[i - 1]) {  //跳过重复的元素 ,避免出现重复解
                continue;
            }
            //每次循环是:当前下标,当前下标+1,最后的边下标
            int curr = nums[i];//当前值
            int l = i + 1, r = nums.length - 1; //左右指针

            while (l < r) {
                int tmp = curr + nums[l] + nums[r];
                if (tmp == 0) { //
                    List<Integer> list = new ArrayList<>();
                    list.add(curr);
                    list.add(nums[l]);
                    list.add(nums[r]);
                    lists.add(list);
                    /**
                     *移动左右指针的时候,需要判断是否重复,重复就跳过即可
                     */
                    while (l < r && nums[l + 1] == nums[l]) {   //和上面一致,跳过重复的值,避免出现重复解
                        ++l;
                    }
                    /**
                     * 这里只移动左指针也行,提交 leetcode 也能通过,但是击败的用户会变少。
                     */
//                    while (l < r && nums[r - 1] == nums[r]) {
//                        --r;
//                    }
                    ++l;
//                    --r;
                } else if (tmp < 0) {  //和小于 0 ,需要将左指针+1
                    ++l;
                } else {  //和大于 0 ,需要将右指针-1
                    --r;
                }
            }
        }
        return lists;

    }
}