营销型网站的设计框架,幼教网站建设分析,网站建设区域代理,平台戚里带崇墉哈喽各位#xff0c;我是前端小L。
欢迎来到贪心算法专题第七篇#xff01;
题目很简单#xff1a;给你一个整数数组 nums 和一个整数 k。你必须执行 k 次取反操作#xff08;可以选择同一个下标#xff09;。最后#xff0c;让数组的总和最大。
直觉告诉我们#xf…哈喽各位我是前端小L。欢迎来到贪心算法专题第七篇题目很简单给你一个整数数组 nums 和一个整数 k。你必须执行 k 次取反操作可以选择同一个下标。最后让数组的总和最大。直觉告诉我们负数是宝藏把负数变成正数总和会蹭蹭往上涨。绝对值越大越好把-100变成100比把-1变成1划算多了。正数是累赘如果负数都变完了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]。结果23-154 13。核心思维两次贪心我们可以把这个过程分为两个阶段第一阶段贪心处理负数策略优先把绝对值最大的负数变成正数。这就要求我们按绝对值大小对数组进行排序。例如[-4, -3, -1, 2, 5]按绝对值降序是5, -4, -3, 2, -1或者我们直接处理负数逻辑。第二阶段贪心处理多余的 K如果负数都变完了k还是正数且是奇数。策略找一个当前数值最小的元素进行取反。因为这时候数组全是正数或0取反一定会减少总和。为了让总和减少得最少必须选最小的那个数。算法流程为了完美配合这两种贪心策略我们可以使用一个巧妙的排序方法按绝对值从大到小排序。排序将数组按照绝对值从大到小排序。原数组[2, -3, -1, 5, -4]排序后[5, -4, -3, 2, -1](绝对值5, 4, 3, 2, 1)第一轮遍历从头往后走。如果遇到负数且k 0就把它变正k--。此时数组变为[5, 4, 3, 2, -1](-4和-3变了)。此时k可能还有剩余。第二轮处理如果k此时是偶数不需要操作对同一个数取反两次等于没变。如果k是奇数必须再操作一次。因为我们是按绝对值从大到小排序的所以数组的最后一个元素一定是绝对值最小的也就是数值最小的非负数。直接对nums[n-1]取反。求和。代码实现 (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(vectorint 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)$ 的栈空间但不需要额外数组。总结贪心的“优先级”这道题教会了我们如何建立贪心优先级最高优先级消除“大负数”收益最大。次高优先级消除“小负数”。最低优先级迫不得已牺牲“小正数”损失最小。通过排序我们将这些优先级线性化从而一趟扫描解决问题。下一题预告加油站接下来我们要挑战贪心算法中最经典、也最容易让人懵圈的题目——“加油站”。你有一个油箱无限大的车想绕环形公路跑一圈。每个加油站有油gas[i]去下一站消耗cost[i]。你需要找一个起点保证能跑完一圈。贪心策略非常神奇如果你尝试从 A 跑到 B发现油不够了那么A 和 B 之间的所有站点都不可能作为起点。为什么准备好发车了吗下期见