[LeetCode]15. 三数之和(扩展:两数之和、四数之和)

15. 三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

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

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]




思路

1.使用双指针思想解决范围内求值问题。先将数组排序,然后遍历数组,先选出最左边元素为准,从右边数组的两端取元素与最左边元素相加之和是否为0,如果大于0 则整体过大,将右端元素往左移一位,如果小于0 则整体过小,将左端元素往右移一位。其中元素需要双重去重。在最外层,选取最左边元素时和在两端指针缩进时,重复元素都需要去掉。

    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> list = new ArrayList<>();
        //遍历数组,从小到大取元素,然后从右边两个指针内取值判断
        for (int i = 0; i < nums.length-2; i++) {
            //对最左边的数进行去重,相同的数只参与一次完整的遍历。
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }
            //获取当前最小值,如果最小值比目标值大,说明没有合适的数组
            int min=nums[i]+nums[i+1]+nums[i+2];
            if(min>0){
                break;
            }
            //获取当前最大值,如果最大值比目标值小,说明后面越来越小,需要改变i的值。
            int max=nums[i]+nums[nums.length-1]+nums[nums.length-2];
            if(max<0){
               continue;
            }
            //选取前后两个指针
            int l = i + 1, r = nums.length - 1;
            while (l < r) {
                //如果三个数相加为0,则需要对指针的边界去重
                if (nums[l] + nums[r] + nums[i] == 0) {
                    //如果左边指针数值重复,则将指针移到重复中最右边的一个
                    while (l + 1 < nums.length && nums[l] == nums[l + 1]) {
                        l++;
                    }
                    //如果右边指针数值重复,则将指针移到重复中最左边的一个
                    while (r - 1 > 0 && nums[r] == nums[r - 1]) {
                        r--;
                    }

                    List<Integer> integers = new ArrayList<>();
                    integers.add(nums[i]);
                    integers.add(nums[l]);
                    integers.add(nums[r]);
                    list.add(integers);
                    //缩小指针范围,对现有的i再从新的指针范围中取值判断
                    l++;
                    r--;
                } else if (nums[l] + nums[r] + nums[i] < 0) {
                    //将左边指针往右移
                    l++;
                } else {
                    //将右边指针往左移
                    r--;
                }
            }
        }
        return list;
    }




扩展

四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

1.思路和三数之和类似,在三数之后外面加一层嵌套循环,然后判断内存循环的数为外层循环的数加1,双指针的规则不变。

    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        List<List<Integer>> list = new ArrayList<>();
        //遍历数组,从小到大取元素,然后从右边两个指针内取值判断
        for (int j = 0; j < nums.length-3; j++) {
        	//对最左边的数进行去重,相同的数只参与一次完整的遍历。
            if(j>0&&nums[j]==nums[j-1]){
                continue;
            }
            //获取当前最小值,如果最小值比目标值大,说明没有合适的数组
            int min1=nums[j]+nums[j+1]+nums[j+2]+nums[j+3];
            if(min1>target){
                break;
            }
            //获取当前最大值,如果最大值比目标值小,说明后面越来越小,需要改变j的值。
            int max1=nums[j]+nums[nums.length-1]+nums[nums.length-2]+nums[nums.length-3];
            if(max1<target){
                continue;
            }

            for (int i = j+1; i < nums.length-2; i++) {
            	//对最左边的数进行去重,相同的数只参与一次完整的遍历。
                if(i>j+1&&nums[i]==nums[i-1]){
                    continue;
                }

                //获取当前最小值,如果最小值比目标值大,说明没有合适的数组
                int min2=nums[j]+nums[i]+nums[i+1]+nums[i+2];
                if(min2>target){
                    break;
                }
               //获取当前最大值,如果最大值比目标值小,说明后面越来越小,需要改变i的值。
                int max2=nums[j]+nums[i]+nums[nums.length-1]+nums[nums.length-2];
                if(max2<target){
                    continue;
                }

                //选取前后两个指针
                int l = i + 1, r = nums.length - 1;
                while (l < r) {
                    //如果四个数相加为目标数,则需要对指针的边界去重
                    if (nums[l] + nums[r] + nums[i]+nums[j] == target) {
                        //如果左边指针数值重复,则将指针移到重复中最右边的一个
                        while (l + 1 < nums.length && nums[l] == nums[l + 1]) {
                            l++;
                        }
                        //如果右边指针数值重复,则将指针移到重复中最左边的一个
                        while (r - 1 > 0 && nums[r] == nums[r - 1]) {
                            r--;
                        }

                        List<Integer> integers = new ArrayList<>();
                        integers.add(nums[j]);
                        integers.add(nums[i]);
                        integers.add(nums[l]);
                        integers.add(nums[r]);

                        list.add(integers);
                        //缩小指针范围,对现有的i再从新的指针范围中取值判断
                        l++;
                        r--;
                    } else if (nums[l] + nums[r] + nums[i]+nums[j]  < target) {
                        //将左边指针往右移
                        l++;
                    } else {
                        //将右边指针往左移
                        r--;
                    }
                }
            }
        }
        return list;
    }

两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

1.遍历数组并将值和索引加入hashmap中并判断,如果hashmap中有和为target的数,则返回该数与hashmap中值的索引。

    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        int[] ints = new int[2];
        int index=0;
        for (int i=0;i<nums.length;i++){
            //map中是否包含与之和为target的,不包含就将值和索引存入map
            if (!hashMap.containsKey(target-nums[i])) {
                hashMap.put(nums[i], i);
            }else {
                //包含就返回这两个数的下标
                ints[index] = hashMap.get(target - nums[i]);
                ints[++index] = i;
                break;
            }
        }
        return  ints;
    }
发布了36 篇原创文章 · 获赞 28 · 访问量 1505

猜你喜欢

转载自blog.csdn.net/tc979907461/article/details/105061120