398.小L的元素修改问题 | 豆包MarsCode AI刷题

50 阅读2分钟

题解 - 数组调整问题

问题描述

小R希望通过对数组进行有限的调整操作,使所有元素都落在给定的区间 [l, r] 内。调整操作包括选择一个元素加1,另一个元素减1。这种操作的目标是尽可能少地调整数组,使得所有元素都在规定的范围内。如果无法达到目标,则返回 -1。

解题思路

  1. 平均值初估:首先,我们需要确保最终数组的平均值要在 [l, r] 的范围内。若数组的总和无法分配到每个元素在该范围内,则无论如何调整也无法实现目标:

    • 计算数组的总和 sum
    • 计算理想情况下每个元素的平均值,该平均值应当在 [l, r] 中。如果 sum / n < l,说明连最小要求的值都不能满足,返回 -1;如果 (sum + n - 1) / n > r,说明即使将所有元素的总和加最大值,它也不能满足上限条件,也返回 -1。
  2. 确定需要的调整量:接下来的步骤是确定数组中每个元素相对于 lr 的偏差。这可以通过以下两部分来计算:

    • ansl:统计所有小于 l 的元素需要增加的数量。
    • ansr:统计所有大于 r 的元素需要减少的数量。

    对于每一个元素,如果它小于 l,则必须增加到 l,其所需的增量就是 l - a[i]。如果元素大于 r,则需要减少到 r,其所需的减量就是 a[i] - r

  3. 计算最小操作次数:因为每次调整必须同时选两个元素,因此我们所需的操作次数实际上是需要将 ansl(需要增加的总量)和 ansr(需要减少的总量)进行比较,最终的需要的最小操作次数是 max(ansl, ansr)

    • 这是因为我们只能通过加减的方式互补,换句话说,如果我们需要增加不少于 x,同时减少不少于 y,那么最少的操作次数就是这两个值的最大值。

代码实现

以下是实现该思路的 C++ 代码:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;

int solution(int n, int l, int r, std::vector<int> a) {
    int sum = accumulate(a.begin(), a.end(), 0);
    
    // 检查总和的平均值是否在 [l, r] 的范围内
    if (sum / n < l || (sum + n - 1) / n > r) {
        return -1;  // 平均值不在范围的情况下返回 -1
    }
    
    int ansl = 0, ansr = 0;

    // 计算需要增加和减少的值
    for (int i = 0; i < n; i++) {
        if (a[i] < l) {
            ansl += l - a[i];  // 需要加的值
        }
        if (a[i] > r) {
            ansr += a[i] - r;  // 需要减的值
        }
    }

    return max(ansl, ansr);  // 返回调整所需的最大步数
}

int main() {
    std::cout << (solution(2, 3, 5, {1, 2}) == -1) << std::endl;  // -1
    std::cout << (solution(3, 4, 6, {3, 6, 5}) == 1) << std::endl;  // 1
    std::cout << (solution(4, 2, 8, {1, 10, 2, 6}) == 2) << std::endl;  // 2
}