当前位置: 首页 > news >正文

贪心算法专题(七):负负得正的极致——「K 次取反后最大化数组和」

哈喽各位,我是前端小L。

欢迎来到贪心算法专题第七篇!

题目很简单:给你一个整数数组 nums 和一个整数 k。你必须执行 k 次取反操作(可以选择同一个下标)。最后,让数组的总和最大。

直觉告诉我们:

  1. 负数是宝藏:把负数变成正数,总和会蹭蹭往上涨。

  2. 绝对值越大越好:把-100变成100,比把-1变成1划算多了。

  3. 正数是累赘:如果负数都变完了,k还没用完,我们不得不把正数变回负数。这时候要选最小的正数,因为-1总比-100造成的损失小。

力扣 1005. K 次取反后最大化数组和

https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/

题目分析:

  • 输入nums数组,k次操作。

  • 目标:最大数组和。

  • 规则:必须操作 K 次。

例子:nums = [2, -3, -1, 5, -4],k = 2

  • 第一次:肯定选-4(绝对值最大),变成4。数组:[2, -3, -1, 5, 4]

  • 第二次:肯定选-3(剩下里绝对值最大的),变成3。数组:[2, 3, -1, 5, 4]

  • 结果:2+3-1+5+4 = 13

核心思维:两次贪心

我们可以把这个过程分为两个阶段:

  1. 第一阶段贪心(处理负数)

    • 策略:优先把绝对值最大的负数变成正数。

    • 这就要求我们按绝对值大小对数组进行排序。

    • 例如[-4, -3, -1, 2, 5](按绝对值降序是5, -4, -3, 2, -1,或者我们直接处理负数逻辑)。

  2. 第二阶段贪心(处理多余的 K)

    • 如果负数都变完了,k还是正数(且是奇数)。

    • 策略:找一个当前数值最小的元素进行取反。

    • 因为这时候数组全是正数(或0),取反一定会减少总和。为了让总和减少得最少,必须选最小的那个数。

算法流程

为了完美配合这两种贪心策略,我们可以使用一个巧妙的排序方法:按绝对值从大到小排序

  1. 排序:将数组按照绝对值从大到小排序。

    • 原数组:[2, -3, -1, 5, -4]

    • 排序后:[5, -4, -3, 2, -1](绝对值:5, 4, 3, 2, 1)

  2. 第一轮遍历

    • 从头往后走。如果遇到负数k > 0,就把它变正,k--

    • 此时数组变为:[5, 4, 3, 2, -1](-4-3变了)。

    • 此时k可能还有剩余。

  3. 第二轮处理

    • 如果k此时是偶数,不需要操作(对同一个数取反两次等于没变)。

    • 如果k奇数,必须再操作一次。

    • 因为我们是按绝对值从大到小排序的,所以数组的最后一个元素,一定是绝对值最小的(也就是数值最小的非负数)。

    • 直接对nums[n-1]取反。

  4. 求和

代码实现 (C++)

C++

#include <vector> #include <algorithm> // for sort, abs #include <numeric> // for accumulate using namespace std; class Solution { // 自定义比较函数:按绝对值从大到小排序 static bool cmp(int a, int b) { return abs(a) > abs(b); } public: int largestSumAfterKNegations(vector<int>& nums, int k) { // 1. 按绝对值从大到小排序 sort(nums.begin(), nums.end(), cmp); // 2. 第一步贪心:把绝对值大的负数变成正数 for (int i = 0; i < nums.size(); i++) { if (nums[i] < 0 && k > 0) { nums[i] *= -1; k--; } } // 3. 第二步贪心:如果 k 还没用完(且是奇数) // 此时数组里全是正数(或者0),且最后一个元素绝对值最小 if (k % 2 == 1) { nums[nums.size() - 1] *= -1; } // 4. 求和 int sum = 0; for (int num : nums) { sum += num; } return sum; } };

深度辨析:为什么要按绝对值排序?

如果我们只按普通升序排序[-4, -3, -1, 2, 5]

  • 处理完负数后,数组变成[4, 3, 1, 2, 5]

  • 如果此时k剩 1,我们需要找最小的数。

  • 在普通排序后的数组里,最小的数1在中间位置,找起来比较麻烦(需要再次遍历或排序)。

