LeetCode(18)—— 四数之和

真的是醉了,3数和搞定又来了个4数和,思路肯定就是把4数和转化为3数和问题。本来呢,我还想利用3数和中类似的一个技巧,快速break掉的,可是老是有重复结果,折磨死我了。。。算了,就直接这样吧。

主要思路:

  • 4转3,3转2
  • 双指针

FourSum

import java.util.*;

public class FourSum18 {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        // 注意一下,List是一个接口,不能被实例化,需要用LinkedList
        List<List<Integer>> result = new LinkedList<List<Integer>>();
        // 先对数组进行排序
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            // 避免结果list中因相邻两次i下标值相同而出现重复
            if (i > 0 && nums[i] == nums[i - 1])
                continue;
            int threeTarget = target - nums[i];  // 后面三个数的目标和

            for (int j = i + 1; j < nums.length - 2; j++) {
                // 避免结果list中因相邻两次j下标值相同而出现重复
                if (j > i + 1 && nums[j] == nums[j - 1])
                    continue;
                int twoTarget = threeTarget - nums[j]; // 再后面两个数的目标和
                // 双指针
                int left = j + 1;
                int right = nums.length - 1;
                while (left < right) {
                    if (nums[left] + nums[right] == twoTarget) {
                        List<Integer> newList = new LinkedList<Integer>();
                        newList.add(nums[i]);
                        newList.add(nums[j]);
                        newList.add(nums[left]);
                        newList.add(nums[right]);
                        result.add(newList);
                        // 避免结果list中因相邻两次left下标值相同而出现重复
                        while (++left < right && nums[left] == nums[left - 1]) {
                        }
                        // 避免结果list中因相邻两次right下标值相同而出现重复
                        while (left < --right && nums[right] == nums[right + 1]) {
                        }
                    } else if (nums[left] + nums[right] < twoTarget) {
                        left++;
                    } else {
                        right--;
                    }
                }
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int[] nums = {1, 0, -1, 0, -2, 2};
        int[] nums1 = {0, 0, 0, 0};
        int[] nums2 = {-3, -2, -1, 0, 0, 1, 2, 3};
        int[] nums3 = {-5, -4, -3, -2, -1, 0, 0, 1, 2, 3, 4, 5};
        int[] nums4 = {1, -2, -5, -4, -3, 3, 3, 5};
        int target = -11;
        FourSum18 fourSum18 = new FourSum18();
        List<List<Integer>> res = fourSum18.fourSum(nums4, target);
        for (int i = 0; i < res.size(); i++) {
            System.out.println();
            for (int j = 0; j < res.get(i).size(); j++)
                System.out.println(res.get(i).get(j));
        }
    }
}

ThreeSum

import java.util.List;
import java.util.LinkedList;
import java.util.Arrays;

class ThreeSum15 {
    public List<List<Integer>> threeSum(int[] nums) {
        // 注意一下,List是一个接口,不能被实例化,需要用LinkedList来帮忙
        List<List<Integer>> result = new LinkedList<List<Integer>>();
        // 先对数组进行排序
        Arrays.sort(nums);
        int target = 0;
        for (int i = 0; i < nums.length - 2; i++) {
            // 受到LeetCode twoSum的启发,先将第一个数视为target
            // 再在后面的数中,找有没有满足条件的即可。
            target = nums[i];
            if (target > 0)   // 若当前数字大于0,那么后面肯定也都大于0,则不可能满足
                break;
            if (i > 0 && nums[i] == nums[i - 1])
                continue;
            // 设置两个移动的“指针”,分别指向两端。
            // 如果两数之和小于-target,就左指针右移;如果两数之和大于target,就右指针左移。
            int left = i + 1;
            int right = nums.length - 1;
            while (left < right) {
                if (nums[left] + nums[right] == -target) {
                    List<Integer> newList = new LinkedList<Integer>();
                    newList.add(nums[i]);
                    newList.add(nums[left]);
                    newList.add(nums[right]);
                    result.add(newList);
                    while (++left < right && nums[left] == nums[left - 1]) {
                    }
                    while (left < --right && nums[right] == nums[right + 1]) {
                    }
                } else if (nums[left] + nums[right] < -target) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值