【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
英文地址,請注明出處:http://en.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,…