【贪心】C020_K 次取反后最大化的数组和(排序 | 记录最小值下标)

一、题目描述

Given an array A of integers, we must modify the array in the following way: we choose an i and replace A[i] with -A[i], and we repeat this process K times in total. (We may choose the same index i multiple times.)

Return the largest possible sum of the array after modifying it in this way.

Input: A = [3,-1,0,2], K = 3
Output: 6
Explanation: Choose indices (1, 2, 2) and A becomes [3,1,0,2].

Note:

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

二、题解

方法一:K 次排序

  • 如何高效的找到最小值的索引 i,然后将其变为 -A[i]
  • 一个朴素的做法就是,每次取反之前对数组进行升序排列,排序后的第一个元素始终是最小的。

A.length 最大 10000,K 最大 10000,K×nlognK × nlogn 大概执行 108×410^8 × 4 次。勉强过…

public int largestSumAfterKNegations(int[] A, int K) {
    int sum = 0;
    while (K-- > 0) {
        Arrays.sort(A);
        A[0] = -A[0];
    }
    for (int n : A)
        sum += n;
    return sum;
}

复杂度分析

  • 时间复杂度:O(K×nlogn)O(K × nlogn)
  • 空间复杂度:O(1)O(1)

方法二:维护最小值下标

方法一的 K 次排序存在冗余,因为每一次排序后最小值可能还是自己,这种情况会使得下一次排序变得徒劳。我们可以这样做:

  • 每次将最小值取反,然后判断下一个数字是否比取反后的数字小。
    • 若是,则将 mini 指向下一个数字。
    • 否则,下一轮取反时,取反当前最小值 A[mini] 会使得总和最大。
public int largestSumAfterKNegations(int[] A, int K) {
    Arrays.sort(A);
    int mini = 0, N = A.length;
    while (K-- > 0) {
        A[mini] = -A[mini];
        if (mini + 1 < N && A[mini+1] < A[mini])
            mini = mini + 1;
    }
    int sum = 0;
    for (int n : A)
        sum += n;
    return sum;
}

复杂度分析

  • 时间复杂度:O(nlogn)O(nlogn)
  • 空间复杂度:O(1)O(1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章