最小化数组中的最大值

111 阅读1分钟

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

描述

给你一个下标从 0 开始的数组 nums ,它含有 n 个非负整数。 每一步操作中,你需要:

  • 选择一个满足 1 <= i < n 的整数 i ,且 nums[i] > 0 。
  • 将 nums[i] 减 1 。
  • 将 nums[i - 1] 加 1 。

你可以对数组执行 任意 次上述操作,请你返回可以得到的 nums 数组中 最大值 最小 为多少。

  • n == nums.length
  • 2 <= n <= 10^5
  • 0 <= nums[i] <= 10^9

思路

题意要求我们找出一个在符合操作下的最大值最小化

一般这类问题如何思考呢?

我们可以直接从最大值最小化这一点开始入手

根据题意,我们可以对 nums[i] 操作,但会让nums[i-1]变化

欸,有传递性!

我们对nums[i] - 1操作之后,我们的nums[i-1]就会 + 1

那么,我们再次对nums[i-1]进行操作,我们的nums[i-2]就会+1

...

持续下去,最后,我们可以发现,我们的值都会被累加到第一个数字去

这本不是我们想看见的,我们想的是尽可能的平均大家的值,可以平分到的最小的最大值

那么,一个比这个值大的最大值是不是一定可能呢?

显然是的,证明如下:

假设我选择可以构造出最大值为x的序列其中x是最大值的最小化的结果,并且找不到比x更小的结果时此时,我们可以对x和旁边的数进行操作,操作有两种:x1,那么旁边那个位置则需要+1由于数列中最大值的最小化是x,所以,调整后的结果值大于等于当前的x若是x+1,则最大值直接为x+1所以,我们可以构造出更大的值出来,并且是可以通过某种操作到达这个结果而比最小值小的,我们却构造不出来假设我选择可以构造出最大值为x的序列\\ 其中x是最大值的最小化的结果,并且找不到比x更小的结果时 \\ 此时,我们可以对 x 和 旁边的数进行操作,操作有两种:\\ x-1,那么旁边那个位置则需要+1,\\ 由于数列中最大值的最小化是x,所以,调整后的结果值大于等于当前的x \\ 若是x+1,则最大值直接为 x+1 \\ 所以,我们可以构造出更大的值出来,并且是可以通过某种操作到达这个结果 \\ 而比最小值小的,我们却构造不出来

于是,我们可以二分答案,去二分出最小的可以枚举出来的值是多少!

代码

class Solution {
public:
    int minimizeArrayValue(vector<int>& nums) {
        #define int long long
        int sum = 0, r = 0;
        for_each(begin(nums), end(nums), [&](int v) {sum += v; r = max(r, v);});
        int l = sum / nums.size();
        vector<int> tm(nums.size());
        while (l < r) {
            int x = l + r >> 1;
            for (int i = 0; i < nums.size(); i ++) tm[i] = nums[i];
            for (int i = tm.size() - 1; i; i --) 
                if (tm[i] > x) tm[i-1] += tm[i] - x;
            if (tm[0] > x) l = x + 1;
            else r = x;
        }
        return r;
        #undef int
    }
};