【LeetCode 2163. 刪除元素后和的最小差值】解析

目錄

  • LeetCode中國站原文
  • 原始題目
    • 題目描述
    • 示例 1:
    • 示例 2:
    • 提示:
  • 講解
  • 分割線的藝術:前后綴分解與優先隊列的完美邂逅
    • 第一部分:算法思想 —— “分割線”與前后綴分解
      • 1. 想象一條看不見的“分割線”
      • 2. 前后綴分解:預計算的威力
    • 第二部分:實現工具 —— 優先隊列(堆)
      • 1. 計算 `prefixMinSum` (前綴最小和)
      • 2. 計算 `suffixMaxSum` (后綴最大和)
    • 第三部分:代碼實現 —— 組裝最終答案
      • 代碼精講

LeetCode中國站原文

https://leetcode.cn/problems/minimum-difference-in-sums-after-removal-of-elements/

原始題目

題目描述

給你一個下標從 0 開始的整數數組 nums ,它包含 3 * n 個元素。

你可以從 nums 中刪除 恰好 n元素,剩下的 2 * n 個元素將會被分成兩個 相同大小 的部分。

  • 前面 n 個元素屬于第一部分,它們的和記為 sumfirst
  • 后面 n 個元素屬于第二部分,它們的和記為 sumsecond

兩部分和的 差值 記為 sumfirst - sumsecond

請你返回刪除 n 個元素之后,剩下兩部分和的 差值的最小值 是多少。

示例 1:

輸入:nums =
輸出:-1
解釋:n = 1。刪除 nums = 3,數組變為 。差值為 1 - 2 = -1。

示例 2:

輸入:nums =
輸出:1
解釋:n = 2。刪除 nums = 9 和 nums = 1,剩下 。差值為 (7+5) - (8+3) = 1。

提示:

  • nums.length==3?nnums.length == 3 * nnums.length==3?n
  • 1<=n<=1051 <= n <= 10^51<=n<=105
  • 1<=nums[i]<=1051 <= nums[i] <= 10^51<=nums[i]<=105

講解

分割線的藝術:前后綴分解與優先隊列的完美邂逅

大家好!今天我們要拆解的,是一道極具思維含量與工程美感的題目——LeetCode 2163. 刪除元素后和的最小差值。

這道題的目標是最小化 sumfirst - sumsecond。要達到這個目的,我們的策略必須是雙管齊下:

  1. sumfirst 盡可能小
  2. sumsecond 盡可能大

但問題在于,我們刪除的 n 個元素會同時影響這兩個部分的選擇,如何找到那個最佳的平衡點呢?答案就藏在“分割線”的移動之中。

第一部分:算法思想 —— “分割線”與前后綴分解

1. 想象一條看不見的“分割線”

我們最終要留下 2n 個元素,前 n 個歸第一部分,后 n 個歸第二部分。這 2n 個元素在原數組 nums 中保持著它們的相對順序。

我們可以想象,在原數組 nums 中,存在一條看不見的**“分割線”,它將 nums 分成了前后兩個部分:一個前綴和一個后綴**。

  • sumfirstn 個元素,全部來自于這條分割線左邊的前綴
  • sumsecondn 個元素,全部來自于這條分割線右邊的后綴
分割后的選擇
原數組 nums (3n)
選出 最小的 n 個
組成 sumfirst
前綴 nums[0...i]
選出 最大的 n 個
組成 sumsecond
后綴 nums[i+1...3n-1]
3n-1
...
i+1
i
...
A

分割線可以放在哪里?

  • 為了能從前綴中選出 n 個數,前綴的長度至少為 n。所以分割線最早可以在索引 n-1 之后。
  • 為了能從后綴中選出 n 個數,后綴的長度至少為 n。所以分割線最晚可以在索引 2n-1 之后。

我們的核心思路就是:遍歷所有可能的分割線位置,對于每一個位置,都計算出最優的 sumfirst - sumsecond,然后取其中的最小值。

2. 前后綴分解:預計算的威力

如果每次移動分割線,我們都重新計算前綴的最小和與后綴的最大和,那效率太低了。解決這個問題的鑰匙,就是**“前后綴分解”**——提前把所有可能需要的信息都算好。

我們需要兩個“信息表”:

  1. prefixMinSum[i]:存儲 nums[0...i] 這個前綴中,最小的 n 個元素之和
  2. suffixMaxSum[i]:存儲 nums[i...3n-1] 這個后綴中,最大的 n 個元素之和

只要我們能高效地構建出這兩個表,問題就迎刃而解了。

第二部分:實現工具 —— 優先隊列(堆)

