LeetCode:18. 4Sum(Medium)

 1. 原题链接

https://leetcode.com/problems/4sum/description/

2. 题目要求

给出整数数组S[n],在数组S中是否存在a,b,c,d四个整数,使得四个数之和等于目标整数target。请找出所有满足此条件的四个整数。

3. 解题思路

先对nums进行排序,然后采用两层for循环来确定前两个数字,最后在第二层for循环中确定后两个数字。

注意可能存在重复解!!

 如下图所示,对Input先进行排序:[-4, -1, -1,0, 1,2],target = -1

存在两个“-1”,因此要考虑结果去重。

使用 if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) 来对第一层for循环,即第一个数字去重。

如果对第二层for循环采用同样的方法去重,很可能导致丢失一个解,返回下图的错误结果。

[-4, -1, -1,0, 1,2],绿色表示第一层for循环遍历到的位置,红色表示第二层for循环开始的位置。如果使用 if (nums[j] != nums[j-1]) 来去重,就会跳过“-1”。

因此引入一个计数器count,来判断第二层for循环执行的次数。当count==1,即第二层for循环刚开始一次时,避免“-1”和“-1”的重复误判。

 4. 代码实现

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class FourSum18 {

    public static void main(String[] args) {
        int[] nums = {-1,-3,-2,2,3,-3,0,-4};
        int target = 4;
        List<List<Integer>> res = FourSum18.fourSum(nums, target);
        for (List list : res) {
            System.out.println(list);
        }
    }

    public static List<List<Integer>> fourSum(int[] nums, int target) {
        ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
        Arrays.sort(nums);  // 对nums进行排序

        for (int i = 0; i < nums.length - 3; i++) {
            int sum1 = target - nums[i];
            if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) {  // 去除遍历第一个数字时重复的结果
                int count =0;
                for (int j = i + 1; j < nums.length - 2; j++) {
                    /**
                     * 需要判断遍历第二个数字存在重复解的可能
                     * 要同时考虑第一次遍历的位置
                     * 用count计数第二个数遍历的次数
                     */
                    count++;

                    if (nums[j] != nums[j-1]|| count==1) {  // 去除遍历第二个数字时重复的结果
                        int sum2 = sum1 - nums[j], l = j + 1, r = nums.length - 1;
                        while (l < r) {
                            if (nums[l] + nums[r] == sum2) {
                                res.add(Arrays.asList(nums[i], nums[j], nums[l], nums[r]));
                                while (l < r && nums[l] == nums[l + 1]) l++;
                                while (l < r && nums[r] == nums[r - 1]) r--;
                                l++;
                                r--;
                            } else if (sum2 < nums[l] + nums[r]) {
                                while (l < r && nums[r] == nums[r - 1]) r--;
                                r--;

                            } else {
                                while (l < r && nums[l] == nums[l + 1]) l++;
                                l++;
                            }
                        }
                    }
                }

            }
        }
        return res;
    }
}

  

转载于:https://www.cnblogs.com/huiAlex/p/8092980.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值