Opening the reading…
Opening the reading…
GREEDY › PART I
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →An operation moves one unit only to the left. Therefore, for any prefix from index 0 through index i, its total can never decrease: units from later positions may enter it, but no unit can leave it. If every final value is at most M, that prefix can contain at most (i + 1) times M units. Its original sum therefore forces M to be at least the ceiling of that prefix sum divided by its length.
This gives a lower bound for every prefix, not just for the whole array. The strongest bound is the largest prefix ceiling. It is also achievable: whenever a prefix has more units than its current limit allows, later positions can send those excess units leftward; when it has no excess, nothing must cross its boundary. Processing prefixes from left to right lets you record the strongest bound as soon as it appears.
The only arithmetic detail is the ceiling. For a prefix sum sum and length len, ceiling(sum / len) is (sum + len - 1) / len with integer division. With i as a zero-based index, len is i + 1, so the expression becomes (sum + i) / (i + 1).
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n) | The scan adds each element once, performs one ceiling calculation once, and updates the answer once, so no element or prefix is revisited. |
| Space | O(1) extra | Only the running sum and answer are stored. The method returns one integer rather than a collection, so there is no output array to exclude; the bound stays constant even for the worst-shaped input. |
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
int minimizeArrayValue(vector<int>& nums) {
long long sum = 0;
long long answer = 0;
for (int i = 0; i < static_cast<int>(nums.size()); ++i) {
sum += nums[i];
long long prefixCeiling = (sum + i) / (i + 1);
answer = max(answer, prefixCeiling);
}
return static_cast<int>(answer);
}
};The expression (sum + i) / (i + 1) is the ceiling of the average because i is one less than the prefix length. The answer is updated after adding the current element, so every prefix from length one through n contributes a bound. The 64-bit sum is essential even though the returned answer fits in int.
You can also guess a maximum M and check whether the array can be transformed so every value is at most M. Process from right to left: if nums[i] exceeds M, move exactly that excess to index i - 1. This is the only useful direction, and handling the rightmost positions first ensures every excess has a path toward the left. If the scan finishes, M is feasible.
#include <algorithm>
#include <vector>
using namespace std;
class Solution {
public:
int minimizeArrayValue(vector<int>& nums) {
long long low = 0;
long long high = *max_element(nums.begin(), nums.end());
while (low < high) {
long long limit = low + (high - low) / 2;
long long excess = 0;
for (int i = static_cast<int>(nums.size()) - 1; i >= 0; --i) {
long long value = nums[i] + excess;
if (value > limit) {
excess = value - limit;
} else {
excess = 0;
}
}
if (excess == 0) {
high = limit;
} else {
low = limit + 1;
}
}
return static_cast<int>(low);
}
};This is a different arrangement, not an optimisation. The check costs O(n), and binary search performs O(log V) checks, where V is the largest initial array value, so the total is O(n log V) instead of O(n). It can feel natural when the question is phrased as a feasibility test, but the prefix-ceiling scan is shorter and faster here.