LeetCode-18-四数之和

Java实现 LeetCode 18 四数之和 18. 四数之和 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 注意: 答案中不可以包含重复的四元组。 示例: 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 满足要求的四元... 阅读详情

题目

来源:LeetCode.

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。
请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] :

示例 1:

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

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

提示:

  • 1 < = n u m s . l e n g t h < = 200 1 <= nums.length <= 200 1<=nums.length<=200
  • − 109 < = n u m s [ i ] < = 109 -109 <= nums[i] <= 109 −109<=nums[i]<=109
  • − 109 < = t a r g e t < = 109 -109 <= target <= 109 −109<=target<=109

接下来看一下解题思路:

思路:排序 + 双指针:

这道题与三数之和类似,也可以用相同的思路来解决这道题
    为了避免枚举到重复四元组,则需要保证每一重循环枚举到的元素不小于其上一重循环枚举到的元素,且在同一重循环中不能多次枚举到相同的元素;
    可以对数组进行排序,并且在循环过程中遵循以下两点:

  • 每一种循环枚举到的下标必须大于上一重循环枚举到的下标;
  • 同一重循环中,如果当前元素与上一个元素相同,则跳过当前元素;
        因为数组已经被排序,因此可以使用双指针的方法去掉一重循环;
        保持第三重循环不变,而将第四重循环变成一个从数组最右端开始向左移动的指针;
        注意:还需要保持左指针一直在右指针的左侧(即满足 c ≤ d c \leq d c≤d)
public static List<List<Integer>> fourSum1(int[] nums, int target) {
    List<List<Integer>> result = new ArrayList<>();

    if (nums == null || nums.length < 4) {
        return result;
    }
    // 排序
    Arrays.sort(nums);
    int len = nums.length;
    // 枚举第一个数字 a
    for (int i = 0; i < len; ++i) {
        // 需要和上一次枚举的数不同
        if (i > 0 && nums[i] == nums[i - 1]) {
            continue;
        }
        // 枚举第二个数字 b
        for (int j = i + 1; j < len; ++j) {
            // 需要和上一次枚举的数不同
            if (j > i + 1 && nums[j] == nums[j - 1]) {
                continue;
            }
            // 枚举第三个数字 c
            for (int k = j + 1; k < len; ++k) {
                // 需要和上一次枚举的数不同
                if (k > j + 1 && nums[k] == nums[k - 1]) {
                    continue;
                }
                // 右指针
                int m = len - 1;
                // 需要保证第三个数字 c 在第四个数字 d 的左侧
                while (m > k && nums[i] + nums[j] + nums[k] + nums[m] > target) {
                    --m;
                }
                // 第三个数字 c 和第四个数字 d 重合,随着 c 后续的增加,
                // 就不会满足 a+b+c+d=0 并且 c < d 的 c 了,可以退出循环。
                if (m == k) {
                    break;
                }
                if (nums[i] + nums[j] + nums[k] + nums[m] == target) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[k]);
                    list.add(nums[m]);
                    result.add(list);
                }
            }
        }
    }
    return result;
}

    然而,即使用双指针省去了一层for循环,但是效率仍然不高,还可以做一些优化;
    使用两重循环分别枚举前两个数,然后在两重循环枚举到的数之后使用双指针枚举剩下的两个数;
    假设两重循环枚举到的前两个数分别位于下标 i i i 和 j j j,其中 i < j i<j i<j。初始时,左右指针分别指向下标 j + 1 j+1 j+1 和下标 n − 1 n-1 n−1。每次计算四个数的和,并进行如下操作:

  • 如果和等于 target \textit{target} target,则将枚举到的四个数加到答案中,然后将左指针右移直到遇到不同的数,将右指针左移直到遇到不同的数;
  • 如果和小于 target \textit{target} target,则将左指针右移一位;
  • 如果和大于 target \textit{target} target,则将右指针左移一位。

    我们还可以做一些优化,避免一些多余的循环:

  • 在确定第一个数之后,如果 nums [ i ] + nums [ i + 1 ] + nums [ i + 2 ] + nums [ i + 3 ] > target \textit{nums}[i]+\textit{nums}[i+1]+\textit{nums}[i+2]+\textit{nums}[i+3]>\textit{target} nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target,说明此时剩下的三个数无论取什么值,四数之和一定大于 target \textit{target} target,因此退出第一重循环;
  • 在确定第一个数之后,如果 nums [ i ] + nums [ n − 3 ] + nums [ n − 2 ] + nums [ n − 1 ] < target \textit{nums}[i]+\textit{nums}[n-3]+\textit{nums}[n-2]+\textit{nums}[n-1]<\textit{target} nums[i]+nums[n−3]+nums[n−2]+nums[n−1]<target,说明此时剩下的三个数无论取什么值,四数之和一定小于 target \textit{target} target,因此第一重循环直接进入下一轮,枚举 nums [ i + 1 ] \textit{nums}[i+1] nums[i+1];
  • 在确定前两个数之后,如果 nums [ i ] + nums [ j ] + nums [ j + 1 ] + nums [ j + 2 ] > target \textit{nums}[i]+\textit{nums}[j]+\textit{nums}[j+1]+\textit{nums}[j+2]>\textit{target} nums[i]+nums[j]+nums[j+1]+nums[j+2]>target,说明此时剩下的两个数无论取什么值,四数之和一定大于 target \textit{target} target,因此退出第二重循环;
  • 在确定前两个数之后,如果 nums [ i ] + nums [ j ] + nums [ n − 2 ] + nums [ n − 1 ] < target \textit{nums}[i]+\textit{nums}[j]+\textit{nums}[n-2]+\textit{nums}[n-1]<\textit{target} nums[i]+nums[j]+nums[n−2]+nums[n−1]<target,说明此时剩下的两个数无论取什么值,四数之和一定小于 target \textit{target} target,因此第二重循环直接进入下一轮,枚举 nums [ j + 1 ] \textit{nums}[j+1] nums[j+1];