而按绝对值降序排序[5, -4, -3, 2, -1]

  • 处理完后变成[5, 4, 3, 2, -1](假设 -1 没被翻,或者翻了变成 1)。

  • 无论如何,绝对值最小的那个数,永远在数组的末尾

  • 这让第二步处理变得只有 $O(1)$ 的复杂度。

深度复杂度分析

  • 时间复杂度:O(N log N)

    • 主要消耗在排序上。

    • 遍历和求和都是 $O(N)$。

  • 空间复杂度:O(1)

    • 如果是 C++ 的sort,通常需要 $O(\log N)$ 的栈空间,但不需要额外数组。

总结:贪心的“优先级”

这道题教会了我们如何建立贪心优先级

  1. 最高优先级:消除“大负数”(收益最大)。

  2. 次高优先级:消除“小负数”。

  3. 最低优先级(迫不得已):牺牲“小正数”(损失最小)。

通过排序,我们将这些优先级线性化,从而一趟扫描解决问题。


下一题预告:加油站

接下来我们要挑战贪心算法中最经典、也最容易让人懵圈的题目——“加油站”

  • 你有一个油箱无限大的车,想绕环形公路跑一圈。

  • 每个加油站有油gas[i],去下一站消耗cost[i]

  • 你需要找一个起点,保证能跑完一圈。

贪心策略非常神奇:如果你尝试从 A 跑到 B,发现油不够了,那么A 和 B 之间的所有站点都不可能作为起点。为什么?

准备好发车了吗?下期见!

http://www.jsqmd.com/news/159053/

相关文章:

  • 2025工程塑料加工企业TOP5实力榜:沧州盛亮塑料公司概况及深度测评 - myqiye
  • 2025年靠谱工业拖链定制服务排行榜,德斯普拖链的定制服务怎么样 - 工业推荐榜
  • 网站响应速度监控利器:GoAccess时间分析功能深度解析
  • Cider终极指南:简单快速解锁跨平台Apple Music新体验
  • 【高斯泼溅】3DGS城市模型从“硬盘杀手”到“轻盈舞者”?看我们如何实现14倍压缩
  • Cocos Creator游戏资源终极保护方案:从入门到精通的完整指南
  • 如何为Windows 11虚拟机打造铜墙铁壁?VMware Workstation 18技术预览版深度评测
  • Jupytext完全实战手册:从安装到精通的全流程指南
  • 第08章-Excel图表与图形
  • Soundux声板应用终极指南:快速上手跨平台音效管理
  • Visual C++ 6.0在Windows 11系统下的完整配置指南
  • 金仓数据库成功支撑某头部基金TA系统Oracle迁移替换
  • Visual C++ 6.0 Windows 7兼容版:经典开发环境的完美解决方案 [特殊字符]
  • kgateway重新定义AI代理通信:云原生网关的技术革新之路
  • 第07章-Excel数据验证与保护
  • 5分钟掌握C++ UUID生成:stduuid跨平台实战指南
  • 现代前端组件库展示与测试方案深度解析
  • 2025 GEO营销服务TOP5权威推荐:甄选高性价比靠谱服务商助力企业获客增长 - 工业品牌热点
  • 蓝绿部署下的自动化测试验证:构建高可靠软件交付的核心引擎
  • 收藏!彻底搞懂Transformer:不用数学公式,只用生活案例讲透AI大模型原理
  • 编写完MCP服务后,我对AI的看法
  • 探索conform.nvim:如何构建高效的Neovim插件协同工作流
  • Blender材质库终极指南:5分钟掌握专业级材质应用
  • 阅读3.0书源优化完全指南:从资源匮乏到高效管理
  • MeterSphere变量优先级:3层架构解密与实战避坑指南
  • 2025年标识标牌生产厂家Top5 - 2025年品牌推荐榜
  • 2026年自媒体人必备!给视频去水印工具排行榜大揭秘! - 资讯焦点
  • 收藏!深入理解Agent:从入门到架构师的能力分级指南
  • 测试左移:在CI阶段预防缺陷的实践
  • 力扣刷题:Z字型变换