如何高效地“在一堆動態變化的數中,維護前K大/小的元素之和”?這正是優先隊列(Priority Queue,即堆) 的拿手好戲。

1. 計算 prefixMinSum (前綴最小和)

我們需要一個大頂堆 (Max-Heap),它的作用像一個“VIP室”,容量只有 n

  1. 我們從左到右遍歷 nums
  2. 每遇到一個數,都讓它嘗試進入“VIP室”。
  3. 如果“VIP室”還沒滿(不足n人),新來的數直接進入。
  4. 如果“VIP室”滿了,新來的數就要和室內的“最大塊頭”(堆頂元素)比一下。如果新來的數比它小,說明新來的更“VIP”(因為我們要找最小的),就把那個“最大塊頭”請出去,讓新來的數進來。
  5. 我們始終維護“VIP室”內所有數的總和。當遍歷到索引 i 時,這個總和就是 nums[0...i] 中最小的 n 個元素之和。
flowchart TDA[初始化一個大小為 n 的<b>大頂堆</b> 和 sum=0] --> B{從左到右遍歷 nums};B --> C{將 nums[i] 加入堆和 sum};C --> D{堆的大小是否 > n?};D -- 是 --> E[sum -= 堆頂元素<br>從堆中移除堆頂元素];D -- 否 --> F;E --> F;F --> G{i 是否 >= n-1?};G -- 是 --> H[記錄 prefixMinSum[i] = sum];G -- 否 --> B;H --> B;

2. 計算 suffixMaxSum (后綴最大和)

這個過程完全對稱。我們需要一個小頂堆 (Min-Heap),容量同樣為 n

  1. 我們從右到左遍歷 nums
  2. 每遇到一個數,讓它和“VIP室”里的“最小塊頭”(堆頂元素)比。如果新來的數比它大,就請“最小塊頭”出去,讓新來的進來。
  3. 這樣,我們就能始終維護后綴中最大的 n 個元素之和。

第三部分:代碼實現 —— 組裝最終答案

有了預計算好的 prefixMinSumsuffixMaxSum 數組,最后的組裝就非常簡單了。

