LeetCode题解java算法18. 四数之和

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

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

示例 1:

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

示例 2:

输入:nums = [], target = 0
输出:[]

提示:

0 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109

双指针解法

 /**
     * 18. 四数之和
     * 1. ArrayList的实现是基于数组,LinkedList的实现是基于双向链表。
     * 2. 对于随机访问,ArrayList优于LinkedList,ArrayList可以根据下标以O(1)时间复杂度对元素进行随机访问。
     * 而LinkedList的每一个元素都依靠地址指针和它后一个元素连接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)
     * 3. 对于插入和删除操作,LinkedList优于ArrayList,因为当元素被添加到LinkedList任意位置的时候,
     * 不需要像ArrayList那样重新计算大小或者是更新索引。
     * 4. LinkedList比ArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个引用,
     * 一个指向前一个元素,一个指向后一个元素。
     * 
     *
     * asList 将数组转化成List
     * @param nums
     * @param target
     * @return
     */
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> lists = new ArrayList<>();
        if (nums.length == 0 || nums == null) {
            return lists;
        }
        //对数组中的数据进行排序
        Arrays.sort(nums);
        //获取数组长度
        int length = nums.length;
        //定义四个指针k,i,left,right   k从0开始遍历   i从k+1开始遍历  留下left和right   left指向i+1  right指向此时的最大值

        //为何length-3呢?   由于同时存在四个指针,每一个指针都会占据一个位置  当length-3的时候   就只剩下一种情况了
        //i=length-2   left=length-1  right=length
        for (int k = 0; k < length - 3; k++) {
            //如果在k>0的基础上 nums[k]==nums[k-1]  只能表明两个数字是一样  那么它和k-1循环的结果相差不是很大,甚至有可能一样
            //因此没有必要  可以进行忽略
            if (k > 0 && nums[k] == nums[k - 1]) {
                continue;
            }
            //由于此数组已经进行过排序  获取当前最小值,如果最小值比目标值大,说明后面越来越大的值根本没戏
            int min1 = nums[k] + nums[k + 1] + nums[k + 2] + nums[k + 3];
            if (min1 > target) {
                break;
            }
            //由于此数组已经进行过排序  获取当前最大值,如果最大值比目标值小,说明后面越来越小的值根本没戏,忽略
            int max1 = nums[k] + nums[length - 1] + nums[length - 2] + nums[length - 3];
            if (max1 < target) {
                continue;
            }
            //第二层循环i,初始值指向k+1  由于k值相当于占取了一位,第二位就没必要去取第一位的数据的,每次数据只能出现一次
            for (int i = k + 1; i < length - 2; i++) {
                //第二层的方法以下内推
                if (i > k + 1 && nums[i] == nums[i - 1]) {
                    continue;
                }
                //注意此时的首位已经确定
                int min2 = nums[k] + nums[i] + nums[i + 1] + nums[i + 2];
                if (min2 > target) {
                    break;
                }
                int max2 = nums[k] + nums[i] + nums[length - 1] + nums[length - 2];
                if (max2 < target) {
                    continue;
                }
                //定义指针j指向i+1
                int left = i + 1;
                //定义指针h指向数组末尾
                int right = length - 1;
                while (left < right) {
                    int num = nums[k] + nums[i] + nums[left] + nums[right];
                    if (num < target) {
                        left++;
                    } else if (num > target) {
                        right--;
                    } else {
                        //存储对应的数据,接着继续向下寻找  直到查找结束
                        lists.add(Arrays.asList(nums[k], nums[i], nums[left], nums[right]));

                        left++;
                        while (left < right && nums[left] == nums[left - 1]) {
                            left++;
                        }
                        right--;
                        while (left < right && i < right && nums[right] == nums[right + 1]) {
                            right--;
                        }
                    }
                }
            }


        }
        return lists;

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值