2439. 最小化陣列中的最大值

胖柚の工作室發表於2024-07-19

題目連結:

看到“最小化最大值”想到二分答案。我們猜測一個上界 \(\rm limit\)\(\rm limit\) 越大越符合條件,越小越不易符合條件,滿足單調性。由於當前維護的是陣列經過操作是否滿足最大值為 \(\rm limit\),可以從後往前遍歷,遇到比 \(\rm limit\) 大的就把大的那部分減去加到前一個元素上。遍歷結束後看第一個元素,若 \(\rm \leqslant limit\) 就滿足,否則說明最大值不是 \(\rm limit\)

\(\rm [0,max]\) 上二分,其中 \(\rm max\) 是陣列元素的最大值。

class Solution {
public:
    bool check(int limit, vector<int>& nums) {
        int n = nums.size();
        vector<long long> t;//需要long long,否則 t[i-1] 增加時有可能溢位
        t.assign(nums.begin(), nums.end());//複製原陣列,防止引用修改原陣列,導致下次二分時陣列發生改變
        for (int i = n - 1; i > 0; i--) {
            if (t[i] > limit) {
                t[i - 1] += t[i] - limit;
            }
        }
        return t[0] <= limit;
    }

    int minimizeArrayValue(vector<int>& nums) {
        int l = 0, r = *max_element(nums.begin(), nums.end()) + 1;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(mid, nums)) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

如要在 \(O(1)\) 的空間上操作,可以選擇維護一個 \(\rm extra\) 變數,用於記錄當前元素比 \(\rm limit\) 大的部分。

class Solution {
public:
    bool check(int limit, vector<int>& nums) {
        int n = nums.size();
        long long extra = 0;
        for (int i = n - 1; i > 0; i--) {
            long long t = nums[i] + extra;
            if (t > limit) {
                extra = t - limit;
            } else extra = 0;
        }
        return nums[0] + extra <= limit;
    }

    int minimizeArrayValue(vector<int>& nums) {
        int l = 0, r = *max_element(nums.begin(), nums.end()) + 1;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(mid, nums)) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

相關文章