public static List<List<Integer>> fourSum(int[] nums, int target) {
    List<List<Integer>> result = new ArrayList<>();

    if (nums == null || nums.length < 4) {
        return result;
    }
    Arrays.sort(nums);
    int n = nums.length;
    // 枚举第一个数字 a
    for (int i = 0; i < n - 3; ++i) {
        // 需要和上一次枚举的数不同
        if (i > 0 && nums[i] == nums[i - 1]) {
            continue;
        }
        // 此时剩下的三个数无论取什么值,四数之和一定大于 target,因此退出第一重循环;
        if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
            break;
        }
        // 此时剩下的三个数无论取什么值,四数之和一定小于 target,因此第一重循环直接进入下一轮,枚举 nums[i+1];
        if (nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) {
            continue;
        }
        // 枚举第二个数字 b
        for (int j = i + 1; j < n - 2; ++j) {
            // 需要和上一次枚举的数不同
            if (j > i + 1 && nums[j] == nums[j - 1]) {
                continue;
            }
            if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
                break;
            }
            if (nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target) {
                continue;
            }
            int left = j + 1;
            int right = n - 1;
            while (left < right) {
                int sum = nums[i] + nums[j] + nums[left] + nums[right];
                // 如果和等于 target,则将枚举到的四个数加到答案中,然后将左指针右移直到遇到不同的数,将右指针左移直到遇到不同的数
                if (sum == target) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    result.add(list);
                    while (left < right && nums[left] == nums[left + 1]) {
                        ++left;
                    }
                    ++left;
                    while (left < right && nums[right] == nums[right - 1]) {
                        --right;
                    }
                    --right;
                } else if(sum < target){   // 如果和小于 target,则将左指针右移一位
                    ++left;
                } else {  // 如果和大于 target,则将右指针左移一位
                    --right;
                }
            }
        }
    }
    return result;
}
总结

    时间复杂度: O ( n 3 ) O(n^3) O(n3),其中 n n n 是数组的长度。排序的时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn),枚举四元组的时间复杂度是 O ( n 3 ) O(n^3) O(n3),因此总时间复杂度为 O ( n 3 + n log ⁡ n ) = O ( n 3 ) O(n^3+n\log n)=O(n^3) O(n3+nlogn)=O(n3);
    空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组的长度。空间复杂度主要取决于排序额外使用的空间。使用了一个额外的数组存储了数组 nums \textit{nums} nums 的副本并排序,空间复杂度为 O ( n ) O(n) O(n);

【中等】力扣算法题解析LeetCode18:四数之和 该算法解决在数组中寻找不重复四元组使其和等于目标值的问题。通过排序数组后使用双重循环固定前两个数,结合双指针法查找后两个数,同时利用多层剪枝优化(跳过重复元素、提前终止无效分支)。使用long类型防止整数溢出,确保正确性。时间复杂度优化至O(n³),空间复杂度O(1)。代码通过5处剪枝和双指针技巧高效处理大规模数据,适用于长度≤200的数组,能正确处理大整数运算。 阅读详情

相关推荐

VFIO框架源码分析(二十一)- IOMMUFD 模式下的 DMA 映射机制

在虚拟化 I/O 的世界里,无论上层管理面(如对象模型、设备绑定)如何重构,数据面最核心的任务始终未变——DMA 映射(DMA Mapping)。即如何建立 Guest Physical Address (GPA) 到 Host Physical Address (HPA) 的映射关系,并将其填入 IOMMU 的硬件页表中,使得直通设备能够正确访问虚拟机内存。在 Legacy VFIO (Type1) 时代,这一职责由承担,它通过ioctl 操作 Container。

qq_36071928的博客 1007

