Welcome to Subscribe On Youtube
4008. Minimum Initial Strength to Defeat All Monsters
Description
You are given an integer array monsters, where monsters[i] represents the strength of the ith monster.
You are also given a 2D integer array boosts, where boosts[i] = [li, ri, vi] indicates that vi is added to your temporary bonus while fighting any monster whose index lies in [li, ri]. Boost ranges may overlap, and the values of all applicable boosts are added together.
You start with a non-negative initial strength and fight the monsters from left to right.
For each monster at index i:
- Let
bonusbe the sum of the values of all boosts that apply to monsteri. - You can defeat the monster only if your current strength plus
bonusis at leastmonsters[i]. - After defeating the monster, only your current strength decreases by
monsters[i]. If it becomes negative, it is set to 0.
Return the minimum initial strength required to defeat all monsters.
Note: The temporary bonus is used only to determine whether the current monster can be defeated. It does not otherwise change your current strength.
Example 1:
Input: monsters = [5,10,15], boosts = [[1,1,10]]
Output: 30
Explanation:
Let's start with an initial strength of 30.
monsters[0] = 5: At index 0, the bonus is 0. Since30 + 0 >= 5, this monster can be defeated. The strength becomes30 - 5 = 25.monsters[1] = 10: At index 1, the bonus is 10. Since25 + 10 >= 10, this monster can be defeated. The strength becomes25 - 10 = 15.monsters[2] = 15: At index 2, the bonus is 0. Since15 + 0 >= 15, this monster can be defeated. The strength becomes15 - 15 = 0.
Thus, the minimum initial strength required is 30.
Example 2:
Input: monsters = [5,10,15], boosts = [[1,2,10],[1,2,5]]
Output: 5
Explanation:
Let's start with an initial strength of 5.
monsters[0] = 5: The bonus is 0. Since5 + 0 >= 5, the monster can be defeated. The strength becomes5 - 5 = 0.monsters[1] = 10: The two overlapping boosts providebonus = 10 + 5 = 15. Since0 + 15 >= 10, the monster can be defeated. The strength remains 0.monsters[2] = 15: The two overlapping boosts again providebonus = 15. Since0 + 15 >= 15, the monster can be defeated. The strength remains 0.
Thus, the minimum initial strength required is 5.
Constraints:
1 <= monsters.length <= 5 * 1041 <= monsters[i] <= 1090 <= boosts.length <= 5 * 104boosts[i] == [li, ri, vi]0 <= li <= ri < monsters.length1 <= vi <= 109
Solutions
Solution 1: Difference Array + Binary Search
Thinking
A larger initial strength always makes it easier to defeat every monster, so the feasibility predicate is monotone and admits binary search.
Applying every boost as a range add inside each check would multiply the cost by the number of boosts. A difference array turns each boost into two endpoint updates; a single scan with the monsters then tests a candidate in $O(n)$.
An upper bound of $10^{15}$ already covers the sum of all monster strengths, so binary search yields the minimum feasible start.
Each boost adds a value to an entire index range $[l, r]$, so we first apply all boosts using a difference array $d$. The $\textit{bonus}$ when fighting the $i$-th monster is then the prefix sum $\sum_{j=0}^{i} d[j]$.
Next, we binary search the initial strength $v$. For a given $v$, we simulate the fights from left to right: maintain the current $\textit{bonus}$ (the prefix sum of the difference array); if $v + \textit{bonus} < \textit{monsters}[i]$, the monster cannot be defeated and $v$ is infeasible; otherwise, we defeat it, decrease $v$ by $\textit{monsters}[i]$, and reset $v$ to $0$ if it becomes negative. If all monsters can be defeated, $v$ is feasible.
A larger initial strength never makes it harder to defeat all monsters, so feasibility is monotonic in $v$, and we can binary search the minimum feasible initial strength. The upper bound of the search is set to $10^{15}$ (the total strength of all monsters is at most $5 \times 10^4 \times 10^9 = 5 \times 10^{13}$).
The time complexity is $O((n + m) \times \log M)$, and the space complexity is $O(n)$, where $n$ is the number of monsters, $m$ is the number of boosts, and $M = 10^{15}$ is the upper bound of the binary search.
-
class Solution { private int[] monsters; private long[] d; public long minInitialStrength(int[] monsters, int[][] boosts) { this.monsters = monsters; int n = monsters.length; d = new long[n + 1]; for (int[] b : boosts) { d[b[0]] += b[2]; d[b[1] + 1] -= b[2]; } long left = 0, right = (long) 1e15; while (left < right) { long mid = (left + right) >>> 1; if (check(mid)) { right = mid; } else { left = mid + 1; } } return left; } private boolean check(long v) { long bonus = 0; for (int i = 0; i < monsters.length; i++) { bonus += d[i]; if (v + bonus < monsters[i]) { return false; } v -= monsters[i]; if (v < 0) { v = 0; } } return true; } } -
class Solution { public: long long minInitialStrength(vector<int>& monsters, vector<vector<int>>& boosts) { int n = monsters.size(); vector<long long> d(n + 1); for (auto& b : boosts) { d[b[0]] += b[2]; d[b[1] + 1] -= b[2]; } auto check = [&](long long v) -> bool { long long bonus = 0; for (int i = 0; i < n; i++) { bonus += d[i]; if (v + bonus < monsters[i]) { return false; } v -= monsters[i]; if (v < 0) { v = 0; } } return true; }; long long left = 0, right = 1000000000000000LL; while (left < right) { long long mid = (left + right) / 2; if (check(mid)) { right = mid; } else { left = mid + 1; } } return left; } }; -
class Solution: def minInitialStrength(self, monsters: list[int], boosts: list[list[int]]) -> int: def check(v: int) -> bool: bonus = 0 for a, b in zip(monsters, d): bonus += b if v + bonus < a: return False v -= a v = max(v, 0) return True n = len(monsters) d = [0] * (n + 1) for l, r, v in boosts: d[l] += v d[r + 1] -= v l, r = 0, 10**15 while l < r: mid = (l + r) >> 1 if check(mid): r = mid else: l = mid + 1 return l -
func minInitialStrength(monsters []int, boosts [][]int) int64 { n := len(monsters) d := make([]int64, n+1) for _, b := range boosts { d[b[0]] += int64(b[2]) d[b[1]+1] -= int64(b[2]) } check := func(v int64) bool { var bonus int64 for i, a := range monsters { bonus += d[i] if v+bonus < int64(a) { return false } v -= int64(a) if v < 0 { v = 0 } } return true } var left, right int64 = 0, 1000000000000000 for left < right { mid := (left + right) / 2 if check(mid) { right = mid } else { left = mid + 1 } } return left } -
function minInitialStrength(monsters: number[], boosts: number[][]): number { const n = monsters.length; const d = new Array<number>(n + 1).fill(0); for (const [l, r, v] of boosts) { d[l] += v; d[r + 1] -= v; } const check = (v: number): boolean => { let bonus = 0; for (let i = 0; i < n; i++) { bonus += d[i]; if (v + bonus < monsters[i]) { return false; } v -= monsters[i]; if (v < 0) { v = 0; } } return true; }; let left = 0; let right = 1e15; while (left < right) { const mid = Math.floor((left + right) / 2); if (check(mid)) { right = mid; } else { left = mid + 1; } } return left; }