【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==3n
  • 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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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…