每天leetcode

| 开始刷题计划,每天刷几道,目标一千道,从今天开始,从不断更

时间 2021年9-30

/**
 * @author js1981725869@163.com
 * @date 2021年09月29日 21:23
 */

import java.util.*;

/**
 * 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a ,b ,c ,使得 a + b + c = 0 ?请找出所有和为 0 且 不重复 的三元组。
 * <p>
 *  
 * <p>
 * 示例 1:
 * <p>
 * 输入:nums = [-1,0,1,2,-1,-4]
 * 输出:[[-1,-1,2],[-1,0,1]]
 * 示例 2:
 * <p>
 * 输入:nums = []
 * 输出:[]
 * 示例 3:
 * <p>
 * 输入:nums = [0]
 * 输出:[]
 * <p>
 * 来源:力扣(LeetCode)
 * 链接:https://leetcode-cn.com/problems/1fGaJU
 * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
 */
public class ThreeNumAddToZero {

    public static void main(String[] args) {
        System.out.println(threeSum(new int[]{-1,0,1,2,-1,-4}));
    }

    public static List<List<Integer>> threeSum(int[] nums) {
        //排序再相加
        quickSort(nums, 0, nums.length - 1);
        Set<List<Integer>> set = new HashSet<>();

        for (int i = 0; i < nums.length; i++) {
            int target = -nums[i];
            //再i+1到length-1的范围找到两个数相加等于target

            int left = i + 1;
            int right = nums.length - 1;

            while (left < right) {
                int sum = nums[left] + nums[right];
                if (sum == target) {
                    set.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    left++;
                    right--;
                }
                else if (sum < target) {
                    left++;
                } else {
                    right--;
                }

            }
        }

        return new ArrayList<>(set); // O(n)
    }

    //快速排序
    public static void quickSort(int[] nums, int left, int right) {
        if (nums == null || nums.length == 0) {
            return;
        }
        if (left > right) {
            return;
        }
        int key = nums[right];

        //保留left和right的指针位置
        int l = left;
        int r = right;
/**
 *         先移动右边找到比key小的数,在移动左边找到比key大的数,交换(如果不按照这个规则来的话)
 *         以下分为两种情况:
 *
 *         第一种:比如先移动右边找比key大的数,再移动左边找比key小的数,那么右边的移动其实没有必要,
 *         因为我们就是从左往右依次增大,而移动左边找到比key小的数之后就需要跟key交换,
 *         这就变成冒泡排序了
 *
 *         第二种情况如果先移动左边的找到比key大的数,再移动右边找到比左边小的数交换,这样的话,
 *         到了最后肯定是先找到左边的最大然后和key做交换,那么就会出错,除非一开始把分界值放在最右侧,
 *         那我们使用这一种方式去做快排
 */
        while (l != r) {
            //l!=r的时候我们就可以根据上面的规则把这两个交换

            while (nums[l] <= key && l < r) {
                //从左边移动找到大于key的数,当他小于key时,我们把l向右移
                l++;
            }
            while (nums[r] >= key && r > l) {
                //从右边开始移动找到小于key的数,当他大于key时,我们把r向左移
                r--;
            }


            //移动完了,看看l和r的情况,只可能是l<r,或者l=r
            if (l < r) {
                //交换l和r位置的数字
                int temp = nums[l];
                nums[l] = nums[r];
                nums[r] = temp;
            }
        }
        //当l = r的时候我们就把key和这个索引处数字交换
        nums[right] = nums[l];
        nums[l] = key;
        quickSort(nums, left, l - 1);
//        [-4, -29, -1, 2, -1, 1, 9, 1, 20, 0]
        quickSort(nums, l + 1, right);
    }
}

心得:对快速排序有了一定的理解。加油!

内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/js119/p/15357896.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!