leetcode
leetcode 901 ~ 950
K 次取反后最大化的数组和

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

难度:

标签:

题目描述

代码结果

运行时间: 22 ms, 内存: 16.2 MB


/*
 * 思路:
 * 1. 将数组转换为流,按绝对值降序排序。
 * 2. 使用forEach和AtomicInteger来处理负数并递减k。
 * 3. 如果k为奇数,找到最小绝对值数并进行翻转。
 * 4. 使用stream.sum()来计算最终数组的和。
 */
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

public class MaximizeArraySum {
    public int largestSumAfterKNegations(int[] nums, int k) {
        AtomicInteger remainingK = new AtomicInteger(k);
        int[] sortedNums = IntStream.of(nums)
                                    .boxed()
                                    .sorted((a, b) -> Integer.compare(Math.abs(b), Math.abs(a)))
                                    .mapToInt(Integer::intValue)
                                    .toArray();

        sortedNums = IntStream.of(sortedNums)
                               .map(n -> {
                                   if (n < 0 && remainingK.get() > 0) {
                                       remainingK.getAndDecrement();
                                       return -n;
                                   }
                                   return n;
                               }).toArray();

        int min = Arrays.stream(sortedNums).min().orElse(0);

        if (remainingK.get() % 2 == 1) {
            sortedNums[Arrays.binarySearch(sortedNums, min)] = -min;
        }

        return Arrays.stream(sortedNums).sum();
    }
}

解释

方法:

此题解采用最小堆的策略来达到最大化数组和。首先,将数组中的所有元素插入到一个最小堆中,这样可以快速地获取到数组中的最小值。随后,进行k次操作,每次操作都是取出当前堆中的最小元素(这个元素是对当前数组和影响最负面的),然后将其值取反后放回堆中。这样做的目的是尽可能地减少数组中负值的影响或增加正值的影响。经过k次这样的操作后,堆中的所有元素即为修改后的数组,最后计算这些元素的和即为所求的最大数组和。

时间复杂度:

O((n+k) log n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在选择数组中的元素取反时倾向于使用最小堆而不是其他数据结构如最大堆或者数组本身?
使用最小堆的主要原因是最小堆能够快速地提供数组中的最小值。在这个问题中,优先取反影响最负面的数(即最小的数),是最优策略。如果使用数组本身,每次寻找最小值需要O(n)的时间复杂度,而在最小堆中这一操作的时间复杂度仅为O(log n)。使用最大堆则主要用于快速获取最大值,不适合本问题的需求,因为我们需要的是最小值。
🦆
在进行k次取反操作后,如果最小元素已经是正数,继续取反是否会降低数组的总和?
是的,如果在k次操作过程中,最小元素变为正数,继续进行取反操作实际上会降低数组的总和。这是因为取反正数会生成负数,从而减少总和。因此,在实际操作时,应当考虑操作的次数和元素的正负,以避免不必要的总和减少。
🦆
该算法处理全为正数或全为负数的数组时,其行为和效果是否有明显的不同?
是的,算法的行为和效果会有所不同。对于全负数数组,取反最小值(即最负的数)可以有效增加数组的总和。如果k次操作后仍有负数,继续取反可以进一步增加总和。对于全正数数组,取反会直接减少数组总和。如果操作次数k是偶数,可以通过成对取反恢复原数值,维持总和不变。如果k是奇数,则会有一个元素保持负值,导致总和减少。
🦆
执行完所有k次操作后直接计算堆中所有元素的和,这里是否考虑到堆的结构可能导致部分元素位置发生变化,从而影响和的计算?
堆结构确实会在操作过程中改变元素的位置,但这不会影响最终计算堆中所有元素的和。堆是一个完全二叉树,其中元素的位置变动确保了堆的性质,但不影响元素本身的值。因此,无论元素在堆中的位置如何变化,堆中所有元素值的总和保持不变。

相关问题