力扣【数组专题】1005. K 次取反后最大化的数组和

207 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 6 天,点击查看活动详情

题目链接

1005. K 次取反后最大化的数组和 - 力扣(LeetCode)

题目描述

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

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

测试用例

示例 1:

输入: nums = [4,2,3], k = 1
输出: 5
解释: 选择下标 1 ,nums 变为 [4,-2,3]

限制

  • 1 <= nums.length <= 104
  • -100 <= nums[i] <= 100
  • 1 <= k <= 104

题目分析

题目,需要我们为一个包含了正负数的数组进行求和;同时,在求和之前,需要对数组的元素做 k 次取反操作

考虑到数组中的正数和负数参合在一起,那么,对 k 的值,需要分如下几种情况考虑:

  1. k 小于等于数组中负数的个数 m 时,此时,只需要将负数数组中,最小的 k 个值反转并求和即可
  2. k 大于数组中负数的个数 m 时,我们需要将所有的负数反转,并且需要记录下,此时,数组中最小的数 x,然后对 x 重复 k-m 次取反即可

为了方便计算,我们可以将数组 numns 过滤一次拿到他的全部的负数数组 arr,对 nums 求和标记为 sum,对 arr 求和并取标记为 diffVal,最后根据 k 相对 arr.length 的大小,进行两个值的合并即可;当处于 情况2 的时候,额外处理一下数组的最小值即可

代码实现

完整的代码实现如下

var largestSumAfterKNegations = function (nums, k) {
    let sum = nums.reduce((prev, curr) => prev + curr, 0);
    let min = nums.map(n => Math.abs(n)).reduce((a, b) => a > b ? b : a);
    let arr = nums.filter(n => n < 0);
    let diff = arr.length - k;
    let diffVal = arr.sort((a, b) => a - b).slice(0, k).reduce((prev, curr) => prev + curr, 0);
    if (arr.length == 0) {
        return k % 2 == 0 ? sum : (sum - min * 2);
    } else if (diff >= 0 || diff % 2 == 0) {
        return sum + diffVal * -2;
    } else {
        return sum + diffVal * -2 - min * 2;
    }
};

image.png