Maximize the Minimum Powered City
HardPrompt
You are given a 0-indexed integer array stations of length n, where stations[i] represents the number of power stations in the ith city.
Each power station can provide power to every city in a fixed range. In other words, if the range is denoted by r, then a power station at city i can provide power to all cities j such that |i - j| <= r and 0 <= i, j <= n - 1.
- Note that
|x|denotes absolute value. For example,|7 - 5| = 2and|3 - 10| = 7.
The power of a city is the total number of power stations it is being provided power from.
The government has sanctioned building k more power stations, each of which can be built in any city, and have the same range as the pre-existing ones.
Given the two integers r and k, return the maximum possible minimum power of a city, if the additional power stations are built optimally.
Note that you can build the k power stations in multiple cities.
Example 1:
Input: stations = [1,2,4,5,0], r = 1, k = 2
Output: 5
Explanation:
One of the optimal ways is to install both the power stations at city 1.
So stations will become [1,4,4,5,0].
- City 0 is provided by 1 + 4 = 5 power stations.
- City 1 is provided by 1 + 4 + 4 = 9 power stations.
- City 2 is provided by 4 + 4 + 5 = 13 power stations.
- City 3 is provided by 5 + 4 = 9 power stations.
- City 4 is provided by 5 + 0 = 5 power stations.
So the minimum power of a city is 5.
Since it is not possible to obtain a larger power, we return 5.Example 2:
Input: stations = [4,4,4,4], r = 0, k = 3
Output: 4
Explanation:
It can be proved that we cannot make the minimum power of a city greater than 4.
Constraints:
n == stations.length1 <= n <= 1050 <= stations[i] <= 1050 <= r <= n - 10 <= k <= 109
Approaches
2 approaches with complexity analysis and trade-offs.
This is the optimal approach, building upon the binary search framework. The key improvement is optimizing the check(x) function to run in linear time, O(n). This is achieved by avoiding the repeated power calculations. We first pre-calculate the initial power of every city. Then, as we iterate through the cities and add new stations, we use a difference array (or a similar sliding window technique) to efficiently track the additional power (boost) these new stations provide to subsequent cities.
Algorithm
- Define a search range for the minimum power, from
0tosum(stations) + k. - Perform binary search on this range. For each
midvalue:
- Call an efficient
check(mid)function. - The
check(targetPower)function works as follows:- In O(n), pre-calculate
initialPower[i]for alliusing a prefix sum array onstations. - Initialize a difference array
boostDiffof sizen+1to all zeros. - Initialize
stationsLeft = kandcurrentBoost = 0. - Iterate through each city
ifrom0ton-1: a. Update the power from new stations:currentBoost += boostDiff[i]. b. Calculate total power:totalPower = initialPower[i] + currentBoost. c. IftotalPower < targetPower, calculateneededstations. d. Ifneeded > stationsLeft, returnfalse. e. DecrementstationsLeftbyneeded. f. IncreasecurrentBoostbyneededas these new stations help cityiimmediately. g. Schedule the boost to be removed after its effect ends. The stations added for cityicover up to cityi+2r. So,boostDiff[i+2r+1] -= needed(with bounds check). - If the loop completes, return
true.
- In O(n), pre-calculate
- If
check(mid)is true, try for a higher power:ans = mid,low = mid + 1. - If
check(mid)is false, we need a lower power:high = mid - 1. - Return the final
ans.
Walkthrough
The check(targetPower) function is optimized as follows:
- Pre-computation: Calculate the initial power of every city based on the original
stationsarray. This can be done in O(n) time using a prefix sum array.initialPower[i] = sum(stations[j])forjin[i-r, i+r]. - Greedy Iteration with Efficient Updates: We iterate through cities from
i = 0ton-1. We maintain a variablecurrentBoostwhich represents the extra power cityireceives from all the new stations added for previous cities (j < i). - When we add
neededstations for cityi, they are placed ati+rand provide power to cities in the range[i, i+2r]. This means thecurrentBoostincreases byneededstarting from cityi. This boost effect stops after cityi+2r. We can model this efficiently using a difference array,boostDiff. When we addneededstations for cityi, we've already addedneededtocurrentBoost. To stop this effect later, we schedule a subtraction:boostDiff[i + 2*r + 1] -= needed. - At each city
i, we updatecurrentBoostby addingboostDiff[i]. The total power is theninitialPower[i] + currentBoost. If this is less thantargetPower, we add new stations and update our data structures as described.
Here is the efficient check function implementation:
private boolean check(long targetPower, int[] stations, int r, long k) { int n = stations.length; long[] prefixSum = new long[n + 1]; for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + stations[i]; } long[] initialPower = new long[n]; for (int i = 0; i < n; i++) { int left = Math.max(0, i - r); int right = Math.min(n - 1, i + r); initialPower[i] = prefixSum[right + 1] - prefixSum[left]; } long stationsLeft = k; long[] boostDiff = new long[n + 1]; long currentBoost = 0; for (int i = 0; i < n; i++) { currentBoost += boostDiff[i]; long currentTotalPower = initialPower[i] + currentBoost; if (currentTotalPower < targetPower) { long needed = targetPower - currentTotalPower; if (needed > stationsLeft) { return false; } stationsLeft -= needed; currentBoost += needed; int endEffectIndex = i + 2 * r + 1; if (endEffectIndex < n) { boostDiff[endEffectIndex] -= needed; } } } return true;}Complexity
Time
O(n * log(S)) where `n` is the number of cities and `S` is the search space size. The `check` function is optimized to O(n) using prefix sums and a difference array. The binary search contributes the `log(S)` factor.
Space
O(n) to store the prefix sum array, the initial power array, and the difference array for the boost.
Trade-offs
Pros
Highly efficient and meets the time constraints of the problem.
It's the standard and optimal way to solve this category of problems.
Cons
The logic for the
checkfunction, especially the use of the difference array to track power boosts, is more complex to understand and implement correctly.
This approach identifies that the problem is a 'maximize the minimum' type, which is a classic signal for binary searching on the answer. We can binary search for the maximum possible minimum power. For each candidate minimum power x, we need a function check(x) that determines if it's possible to make every city's power at least x using at most k additional stations.
Algorithm
- Define a search range for the minimum power, from
0to a safe upper bound likesum(stations) + k. - Perform binary search on this range. For each
midvalue:
- Call a
check(mid)function to see if a minimum power ofmidis achievable. - The
check(targetPower)function works as follows:- Create a mutable copy of the
stationsarray, saycurrentStations. - Initialize
stationsUsed = 0. - Iterate through each city
ifrom0ton-1: a. Calculate the power of cityiby summingcurrentStations[j]forjin[max(0, i-r), min(n-1, i+r)]. b. If the calculated power is less thantargetPower, calculate theneededstations. c. Ifneededexceeds the remainingk, it's impossible, so returnfalse. d. Addneededstations tocurrentStations[min(n-1, i+r)]and decrement the remainingk. - If the loop completes, it's possible, so return
true.
- Create a mutable copy of the
- If
check(mid)is true, we try for a higher power:ans = mid,low = mid + 1. - If
check(mid)is false, we need a lower power:high = mid - 1. - Return the final
ans.
Walkthrough
The core of this method is the check(targetPower) function. It simulates the process of adding stations greedily. We iterate through the cities from left to right. For each city, we calculate its current power. If it's below targetPower, we must add new stations. The optimal greedy strategy is to place these new stations as far to the right as possible while still covering the current city. This position is i + r. This helps cover the maximum number of subsequent cities.
In this specific approach, the calculation of each city's power is done naively. For each city i, we iterate through its range [i-r, i+r] and sum up the stations (including any newly added ones) to find its power. This leads to a less efficient check function.
Here is the check function implementation:
private boolean check(long targetPower, int[] stations, int r, long k) { int n = stations.length; long[] currentStations = new long[n]; for (int i = 0; i < n; i++) { currentStations[i] = stations[i]; } long stationsLeft = k; for (int i = 0; i < n; i++) { // Naively calculate power for city i by summing its window long currentPower = 0; for (int j = Math.max(0, i - r); j <= Math.min(n - 1, i + r); j++) { currentPower += currentStations[j]; } if (currentPower < targetPower) { long needed = targetPower - currentPower; if (needed > stationsLeft) { return false; } stationsLeft -= needed; // Place new stations greedily at the rightmost edge of the range int placementCity = Math.min(n - 1, i + r); currentStations[placementCity] += needed; } } return true;}The main function performs binary search calling this check function.
Complexity
Time
O(n * r * log(S)) where `n` is the number of cities, `r` is the range, and `S` is the size of the search space for the answer (from 0 to `sum(stations) + k`). The `check` function takes O(n * r) because for each of the `n` cities, it iterates up to `2r+1` other cities to calculate power. The binary search contributes the `log(S)` factor.
Space
O(n) to store the copy of the `stations` array within the `check` function.
Trade-offs
Pros
The logic for the
checkfunction is straightforward and easier to understand.
Cons
This approach is too slow for the given constraints on
nandr, and will likely result in a Time Limit Exceeded error.
Solutions
Solution
class Solution {private long[] s;private long[] d;private int n;public long maxPower(int[] stations, int r, int k) { n = stations.length; d = new long[n + 1]; s = new long[n + 1]; for (int i = 0; i < n; ++i) { int left = Math.max(0, i - r), right = Math.min(i + r, n - 1); d[left] += stations[i]; d[right + 1] -= stations[i]; } s[0] = d[0]; for (int i = 1; i < n + 1; ++i) { s[i] = s[i - 1] + d[i]; } long left = 0, right = 1 l << 40; while (left < right) { long mid = (left + right + 1) >>> 1; if (check(mid, r, k)) { left = mid; } else { right = mid - 1; } } return left; }private boolean check(long x, int r, int k) { Arrays.fill(d, 0); long t = 0; for (int i = 0; i < n; ++i) { t += d[i]; long dist = x - (s[i] + t); if (dist > 0) { if (k < dist) { return false; } k -= dist; int j = Math.min(i + r, n - 1); int left = Math.max(0, j - r), right = Math.min(j + r, n - 1); d[left] += dist; d[right + 1] -= dist; t += dist; } } return true; }}class Solution {public: long long maxPower(vector<int> &stations, int r, int k) { int n = stations.size(); long d[n + 1]; memset(d, 0, sizeof d); for (int i = 0; i < n; ++i) { int left = max(0, i - r), right = min(i + r, n - 1); d[left] += stations[i]; d[right + 1] -= stations[i]; } long s[n + 1]; s[0] = d[0]; for (int i = 1; i < n + 1; ++i) { s[i] = s[i - 1] + d[i]; } auto check = [&](long x, int k) { memset(d, 0, sizeof d); long t = 0; for (int i = 0; i < n; ++i) { t += d[i]; long dist = x - (s[i] + t); if (dist > 0) { if (k < dist) { return false; } k -= dist; int j = min(i + r, n - 1); int left = max(0, j - r), right = min(j + r, n - 1); d[left] += dist; d[right + 1] -= dist; t += dist; } } return true; }; long left = 0, right = 1e12; while (left < right) { long mid = (left + right + 1) >> 1; if (check(mid, k)) { left = mid; } else { right = mid - 1; } } return left; }};class Solution: def maxPower(self, stations: List[int], r: int, k: int) -> int: def check(x, k): d = [0] * (n + 1) t = 0 for i in range(n): t += d[i] dist = x - (s[i] + t) if dist > 0: if k < dist: return False k -= dist j = min(i + r, n - 1) left, right = max(0, j - r), min(j + r, n - 1) d[left] += dist d[right + 1] -= dist t += dist return True n = len(stations) d = [0] * (n + 1) for i, v in enumerate(stations): left, right = max(0, i - r), min(i + r, n - 1) d[left] += v d[right + 1] -= v s = list(accumulate(d)) left, right = 0, 1 << 40 while left < right: mid = (left + right + 1) >> 1 if check(mid, k): left = mid else: right = mid - 1 return leftVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.