Skip to content
← All posts

Minimum Operations to Make the Array Increasing: Greedy Pass Pattern

6 min read
leetcodeproblemeasyarraysgreedy

You are given a 0-indexed integer array nums. In one operation, you can choose any element and increment it by 1. Return the minimum number of operations needed to make nums strictly increasing.

This is LeetCode 1827: Minimum Operations to Make the Array Increasing, an easy problem that demonstrates the single-pass greedy scanning pattern. You never need to look back or reconsider earlier decisions. One pass from left to right, tracking what each element needs to become, gives you the answer.

Original [1, 1, 1]Target [1, 2, 3]1[0]1[1]1[2]+3 ops1[0]2+1[1]3+2[2]original valueadded by operations
Array [1, 1, 1] needs 3 operations to become strictly increasing [1, 2, 3]. Index 1 gets +1, index 2 gets +2.

Why this problem matters

This problem is a clean entry point into the greedy forward scan family. You process elements left to right, and at each index you make a local decision that is guaranteed to be globally optimal. No dynamic programming table, no backtracking, no sorting. Just one variable tracking the previous value and a running counter.

The same pattern appears in harder problems like Candy and Jump Game, where you scan in one direction and make greedy choices at each step. Mastering this easy version builds the reflex you need for those tougher variants.

The key insight: track the minimum required value

Scan left to right. Maintain a variable prev that holds the value the last element was set to. For each new element:

  • If nums[i] is already greater than prev, it is fine as-is. Set prev = nums[i].
  • If nums[i] is less than or equal to prev, you must bump it to prev + 1. The cost is (prev + 1) - nums[i] operations. Set prev = prev + 1.

This works because you can only increment, never decrement. Each element only depends on the one before it. Making it exactly prev + 1 when it is too small is always the cheapest move. Any value larger than prev + 1 would cost more and provide no benefit to later elements.

The solution

def min_operations(nums):
    ops = 0
    prev = nums[0]

    for i in range(1, len(nums)):
        if nums[i] <= prev:
            prev += 1
            ops += prev - nums[i]
        else:
            prev = nums[i]

    return ops

Here is what each piece does:

  1. ops accumulates the total number of increment operations. prev tracks the value of the previous element after any adjustments.
  2. Start by setting prev = nums[0]. The first element never needs to change because there is nothing before it to compare against.
  3. For each subsequent element, check if it is less than or equal to prev. If so, it must become prev + 1. Add the difference to ops and update prev.
  4. If the element is already greater than prev, no operations are needed. Just update prev to the current element's value.
  5. After the loop, ops holds the total minimum operations.

The logic is greedy because at each index you do the minimum possible work to satisfy the strictly increasing constraint. You never overshoot, and you never need to revisit earlier elements.

The variable prev does double duty. It tracks both what the last element became and what the current element must exceed. This means you do not need to modify the original array or allocate any extra storage.

Walking through it step by step

Let's trace through nums = [1, 1, 1]. We maintain ops = 0 and prev = 1 (the first element).

Step 1: index 0

1 -> 111
original = 1required = 1ops added = 0
total ops: 0

First element. Set prev = 1. No operations needed.

Step 2: index 1

11 -> 21
original = 1required = 2ops added = 1
total ops: 1

nums[1] = 1, but it must be at least prev + 1 = 2. Increment once. prev = 2.

Step 3: index 2

121 -> 3
original = 1required = 3ops added = 2
total ops: 3

nums[2] = 1, but it must be at least prev + 1 = 3. Increment twice. prev = 3.

The final answer is 3. Each element that was too small got bumped to exactly one more than the previous, and no extra work was done.

Complexity analysis

MetricValue
TimeO(n), single pass through the array
SpaceO(1), only two variables (ops and prev)

This is optimal. You must look at every element at least once to know whether it needs incrementing, so O(n) time is the lower bound. And O(1) space means you are not creating any auxiliary data structures.

Building blocks

This problem is built on two reusable patterns that CodeBricks drills independently.

1. Left-to-right greedy scan

The pattern of processing an array from left to right, making a locally optimal decision at each index:

prev = initial_value
for i in range(1, len(arr)):
    if arr[i] violates constraint relative to prev:
        fix arr[i] with minimum cost
        update prev
    else:
        prev = arr[i]

In Minimum Operations, the constraint is arr[i] > prev. In Jump Game, the constraint is reachability. In Best Time to Buy and Sell Stock, the constraint is tracking the minimum seen so far. The skeleton is identical: scan forward, maintain one piece of state, and make a greedy choice at each step.

2. Gap accumulation

The pattern of computing the total cost by summing up the gap between what you have and what you need:

total_cost = 0
for each element:
    gap = required_value - actual_value
    total_cost += gap

In this problem, the gap is (prev + 1) - nums[i] when the element is too small. In problems like Minimum Cost to Move Chips, the gap is the distance each chip needs to move. The idea is the same: measure how far each item is from where it needs to be, and sum up the costs.

Edge cases

Before submitting, make sure your solution handles these:

  • Already increasing [1, 2, 3, 4]: every element is already greater than the previous. Zero operations needed.
  • All equal [5, 5, 5, 5]: each element after the first must be bumped. Total ops = 0 + 1 + 2 + 3 = 6.
  • Decreasing array [4, 3, 2, 1]: the worst case for a given set of values. Each element needs more bumping than the last. For this input, [4, 5, 6, 7] costs 0 + 2 + 4 + 6 = 12 operations.
  • Single element [42]: only one element, nothing to compare. Returns 0.
  • Two elements, already increasing [1, 2]: no operations needed. Returns 0.
  • Two elements, equal [3, 3]: bump the second to 4. Returns 1.

The greedy solution handles all of these without special-case logic.

From understanding to recall

You have read the greedy solution and it makes sense. One loop, one variable, one accumulator. But can you write it from scratch under interview pressure without looking at it?

The details matter: initializing prev to nums[0], checking nums[i] <= prev (not just <), and computing the cost as prev + 1 - nums[i] before updating prev. These are small things, but getting any one of them wrong produces a bug.

Spaced repetition closes that gap. You practice writing the left-to-right greedy scan from scratch at increasing intervals. After a few rounds, the pattern is automatic. You see "make array strictly increasing with minimum increments" and the code flows out without hesitation.

The greedy forward scan pattern is one of roughly 60 reusable building blocks that cover hundreds of LeetCode problems. Learning them individually and drilling them with spaced repetition is far more effective than grinding random problems and hoping they stick.

Related posts

CodeBricks breaks the minimum operations LeetCode problem into its greedy scan and gap accumulation building blocks, then drills them independently with spaced repetition. You type each piece from scratch until the pattern is automatic. When a greedy array adjustment question shows up in your interview, you do not think about it. You just write it.