力扣LeetCode第18题四数之和

## 力扣LeetCode第18题四数之和

weixin_44061444的博客 257

MiFlash Prime免授权刷机实战:解锁小米9008 EDL救砖新方案

MiFlash Prime作为免授权刷机工具,有效解决了小米设备在9008 EDL模式下因账号验证无法救砖的难题。本文详细介绍了从驱动安装、进入EDL模式到固件刷写的完整流程,帮助用户安全快速地恢复变砖设备,是维修人员和极客的实用解决方案。

5f4d3s2a1q的博客 2859

18. 四数之和 - 力扣(LeetCode)

所以最终结果为 [[ -2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]。假设输入数组为 nums = [1, 0, -1, 0, -2, 2],目标值为 target = 0。通过移动这两个指针,可以高效地找到所有可能的后两个数,使得四个数的和等于目标值。输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]输入:nums = [1,0,-1,0,-2,2], target = 0。排序后的数组为 [-2, -1, 0, 0, 1, 2]。

q1111111da的博客 1053

从Microchip SDK到STM32实战:手把手教你移植LAN9252 EtherCAT从站驱动(含EEPROM配置避坑)

本文详细介绍了如何将Microchip SDK中的LAN9252 EtherCAT从站驱动移植到STM32F407平台,包括FSMC接口配置、中断处理适配和EEPROM配置等关键步骤。通过实战指南和避坑技巧,帮助开发者快速实现高性能EtherCAT从站设备的开发,适用于工业自动化领域。

weixin_29197835的博客 446

到底什么是Harness工程?一篇文章从入门到企业落地全解析

随着OpenClaw爆火,Harness Engineering(驾驭工程)成为AI编程时代的热门概念,很多小白对其感到陌生。本文用通俗类比和真实案例,避开复杂术语,从基础定义入手,讲清Harness Engineering的核心逻辑——人类工程师设计“约束系统”(马具),让AI模型(烈马)安全高效地完成代码工作,同时拆解其核心组件、企业落地场景和实战成果,帮小白快速入门,读懂这项能解放人力、提升效率的新技术,轻松掌握它的核心价值和落地思路。

program哲学 3257

力扣18:四数之和

本文介绍了力扣18题"四数之和"的解题思路。题目要求找出数组中所有和为target且不重复的四元组。采用回溯算法,通过三个关键剪枝优化:1)剩余数字不足时提前终止;2)当前和加最小值仍大于target时终止;3)当前和加最大值仍小于target时跳过。同时使用排序和去重处理确保结果唯一。代码实现中,先对数组排序,再通过深度优先搜索回溯所有可能组合,利用剪枝条件大幅降低时间复杂度,最终返回所有符合条件的四元组。

weixin_74285822的博客 1108

Codex入门01-环境安装(小白入门:手把手教你安装配置,国内网络也能搞定)

本文手把手教你从零搭建 Codex CLI 开发环境。内容涵盖 Node.js 安装(macOS/Windows/Linux)、Codex CLI 全局安装、ChatGPT 账号登录认证,以及国内网络代理配置。还包括常见问题排查和一键启动脚本编写。跟着截图一步步操作,10分钟搞定全部环境,开始用AI写代码!

yueyeguzhuo的专栏 344

LeetCode - 18 四数之和

四数之和:固定四元组中最小两个值的索引 i,j,然后定义双指针 L = j + 1,R = len(nums) - 1,如果此时四元组之和 sum = nums[i] + nums[j] + nums[L] + nums[R]因此当 nums[i] == nums[i-1] 时,我们可以跳过,比如上图 i = 1,j=2 的过程可以跳过,因为产生的必然时重复的四元组。如上图所示,红色框部分,其中 j 的位置相同,L,R的运动过程也相同,只是 i 的位置发生了变化,但是 i 指向的元素值时没有改变的。

优快云 1136

Mac安装Typescript报错

根本原因是系统级目录的权限限制。推荐通过修改目录权限或使用nvm彻底解决问题。

江拥羡橙的博客 210

【七.三维视觉与视频分析】【1.点云处理:PointNet++/PointTransformer】

各位老铁,今天咱们要聊的可不是普通的二维图像处理,而是三维视觉领域最硬核的技术——点云处理。从最早的PointNet到如今的PointTransformer,这场技术进化堪比三维版的"像素革命"。今天咱们就深入解剖两大里程碑:PointNet++和PointTransformer,保证让你看完全文就能在点云领域横着走!想象一下,你抓了把沙子撒在空中,每粒沙子的位置都是三维坐标——这就是点云的典型形态。最后送大家一句话:点云处理就像在三维宇宙中寻找星辰的轨迹,既要望远镜的宏观视野,也要显微镜的细致入微。

商务合作|问题讨论|交流学习 请联系作者微信,加微信请务必注明来意,博客主页有联系方式 473

