You are given an integer array target. You have an integer array initial of the same size as target with all elements initially zeros.
In one operation you can choose any subarray from initial and increment each value by one.
Return the minimum number of operations to form a target array from initial.
The test cases are generated so that the answer fits in a 32-bit integer.
A subarray is a contiguous non-empty sequence of elements within an array.
Example 1:
Input: target = [3,1,5,4,2,3,4,2]
Output: 9Explanation: [0,0,0,0,0,0,0,0] -> [1,1,1,1,1,1,1,1] -> [2,1,1,1,1,1,1,1] -> [3,1,1,1,1,1,1,1] -> [3,1,2,2,2,2,2,2] -> [3,1,2,2,2,3,3,2] -> [3,1,2,2,2,3,4,2] -> [3,1,3,3,2,3,4,2] -> [3,1,4,4,2,3,4,2] -> [3,1,5,4,2,3,4,2].
Example 2:
Input: target = [3,1,1,2]
Output: 4Explanation: [0,0,0,0] -> [1,1,1,1] -> [1,1,1,2] -> [2,1,1,2] -> [3,1,1,2].
Constraints:
1 <= target.length <= 100,0001 <= target[i] <= 100,000Before attempting this problem, you should be comfortable with:
Think of building the target array as painting horizontal layers. Each operation increments a contiguous subarray by 1, which is like painting one layer. We can recursively find the minimum element in a range, paint up to that height, then solve the left and right portions independently.
The minimum element acts as a "floor" that separates the problem into independent subproblems. We paint min_value - current_height layers across the whole range, then recursively handle the regions to the left and right of the minimum.
left > right, return 0.target[minIdx] - height to the result (layers needed to reach this minimum).class Solution:
def minNumberOperations(self, target: List[int]) -> int:
def rec(l, r, h):
if l > r:
return 0
minIdx = l
for i in range(l + 1, r + 1):
if target[i] < target[minIdx]:
minIdx = i
res = target[minIdx] - h
return res + rec(l, minIdx - 1, target[minIdx]) + rec(minIdx + 1, r, target[minIdx])
return rec(0, len(target) - 1, 0)The simulation approach is slow because finding the minimum in each range takes O(n) time. A segment tree allows O(log n) range minimum queries, speeding up the overall algorithm.
The logic remains the same: divide at the minimum, but now we query the segment tree instead of scanning linearly. This reduces the total time from O(n^2) to O(n log n).
INF = float('inf')
class SegmentTree:
def __init__(self, A):
self.A = A[:]
self.n = len(A)
while (self.n & (self.n - 1)) != 0:
self.A.append(INF)
self.n += 1
self.tree = [0] * (2 * self.n)
self.build()
def build(self):
for i in range(self.n):
self.tree[self.n + i] = i
for j in range(self.n - 1, 0, -1):
a = self.tree[j << 1]
b = self.tree[(j << 1) | 1]
self.tree[j] = a if self.A[a] <= self.A[b] else b
def update(self, i, val):
self.A[i] = val
j = (self.n + i) >> 1
while j >= 1:
a = self.tree[j << 1]
b = self.tree[(j << 1) | 1]
self.tree[j] = a if self.A[a] <= self.A[b] else b
j >>= 1
def query(self, ql, qh):
return self._query(1, 0, self.n - 1, ql, qh)
def _query(self, node, l, h, ql, qh):
if ql > h or qh < l:
return -1
if l >= ql and h <= qh:
return self.tree[node]
mid = (l + h) >> 1
a = self._query(node << 1, l, mid, ql, qh)
b = self._query((node << 1) | 1, mid + 1, h, ql, qh)
if a == -1: return b
if b == -1: return a
return a if self.A[a] <= self.A[b] else b
class Solution:
def minNumberOperations(self, target: List[int]) -> int:
seg = SegmentTree(target)
stack = [(0, len(target) - 1, 0)]
res = 0
while stack:
l, r, h = stack.pop()
if l > r:
continue
minIdx = seg.query(l, r)
res += target[minIdx] - h
stack.append((l, minIdx - 1, target[minIdx]))
stack.append((minIdx + 1, r, target[minIdx]))
return resConsider how we would paint the array left to right. At the first element, we need target[0] operations to build it from 0. For each subsequent element, if it is taller than the previous one, we need additional operations to "extend" our brush strokes upward. If it is shorter or equal, the existing strokes can simply continue or stop.
The key insight: we only need new operations when the height increases. The total count is the first element plus the sum of all positive increases between consecutive elements.
target[0] (operations needed for the first element).target[i] > target[i-1], add the difference to result.A common mistake is trying to explicitly simulate which subarrays to increment, tracking their boundaries and overlaps. This leads to complex and inefficient solutions. The key insight is that you only need to count the number of new "layers" or "strokes" needed, which happens whenever the height increases from one element to the next. The greedy formula target[0] + sum(max(target[i] - target[i-1], 0) for i in range(1, n)) captures this without tracking any subarray explicitly.
The result must start with target[0], not 0. The first element requires exactly target[0] operations to build from zero, regardless of what follows. Starting the result at 0 and only counting positive differences will miss all the operations needed to build the first element, giving an answer that is target[0] less than correct.
The greedy solution only adds to the result when target[i] > target[i-1], not when it decreases. When the height decreases, existing operations "cover" the lower height naturally without needing new operations. Incorrectly adding something when the height decreases (like trying to "close" previous operations) will overcounting.
The simulation approach with O(n^2) complexity or the segment tree approach with O(n log n) complexity will pass, but the O(n) greedy solution is much simpler and faster. If you find yourself implementing a segment tree or divide-and-conquer, step back and consider whether a simpler left-to-right scan could work. The pattern of counting increases is a common greedy technique for "painting" problems.
For large arrays with large values, the sum of all positive increases could exceed 32-bit integer limits. While this problem typically has constraints that prevent overflow, always be mindful when accumulating potentially large sums. Use 64-bit integers (long in Java, long long in C++) if the constraints allow very large values or many elements.