import java.util.PriorityQueue;
import java.util.Collections;public class Solution {public long minimumDifference(int[] nums) {int n = nums.length / 3;// ======================= 步驟 1: 計算前綴最小和 =======================// prefixMinSum[i] = nums[0...i] 中,n個最小元素的和long[] prefixMinSum = new long[3 * n];// 使用大頂堆來動態維護n個最小的元素PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());long currentSum = 0;for (int i = 0; i < 3 * n; i++) {currentSum += nums[i];maxHeap.add(nums[i]);if (maxHeap.size() > n) {currentSum -= maxHeap.poll(); // 移除最大的那個}if (maxHeap.size() == n) {prefixMinSum[i] = currentSum;}}// ======================= 步驟 2: 計算后綴最大和 =======================// suffixMaxSum[i] = nums[i...3n-1] 中,n個最大元素的和long[] suffixMaxSum = new long[3 * n];// 使用小頂堆來動態維護n個最大的元素PriorityQueue<Integer> minHeap = new PriorityQueue<>();currentSum = 0;for (int i = 3 * n - 1; i >= 0; i--) {currentSum += nums[i];minHeap.add(nums[i]);if (minHeap.size() > n) {currentSum -= minHeap.poll(); // 移除最小的那個}if (minHeap.size() == n) {suffixMaxSum[i] = currentSum;}}// ======================= 步驟 3: 遍歷分割點,尋找最小差值 =======================long minDifference = Long.MAX_VALUE;// 分割線在索引 i 和 i+1 之間// i 的范圍是從 n-1 到 2n-1for (int i = n - 1; i < 2 * n; i++) {long sumFirst = prefixMinSum[i];       // 前綴 nums[0...i] 的最小n和long sumSecond = suffixMaxSum[i + 1];  // 后綴 nums[i+1...3n-1] 的最大n和minDifference = Math.min(minDifference, sumFirst - sumSecond);}return minDifference;}
}

代碼精講

  1. 數據類型:由于數字和 n 的范圍較大,和可能會超出 int 的范圍,因此我們全程使用 long 來存儲和,避免溢出。
  2. 大頂堆的創建:Java的 PriorityQueue 默認是小頂堆,創建大頂堆需要傳入 Collections.reverseOrder()
  3. 循環范圍:計算前綴和后綴的循環覆蓋了整個數組。但最后尋找答案的循環,分割點 i 的范圍是從 n-12*n-1(注意不是 < 2*n),這保證了前綴和后綴都有至少 n 個元素可供選擇。

通過這“三步走”戰略,我們把一個復雜的、看似需要回溯搜索的問題,轉化成了一個結構清晰、邏輯流暢的動態規劃+數據結構優化問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/89494.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/89494.shtml
英文地址,請注明出處:http://en.pswp.cn/web/89494.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

控制鼠標和鍵盤

控制鼠標和鍵盤的Python庫Python中有多個庫可以用于控制鼠標和鍵盤&#xff0c;常用的包括pyautogui、pynput、keyboard和mouse等。這些庫提供了模擬用戶輸入的功能&#xff0c;適用于自動化測試、GUI操作等場景。使用pyautogui控制鼠標pyautogui是一個跨平臺的庫&#xff0c;支…

基于按鍵開源MultiButton框架深入理解代碼框架(二)(指針的深入理解與應用)

文章目錄2、針對該開源框架理解3、分析代碼3.1 再談指針、數組、數組指針3.2 繼續分析源碼2、針對該開源框架理解 在編寫按鍵模塊的框架中&#xff0c;一定要先梳理按鍵相關的結構體、枚舉等變量。這些數據是判斷按鍵按下、狀態跳轉、以及綁定按鍵事件的核心。 這一部分定義是…

web前端渡一大師課 CSS屬性計算過程

你是否了解CSS 的屬性計算過程呢? <body> <h1>這是一個h1標題</h1> </body> 目前我們沒有設置改h1的任何樣式,但是卻能看到改h1有一定的默認樣式,例如有默認的字體大小,默認的顏色 那么問題來了,我們這個h1元素上面除了有默認字體大小,默認顏色等…

Redis高頻面試題:利用I/O多路復用實現高并發

Redis 通過 I/O 多路復用&#xff08;I/O Multiplexing&#xff09;技術實現高并發&#xff0c;這是其單線程模型能夠高效處理大量客戶端連接的關鍵。以下是通俗易懂的解釋&#xff0c;結合 Redis 的工作原理&#xff0c;詳細說明其實現過程。 1. 什么是 I/O 多路復用&#xff…

爬蟲小知識(二)網頁進行交互

一、提交信息到網頁 1、模塊核心邏輯 “提交信息到網頁” 是網絡交互關鍵環節&#xff0c;借助 requests 庫的 post() 函數&#xff0c;能模擬瀏覽器向網頁發數據&#xff08;如表單、文件 &#xff09;&#xff0c;實現信息上傳&#xff0c;讓我們能與網頁背后的服務器 “溝通…

WPF學習(五)

文章目錄一、FileStream和StreamWriter理解1.1、具體關系解析1.2、類比理解1.3、總結1.4、示例代碼1.5、 WriteLine()和 Write&#xff08;&#xff09;的區別1.6、 StreamWriter.Close的作用二、一、FileStream和StreamWriter理解 在 C# 中&#xff0c;StreamWriter 和 FileS…

ctf.show-web習題-web2-最簡單的sql注入-flag獲取詳解、總結

解題思路打開靶場既然提示是最簡單的sql注入了&#xff0c;那么直接嘗試永真登錄1 or 11#這里閉合就是簡單的單引號可以看到沒登錄成功&#xff0c;但是有回顯&#xff1a;歡迎你&#xff0c;ctfshowsql注入最喜歡的就是回顯了&#xff01;這題的思路就是靠這個回顯&#xff0c…

upload-labs 靶場通關(1-20)

目錄 Pass-01(JS 繞過) Pass-02(文件類型驗證) Pass-03(黑名單驗證) Pass-04(黑名單驗證.htaccess) Pass-05(大小寫繞過) Pass-06(末尾空格) Pass-07(增加一個.) Pass-08(增加一個::$DATA) Pass-09&#xff08;代碼不嚴謹&#xff09; Pass-10&#xff08;PPHPHP&am…

[附源碼+數據庫+畢業論文]基于Spring+MyBatis+MySQL+Maven+vue實現的酒店預訂管理系統,推薦!

摘 要 使用舊方法對酒店預訂信息進行系統化管理已經不再讓人們信賴了&#xff0c;把現在的網絡信息技術運用在酒店預訂信息的管理上面可以解決許多信息管理上面的難題&#xff0c;比如處理數據時間很長&#xff0c;數據存在錯誤不能及時糾正等問題。 這次開發的酒店預訂管理系…

LSTM入門案例(時間序列預測)| pytorch實現(可復現)

需求 假如我有一個時間序列&#xff0c;例如是前113天的價格數據&#xff08;訓練集&#xff09;&#xff0c;然后我希望借此預測后30天的數據&#xff08;測試集&#xff09;&#xff0c;實際上這143天的價格數據都已經有了。這里為了簡單&#xff0c;每一天的數據只有一個價…

Axure RP 10 預覽顯示“無標題文檔”的空白問題探索【護航版】

1. 安裝情況 官網 Axure RP 10&#xff1a;Download Axure RP 10 - Axure &#xff08;PS&#xff1a;11都出了&#xff09; 版本&#xff1a;10.0.0.3924 激活碼&#xff1a;49bb9513c40444b9bcc3ce49a7a022f9 &#xff08;10/11都可以用&#xff0c;但只嘗試了10&#xff…

基于SpringBoot+Vue的汽車租賃系統(協同過濾算法、騰訊地圖API、支付寶沙盒支付、WebsSocket實時聊天、ECharts圖形化分析)

系統亮點&#xff1a;協同過濾算法、騰訊地圖API、支付寶沙盒支付、WebsSocket實時聊天、ECharts圖形化分析&#xff1b;01系統開發工具與環境搭建—前后端分離架構項目架構&#xff1a;B/S架構運行環境&#xff1a;win10/win11、jdk17前端&#xff1a;技術&#xff1a;框架Vue…

數據結構入門:像整理收納一樣簡單!

在我們生活中&#xff0c;經常會面對這樣的問題&#xff1a; “我要怎么整理我的衣柜&#xff1f;” “電腦里照片太多了&#xff0c;怎么歸類才方便查找&#xff1f;” 其實&#xff0c;程序員也有類似的煩惱。他們不整理衣柜&#xff0c;而是“整理數據”。而這門關于如何“收…

力扣每日一題--2025.7.15

&#x1f4da; 力扣每日一題–2025.7.15 3135. 有效單詞 &#xff08;簡單&#xff09; 大家好&#xff01;今天我們要來聊聊一道有趣的編程題——有效單詞 &#x1f4dd; 題目描述 題目分析 &#x1f4da; 題目要求我們判斷一個字符串是否為有效單詞。有效單詞需要滿足以下…

Mysql數據庫——增刪改查CRUD

文章目錄一、數據庫的基礎命令二、創建表三、增(create)四、查詢&#xff08;retrieve)五、條件查詢&#xff08;where&#xff09;六、修改&#xff08;update&#xff09;七、刪除&#xff08;delete&#xff09;一、數據庫的基礎命令 1.使用客戶端連接服務器 mysql -u root…

關于pytorch虛擬環境及具體bug問題修改

本篇博客包含對于虛擬環境概念的講解和代碼實現過程中相關bug的解決關于虛擬環境我的pytorch虛擬環境在D盤&#xff0c;相應python解釋器也在D盤&#xff08;一起&#xff09;&#xff0c;但是我的pycharm中的項目在C盤&#xff0c;使用的是pytorch的虛擬環境&#xff0c;這是為…

U盤量產工具與性能優化完全指南

本文還有配套的精品資源&#xff0c;點擊獲取 簡介&#xff1a;U盤量產工具是IT行業中的專業軟件&#xff0c;用于批量生產或修復U盤。安國和銀燦是兩個提供U盤量產工具的主控芯片制造商&#xff0c;提供初始化、格式化、分區管理、性能優化、故障修復、個性化定制、固件升級…

Golang http開發實戰:構建RESTful API保姆級教程

目錄 章節1:RESTful API的精髓與Go的Web開發哲學 RESTful API的設計原則 Go的http包核心組件 實戰:第一個RESTful API端點 章節2:設計優雅的RESTful路由 路由設計的注意事項 使用Gorilla Mux實現動態路由 章節3:請求與響應的藝術:解析與格式化 解析請求數據 統一…

UGUI 性能優化系列:第一篇——基礎優化與資源管理

UGUI 性能優化系列&#xff1a;第一篇——基礎優化與資源管理 UGUI 性能優化系列&#xff1a;第二篇——Canvas 與 UI 元素管理 在 Unity 游戲中&#xff0c;用戶界面&#xff08;UI&#xff09;是玩家與游戲交互的核心。然而&#xff0c;不當的 UGUI 使用常常成為游戲性能的…

多端協同的招聘系統源碼開發指南:小程序+APP一體化設計

當下&#xff0c;很多企業選擇搭建屬于自己的多端協同招聘平臺&#xff0c;尤其是中大型人力資源公司、連鎖品牌企業&#xff0c;以及同城服務平臺&#xff0c;更是將“小程序APP”一體化招聘系統視為提升效率、降低用工成本的利器。 今天&#xff0c;筆者將從源碼開發的角度&a…