18. 四数之和(力扣LeetCode)

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target。输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]输入:nums = [1,0,-1,0,-2,2], target = 0。输入:nums = [2,2,2,2,2], target = 8。你可以按 任意顺序 返回答案。输出:[[2,2,2,2]]

m0_73841621的博客 1035

Ardupilot二次开发(二):自定义mavlivk消息

在下面的文件添加自定义消息的xml定义然后编译固件,会生成相应的消息头文件。

超维空间科技的博客 2312

【算法专题】双指针算法之18. 四数之和(力扣)

🏆本篇主题为:【算法专题】双指针算法之18. 四数之和(力扣)

cilmy23的note 1298

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

LeetCode18 四数之和

LeetCode18 四数之和题解(附伪代码步骤) 题目 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 举个例子: 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 满足要求的四元组集合为: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2]

lizefeng1998的博客 272

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

day30【LeetCode力扣】18.四数之和

排序后,可以确保不同顺序的相同元素组合被视为同一个组合。这是因为排序后的元组是唯一的,无论元素的原始顺序如何。,它们的元素相同,但顺序不同。如果不排序,它们将被视为不同的项,并且都会被添加到集合。排序的主要目的是为了避免重复。而排序后,这两个四元组都会变成。

canGfly的博客 388

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

LeetCode第18题_四数之和

这道题的关键点:理解三数之和到四数之和的扩展处理整数溢出问题高效的剪枝策略优化策略:添加更多的剪枝条件预处理边界情况避免重复计算注意事项:整数溢出的处理去重的正确性边界条件的处理。

qq_40263592的博客 1795

算法学习——LeetCode力扣哈希表篇2(454. 四数相加 II、383. 赎金信、15. 三数之和、18. 四数之和)

算法学习——LeetCode力扣哈希表篇2(454. 四数相加 II、383. 赎金信、15. 三数之和、18. 四数之和)

拉依达不拉跨的博客 1211

【LeetCode-18】四数之和

LeetCode-18】四数之和,本文将详细讲解如何解决经典的“四数之和”问题。我们会从问题的背景出发,逐步分析解题思路,并通过清晰的案例执行过程展示每一步的逻辑推导。同时,我们还会提供完整的Java代码实现,并对代码进行详细的注释说明。

qq_44530108的博客 1064

力扣(LeetCode 18)四数之和 python

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

qq_41318002的博客 261

力扣LeetCode #18 四数之和(FourSum)

- 题目描述 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 注意:答案中不可以包含重复的四元组。 来源:LeetCode(https://leetcode-cn.com/problems/4sum) - 示例 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0,满足要求的四元组集合为: [[

weixin_49155948的博客 313

力扣18题解:四数之和(java实现)

LeetCode第18题是一个经典的四数之和问题,通过这个问题,我们可以加深对哈希表和双指针技巧的理解。掌握这个问题的解法,对于解决其他类似问题非常有帮助。

2301_77695569的博客 858

力扣第18题:四数之和

力扣第18题:四数之和。接下来我们开始循环,我们做三数之和时候采用一个循环,两个指针就可以求得解,但是我们求四数之和时,一个循环是显然不够用的,我们需要采取双循环来遍历前面两个数,再使用双指针来决定后面两个数。当然我们还可以进一步缩减循环次数,我们可以在每一重循环中判断当前循环的所对应的最大值和最小值。双指针那块的流程在前面三数之和中已经叙述过,这里就不再赘述,可以在博主的主页中进行查看。输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]首先,我们对数组进行排序,避免去重操作消耗大

一位想要成为优秀全栈工程师的有志青年! 827

#力扣LeetCode18. 四数之和 @FDDLC

题目描述: 18. 四数之和 - 力扣(LeetCode) (leetcode-cn.com) Java代码一: class Solution { public List<List<Integer>> fourSum(int[] n, int t) { List<List<Integer>> ans=new LinkedList<>(); Arrays.sort(n); HashM

LiuXingchang的博客 396

【LeetCode刷题日记】18.四数之和

本文介绍了LeetCode 18题"四数之和"的解题思路与Java实现。该题要求在给定数组中找到所有不重复的四元组,使其和等于目标值。解题采用双指针法,在排序后的数组基础上,通过两层循环固定前两个数,再用双指针寻找后两个数,同时进行剪枝优化和去重处理。时间复杂度为O(n³),与三数之和类似但多一层循环。文章详细解析了代码逻辑,包括排序、双重循环、双指针移动、剪枝条件和去重操作,并指出其可扩展性(五数、六数之和等)。最后提供了完整的Java代码示例和测试用例。

任岁月风干理想再也找不回真的我 1210
上一篇: LeetCode-17-电话号码的字母组合
下一篇: LeetCode-20-有效的括号
CodAlun
博客等级 码龄8年 46粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值