K次取反后最大化的数组和

力扣题目链接(opens new window)

给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次。(我们可以多次选择同一个索引 i。)

以这种方式修改数组后,返回数组可能的最大和。

示例 1:

  • 输入:A = [4,2,3], K = 1
  • 输出:5
  • 解释:选择索引 (1,) ,然后 A 变为 [4,-2,3]。

示例 2:

  • 输入:A = [3,-1,0,2], K = 3
  • 输出:6
  • 解释:选择索引 (1, 2, 2) ,然后 A 变为 [3,1,0,2]。

示例 3:

  • 输入:A = [2,-3,-1,5,-4], K = 2
  • 输出:13
  • 解释:选择索引 (1, 4) ,然后 A 变为 [2,3,-1,5,4]。

提示:

  • 1 <= A.length <= 10000
  • 1 <= K <= 10000
  • -100 <= A[i] <= 100

思路

要用贪心的方式去想解决方法

一个直观的想法是:

局部最优:让绝对值大的负数变为正数

全局最优:让数组元素的和最大

要实现上面的想法,需要先将数组进行排序(注意,此处排序包括负数,所以得自定义排序规则)

排完序之后就可以从小到大将负数反转为正数

但如果出现以下情况:(数组已经排序)

{-1, -2, -3, 5, 8}, K = 4 ---->{1, 2, 3, 5, 8}, K = 1

即将所有负数从小到大反转之后,K还有剩余

此时问题就变成了:在一个正整数数组中如何取反K次以获得最大数组元素和

那么这里又要制定新的贪心策略

局部最优:找到数组中数值最小的正整数进行反转(这样对整体影响最小)

全局最优:让数组元素的和最大

题外话:自定义sort排序规则

参考:https://www.cnblogs.com/Daniel-lmz/p/16452975.html

sort(iterator beg, iterator end, _Pred);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// _Pred 谓词(即cmp,排序的方式

[first****,last)(一定要注意这里的区间是左闭又开)区间内数据根据cmp的方式进行排序。也可以不写第三个参数,此时按默认排序,从小到大进行排序。

例子:自定义sort的排序规则(从大到小),默认是从小到大

static bool cmp(int a,int b){
     return b < a;
}
sort(a,a+n,cmp);

代码

步骤

依据上述思路可以总结出以下步骤:

1、先自定义排序规则,对含有负数的数组进行排序(自定义规则是:按照绝对值大小进行排序

例子:{-3, -1, 0, 2}------->{-3, 2, -1, 0}

2、排好之后,遍历数组,从小到大将负数元素反转为正数,同时K--

3、如果负数已经被反转完,K仍有剩余,则不断反转当前数组中最小的正数,直到用完K

4、求出当前数组的和,返回

class Solution {
static bool cmp(int a, int b) {
    return abs(a) > abs(b);
}

public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end(), cmp);//对含有负数的数组进行排序
        for(int i = 0; i < nums.size(); ++i){//遍历数组,从小到大将负数元素反转为正数
            if(nums[i] < 0 && k > 0){//第一处贪心
                nums[i] = -nums[i];
                k--;
            } 
        }//如果负数已经被反转完,K仍有剩余,则不断反转当前数组中最小的正数(就是数组最后一个数),直到用完K
        if(k % 2 == 1){//第二处贪心
            nums[nums.size() - 1] *= -1;//只在k为奇数时取反,因为偶数取反还是正数,没必要进行操作
        }
        //求数组和
        int res = 0;
        for(int num : nums) res += num;
        return res;
    }
};
注意点
1、自定义sort的规则

在写cmp函数时,记得要用static修饰(参考本题题解)

2、反转亦有优化

当我们实现第二处贪心的逻辑时,需要对数组中的最小正数进行不断反转以消耗掉K值

此处是可以优化的

一个正数,翻转偶数次它还是正数

所以只需要在K为奇数的时候进行反转操作即可,这样可以省去偶数次反转操作带来的额外性能开支

3、for循环时别忘了可以使用增强for循环