zoukankan      html  css  js  c++  java
  • 三数之和

    给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 请你找出所有和为 0 且不重复的三元组。
    注意:答案中不可以包含重复的三元组。

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

    对数组进行排序
    {-4,-1,-1,0,1,2}
    left=i+1
    right=length-1=5
    while(right>left)
    i=0,left=1,right=5 即-4-1+2=-3<0 left++
    i=0,left=2,right=5 即-4-1+2=-3<0 left++
    i=0,left=3,right=5 即-4+0+2=-2<0 left++
    i=0,left=4,right=5 即-4+1+2=-1<0 left++

    i=1,left=2,right=5 即-1-1+2=0 left++ right-- 此时left=3 right=4 nums[left]=0 nums[left+1]=1 nums[right]=1 nums[right-1]=0 不进入循环
    while (right>left && nums[left] == nums[left+1]) {
    left++; //left后移,寻找新的解
    }
    //判断右界是否和下一位置重复,去除重复解。
    while (right>left && nums[right] == nums[right-1]) {
    right--; //right左移,寻找新的解
    }
    i=1,left=3,right=4 即-1+0+1=0 left++ right-- 此时left =4 right=3 跳出循环

    i=2,nums[i]=nums[i-1]=-1 跳出循环

    i=3,left=4,right=5 即0+1+2>0 right-- 此时left=4 right=4 跳出循环

    代码实现

    package leetcode;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class _15three_sum {
        public static void main(String[] args) {
            int[] nums = new int[]{-1,0,1,2,-1,-4};
            int [] nums2 = new int[]{-2,0,1,1,2};
            List<List<Integer>> lists = doThreeSum(nums2);
            System.out.println(lists);
        }
    
        /**
         * 三数之和为0
         * 输入:nums = [-1,0,1,2,-1,-4]
         * 输出:[[-1,-1,2],[-1,0,1]]
         * 1. 特判,对于数组长度 n,如果数组为 null 或者数组长度小于 3,返回 []。
         * 2. 对数组进行排序。
         * 3. 遍历排序后数组:
         *    若 nums[i]>0:因为已经排序好,所以后面不可能有三个数加和等于 0,直接返回结果。
         *    对于重复元素:跳过,避免出现重复解
         *    令左指针 left=i+1,右指针 right=n-1,当 right>left时,执行循环:
         *        *当 nums[i]+nums[L]+nums[R]==0 执行循环
         *         判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,R移到下一位置,寻找新的解
         *        *若和大于 0,说明 nums[R] 太大,R 左移
         *        *若和小于 0,说明 nums[L]nums[L] 太小,LL 右移
         * @param nums
         */
        private static List<List<Integer>> doThreeSum(int [] nums){
            List<List<Integer>> results = new ArrayList<>();
            //特判,对于数组长度 n,如果数组为 null 或者数组长度小于 3,返回 []。
            if(nums.length<3||nums==null){
                return results;
            }
            //对数组进行排序。
            Arrays.sort(nums);
            for (int i = 0; i < nums.length-2; i++) {
                //因为已经排序好,故后面不可能有三个数加和等于0,跳出循环
                if(nums[i]>0){
                    break;
                }
                //对于重复元素:跳过,避免出现重复解
                if(i > 0 && nums[i] == nums[i - 1])
                    continue;
                //令左指针 left=i+1
                int left =i+1;
                //令右指针 right=nums.length-1;
                int right =nums.length-1;
                //当 right>left时,执行循环
                while (right>left){
                    int sum = nums[i]+nums[left]+nums[right];
                    if(sum==0){
                        //加入集合
                        results.add(Arrays.asList(nums[i],nums[left],nums[right]));
                        //{-2,0,1,1,2} 本来是判断
                        //left++; right--; 写在这里,会影响下面的判断,导致left一下加两次
                        //本来是判断0 和1是否相等的,先left++,导致判断的是1 1 ,把-2,1,1这个结果丢失
                        //判断左界是否和下一位置重复,去除重复解。用while而不用if是为了排除0,0,0,0这样重复的数据,减少判断次数
                        while (right>left && nums[left] == nums[left+1]) {
                            left++; //left后移,寻找新的解
                        }
                        //判断右界是否和下一位置重复,去除重复解。
                        while (right>left && nums[right] == nums[right-1]) {
                            right--; //right左移,寻找新的解
                        }
                        left++; right--;
                    }
                    //三数相加大于0,说明右边的数太大,向前移一下
                    else if(sum>0){
                        right--;
                    }
                    //三数相加大于0,说明左边的数太小,向后移一下
                    else if(sum<0){
                        left++;
                    }
                }
            }
            return results;
        }
    }
  • 相关阅读:
    linux下C语言socket网络编程简例
    cJSON学习笔记 续集
    用javac编译整个j2ee项目
    如何用javac 和java 编译运行整个Java工程
    Log4j 日志级别
    (获取选中的光标起始位置)EditText常用属性【三】:EditText选取操作
    Linux下启动和停止Java应用程序的Shell脚本
    (判断url文件大小)关于inputStream.available()方法获取下载文件的总大小
    java 从网络Url中下载文件
    JavaMail入门:创建纯文本、HTML格式的邮件
  • 原文地址:https://www.cnblogs.com/huangzhen22/p/14554140.html
Copyright © 2011-2022 走看看