【LeetCode】18. 四数之和

文章目录

  • 18. 四数之和
    • 题目描述
    • 示例 1:
    • 示例 2:
    • 提示:
    • 解题思路
      • 算法一:排序 + 双指针(推荐)
      • 算法二:通用 kSum(含 2Sum 双指针)
      • 复杂度
      • 关键细节
      • 代码实现要点
    • 完整题解代码

18. 四数之和

题目描述

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

  • 0 <= a, b, c, d < n
  • a、b、c 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[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 = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

提示:

  • 1 <= nums.length <= 200
  • -10^9 <= nums[i] <= 10^9
  • -10^9 <= target <= 10^9

解题思路

本题是“kSum”系列的典型代表。最直接的思路是:

  • 先对数组排序
  • 固定两个数,用双指针在剩余区间内查找另外两个数(3重循环 + 双指针)
  • 通过跳过重复元素与剪枝优化,保证不重复且加速

此外,还可以抽象成通用的 kSum 递归框架:当 k==2 时用双指针解决,否则固定一个元素,递归解决 (k-1)Sum。

算法一:排序 + 双指针(推荐)

  • 排序后,外层两重循环固定 i、j
  • 内层用左右指针 left、right 搜索两数和,使四数之和为 target
  • 跳过重复元素(i、j、left、right 层面)避免重复解
  • 剪枝:用最小可能和/最大可能和与 target 比较,提前 break/continue
flowchart TDA[排序nums] --> B[i从0到n-4]B --> C{去重/剪枝}C -->|不满足| BC --> D[j从i+1到n-3]D --> E{去重/剪枝}E -->|不满足| DE --> F[left=j+1,right=n-1]F --> G{left<right?}G -->|否| DG --> H[sum=nums[i]+nums[j]+nums[left]+nums[right]]H --> I{sum==target?}I -->|是| J[加入解并去重移动]I -->|sum<target| K[left++]I -->|sum>target| L[right--]J --> GK --> GL --> G

算法二:通用 kSum(含 2Sum 双指针)

  • 排序
  • kSum(nums,k,start,target):
    • 若 k==2,用双指针在区间 [start,n) 里求两数和为 target 的所有解
    • 否则,从 start 枚举 i,跳过重复元素,并递归 kSum(nums,k-1,i+1,target-nums[i])
  • 结合最小/最大可能和剪枝
flowchart TDA[sort(nums)] --> B[kSum(nums,4,0,target)]B --> C{k==2?}C -->|是| D[2Sum 双指针]C -->|否| E[for i from start to n-k]E --> F{跳过重复}F --> EE --> G[递归 kSum(k-1,i+1,target-nums[i])]G --> H[前缀拼接nums[i]并收集]H --> E

复杂度

  • 排序 + 双指针:时间 O(n^3),空间 O(1)(不计结果集)
  • kSum:最坏也为 O(n^{k-1}),本题 k=4 即 O(n^3)

关键细节

  • 去重
    • i>0 且 nums[i]==nums[i-1] 跳过
    • j>i+1 且 nums[j]==nums[j-1] 跳过
    • 命中答案后 left/right 向内移动并跳过相同值
  • 剪枝
    • 对当前固定前缀,比较最小可能和与最大可能和与 target 的关系进行 break/continue
  • long 溢出处理
    • 计算和时转为 int64 避免大数相加溢出

代码实现要点

  1. 先排序,明确单调结构便于双指针
  2. 严格实现四处去重逻辑,保证不重复
  3. 使用 int64 做加法再比较,避免溢出
  4. 通过下界/上界剪枝减少无效搜索

本仓库 18/main.go 中提供:

  • fourSum:排序 + 双指针实现
  • fourSumKSum + kSum:通用 kSum 版本
  • 主函数内含示例用例并输出结果,便于自检

完整题解代码

package mainimport ("fmt""sort"
)// fourSum 经典排序 + 双指针解法
// 时间复杂度: O(n^3)
// 空间复杂度: O(1)(不计结果集)
func fourSum(nums []int, target int) [][]int {res := make([][]int, 0)if len(nums) < 4 {return res}sort.Ints(nums)n := len(nums)t := int64(target)for i := 0; i < n-3; i++ {// 去重: 固定 iif i > 0 && nums[i] == nums[i-1] {continue}// 剪枝: 最小可能和 > target 或 最大可能和 < targetminSum := int64(nums[i]) + int64(nums[i+1]) + int64(nums[i+2]) + int64(nums[i+3])if minSum > t {break}maxSum := int64(nums[i]) + int64(nums[n-1]) + int64(nums[n-2]) + int64(nums[n-3])if maxSum < t {continue}for j := i + 1; j < n-2; j++ {// 去重: 固定 jif j > i+1 && nums[j] == nums[j-1] {continue}// 剪枝min2 := int64(nums[i]) + int64(nums[j]) + int64(nums[j+1]) + int64(nums[j+2])if min2 > t {break}max2 := int64(nums[i]) + int64(nums[j]) + int64(nums[n-1]) + int64(nums[n-2])if max2 < t {continue}left, right := j+1, n-1for left < right {sum := int64(nums[i]) + int64(nums[j]) + int64(nums[left]) + int64(nums[right])if sum == t {res = append(res, []int{nums[i], nums[j], nums[left], nums[right]})// 去重移动lv, rv := nums[left], nums[right]for left < right && nums[left] == lv {left++}for left < right && nums[right] == rv {right--}} else if sum < t {left++} else {right--}}}}return res
}// fourSumKSum 通用 kSum 解法入口(调用 kSum with k=4)
func fourSumKSum(nums []int, target int) [][]int {sort.Ints(nums)return kSum(nums, 4, 0, int64(target))
}// kSum 通用递归解法
// nums 已排序,寻找从 start 开始 k 个数之和为 target 的所有组合
func kSum(nums []int, k int, start int, target int64) [][]int {res := make([][]int, 0)n := len(nums)if k == 2 {// 2Sum 双指针l, r := start, n-1for l < r {s := int64(nums[l]) + int64(nums[r])if s == target {res = append(res, []int{nums[l], nums[r]})lv, rv := nums[l], nums[r]for l < r && nums[l] == lv {l++}for l < r && nums[r] == rv {r--}} else if s < target {l++} else {r--}}return res}// 剪枝: 若最小可能和或最大可能和不满足,直接返回if start >= n {return res}minSum := int64(0)for i := 0; i < k; i++ {if start+i >= n {return res}minSum += int64(nums[start+i])}maxSum := int64(0)for i := 0; i < k; i++ {if n-1-i < start {return res}maxSum += int64(nums[n-1-i])}if minSum > target || maxSum < target {return res}for i := start; i <= n-k; i++ {if i > start && nums[i] == nums[i-1] {continue}// 递归找 (k-1)Sumpartial := kSum(nums, k-1, i+1, target-int64(nums[i]))for _, comb := range partial {res = append(res, append([]int{nums[i]}, comb...))}}return res
}func main() {// 示例 1nums1 := []int{1, 0, -1, 0, -2, 2}target1 := 0ans1 := fourSum(nums1, target1)fmt.Printf("示例1(双指针): nums=%v target=%d\n结果: %v\n\n", nums1, target1, ans1)// 示例 2nums2 := []int{2, 2, 2, 2, 2}target2 := 8ans2 := fourSum(nums2, target2)fmt.Printf("示例2(双指针): nums=%v target=%d\n结果: %v\n\n", nums2, target2, ans2)// 通用 kSum 版本对比ans1k := fourSumKSum(nums1, target1)ans2k := fourSumKSum(nums2, target2)fmt.Printf("示例1(kSum): %v\n示例2(kSum): %v\n\n", ans1k, ans2k)// 其他用例nums3 := []int{0, 0, 0, 0}target3 := 0fmt.Printf("全零用例: %v\n结果: %v\n\n", nums3, fourSum(nums3, target3))nums4 := []int{-3, -1, 0, 2, 4, 5}target4 := 2fmt.Printf("混合用例: %v target=%d\n结果: %v\n", nums4, target4, fourSum(nums4, target4))
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919602.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919602.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言入门(10)-数组

访问数组元素&#xff1a;数组中的每个元素都可以通过“[]”和一个从0开始的索引进行访问数组的长度可由内置函数len来确定。在声明数组时&#xff0c;未被赋值元素的值是对应类型的零值。下面看一个例子package mainfunc main(){var planets [8]stringplanets[0] "Mercu…

为什么经过IPSec隧道后HTTPS会访问不通?一次隧道环境下的实战分析

在运维圈子里&#xff0c;大家可能都遇到过这种奇怪的问题&#xff1a;浏览器能打开 HTTP 网站&#xff0c;但一换成 HTTPS&#xff0c;页面就死活打不开。前段时间&#xff0c;我们就碰到这么一个典型案例。故障现象某公司系统在 VPN 隧道里访问 HTTPS 服务&#xff0c;结果就…

【Linux系统】进程信号:信号的产生和保存

上篇文章我们介绍了Syetem V IPC的消息队列和信号量&#xff0c;那么信号量和我们下面要介绍的信号有什么关系吗&#xff1f;其实没有关系&#xff0c;就相当于我们日常生活中常说的老婆和老婆饼&#xff0c;二者并没有关系1. 认识信号1.1 生活角度的信号解释&#xff08;快递比…

WEB服务器(静态/动态网站搭建)

简介 名词:HTML(超文本标记语言),网站(多个网页组成一台网站),主页,网页,URL(统一资源定位符) 网站架构:LAMP(linux(系统)+apache(服务器程序)+mysql(数据库管理软件)+php(中间软件)) 静态站点 Apache基础 Apache官网:www.apache.org 软件包名称:…

开发避坑指南(29):微信昵称特殊字符存储异常修复方案

异常信息 Cause: java.sql.SQLException: Incorrect string value: \xF0\x9F\x8D\x8B\xE5\xBB... for column nick_name at row 1异常背景 抽奖大转盘&#xff0c;抽奖后需要保存用户抽奖记录&#xff0c;用户再次进入游戏时根据抽奖记录判断剩余抽奖机会。保存抽奖记录时需要…

leetcode-python-242有效的字母异位词

题目&#xff1a; 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的 字母异位词。 示例 1: 输入: s “anagram”, t “nagaram” 输出: true 示例 2: 输入: s “rat”, t “car” 输出: false 提示: 1 < s.length, t.length < 5 * 104 s 和 t 仅…

【ARM】Keil MDK如何指定单文件的优化等级

1、 文档目标解决在MDK中如何对于单个源文件去设置优化等级。2、 问题场景在正常的项目开发中&#xff0c;我们通常都是针对整个工程去做优化&#xff0c;相当于整个工程都是使用一个编译器优化等级去进行的工程构建。那么在一些特定的情况下&#xff0c;工程师需要保证我的部分…

零基础学Java第二十二讲---异常(2)

续接上一讲 目录 一、异常的处理&#xff08;续&#xff09; 1、异常的捕获-try-catch捕获并处理异常 1.1关于异常的处理方式 2、finally 3、异常的处理流程 二、自定义异常类 1、实现自定义异常类 一、异常的处理&#xff08;续&#xff09; 1、异常的捕获-try-catch捕…

自建开发工具IDE(一)之拖找排版—仙盟创梦IDE

自建拖拽布局排版在 IDE 中的优势及初学者开发指南在软件开发领域&#xff0c;用户界面&#xff08;UI&#xff09;的设计至关重要。自建拖拽布局排版功能为集成开发环境&#xff08;IDE&#xff09;带来了诸多便利&#xff0c;尤其对于初学者而言&#xff0c;是踏入开发领域的…

GitHub Copilot - GitHub 推出的AI编程助手

本文转载自&#xff1a;GitHub Copilot - GitHub 推出的AI编程助手 - Hello123工具导航。 ** 一、GitHub Copilot 核心定位 GitHub Copilot 是由 GitHub 与 OpenAI 联合开发的 AI 编程助手&#xff0c;基于先进大语言模型实现代码实时补全、错误检测及文档生成&#xff0c;显…

基于截止至 2025 年 6 月 4 日,在 App Store 上进行交易的设备数据统计,iOS/iPadOS 各版本在所有设备中所占比例详情

iOS 和 iPadOS 使用情况 基于截止至 2025 年 6 月 4 日&#xff0c;在 App Store 上进行交易的设备数据统计。 iPhone 在过去四年推出的设备中&#xff0c;iOS 18 的普及率达 88。 88% iOS 188% iOS 174% 较早版本 所有的设备中&#xff0c;iOS 18 的普及率达 82。 82% iOS 189…

云计算-k8s实战指南:从 ServiceMesh 服务网格、流量管理、limitrange管理、亲和性、环境变量到RBAC管理全流程

介绍 本文是一份 Kubernetes 与 ServiceMesh 实战操作指南,涵盖多个核心功能配置场景。从 Bookinfo 应用部署入手,详细演示了通过 Istio 创建 Ingress Gateway 实现外部访问,以及基于用户身份、请求路径的服务网格路由规则配置,同时为应用微服务设置了默认目标规则。 还包…

Vue 3项目中的路由管理和状态管理系统

核心概念理解 1. 整体架构关系 这两个文件构成了Vue应用的导航系统和状态管理系统&#xff1a; Router&#xff08;路由&#xff09;&#xff1a;控制页面跳转和URL变化Store&#xff08;状态&#xff09;&#xff1a;管理全局数据和用户状态两者协同工作实现权限控制 2. 数据流…

Linux Capability 解析

文章目录1. 权限模型演进背景2. Capability核心原理2.1 能力单元分类2.2 进程三集合2.3 文件系统属性3. 完整能力单元表4. 高级应用场景4.1 能力边界控制4.2 编程控制4.3 容器安全5. 安全实践建议6. 潜在风险提示 1. 权限模型演进背景 在传统UNIX权限模型中&#xff0c;采用二进…

vue 监听 sessionStorage 值的变化

<template><div class"specific-storage-watcher"><h3>仅监听 userId 变化</h3><p>当前 userId: {{ currentUserId }}</p><p v-if"changeRecord">最近变化: {{ changeRecord }}</p><button click"…

IDEA:控制台中文乱码

目录一、设置字符编码为 UTF-8一、设置字符编码为 UTF-8 点击菜单 File -> settings -> Eitor -> File Encodings , 将字符全局编码、项目编码、配置文件编码统一设置为UTF-8, 然后点击 Apply 应用设置&#xff0c;点击 OK 关闭对话框:

[Sql Server]特殊数值计算

任务一&#xff1a;求下方的Num列的中值:参考代码:use Test go SELECT DISTINCTPERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY Num) over()AS MedianSalary FROM MedianTest;任务二: 下方表中,每个选手有多个评委打分&#xff0c;求每个选手的评委打分中值。参考代码:use Tes…

01-Docker概述

Docker 的主要目标是:Build, Ship and Run Any App, Anywhere,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的 APP 及其运行环境能做到一次镜像,处处运行。 Docker 运行速度快的原因: 由于 Docker 不需要 Hypervisor(虚拟机)实现硬件资源虚拟化…

Laravel中如何使用php-casbin

一、&#x1f680; 安装和配置 1. 安装包 composer require casbin/laravel-authz2. 发布配置文件 php artisan vendor:publish这会生成两个重要文件&#xff1a; config/lauthz.php - 主配置文件config/lauthz-rbac-model.conf - RBAC 模型配置文件 3. 运行数据库迁移 php…

算法题打卡力扣第4题:寻找两个正序数组的中位数(hard))

题目描述 提示&#xff1a; nums1.length m nums2.length n 0 < m < 1000 0 < n < 1000 1 < m n < 2000 -106 < nums1[i], nums2[i] < 106 解答思路 我的想法是先归并排序再直接返回下标中位数 代码 double findMedianSortedArrays(int* nums1,…