題目連結:
看到“最小化最大值”想到二分答案。我們猜測一個上界 \(\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;
}
};