Steps to Make Array Non-decreasing

medium monotonic stack dynamic programming simulation

Problem

Given a 0-indexed array nums, in one step remove every nums[i] for which nums[i − 1] > nums[i] (a strictly larger left neighbor). All such elements are removed simultaneously, the survivors close ranks, and we repeat. Return how many steps run until nums is non-decreasing.

Inputnums = [5,3,4,4,7,3,6,11,8,5,11]
Output3
Step 1 deletes 3,3,8,5 → [5,4,4,7,6,11,11]; Step 2 deletes 4,6 → [5,4,7,11,11]; Step 3 deletes 4 → [5,7,11,11], now non-decreasing. 3 steps.

def totalSteps(nums):
    # stack holds [value, rounds_until_removed], values strictly decreasing
    stack = []
    ans = 0
    for v in nums:
        cur = 0
        # pop every element this v can "absorb" (it is >= them)
        while stack and stack[-1][0] <= v:
            cur = max(cur, stack.pop()[1])
        # if something bigger is still to the left, v dies one round later
        cur = cur + 1 if stack else 0
        ans = max(ans, cur)
        stack.append([v, cur])
    return ans
function totalSteps(nums) {
  // stack holds [value, roundsUntilRemoved], values strictly decreasing
  const stack = [];
  let ans = 0;
  for (const v of nums) {
    let cur = 0;
    // pop every element this v can "absorb" (it is >= them)
    while (stack.length && stack[stack.length - 1][0] <= v) {
      cur = Math.max(cur, stack.pop()[1]);
    }
    // if something bigger is still to the left, v dies one round later
    cur = stack.length ? cur + 1 : 0;
    ans = Math.max(ans, cur);
    stack.push([v, cur]);
  }
  return ans;
}
int totalSteps(int[] nums) {
    // stack of {value, roundsUntilRemoved}, values strictly decreasing
    Deque<int[]> stack = new ArrayDeque<>();
    int ans = 0;
    for (int v : nums) {
        int cur = 0;
        // pop every element this v can "absorb" (it is >= them)
        while (!stack.isEmpty() && stack.peek()[0] <= v) {
            cur = Math.max(cur, stack.pop()[1]);
        }
        // if something bigger is still to the left, v dies one round later
        cur = stack.isEmpty() ? 0 : cur + 1;
        ans = Math.max(ans, cur);
        stack.push(new int[]{v, cur});
    }
    return ans;
}
int totalSteps(vector<int>& nums) {
    // stack of {value, roundsUntilRemoved}, values strictly decreasing
    vector<pair<int,int>> stack;
    int ans = 0;
    for (int v : nums) {
        int cur = 0;
        // pop every element this v can "absorb" (it is >= them)
        while (!stack.empty() && stack.back().first <= v) {
            cur = max(cur, stack.back().second);
            stack.pop_back();
        }
        // if something bigger is still to the left, v dies one round later
        cur = stack.empty() ? 0 : cur + 1;
        ans = max(ans, cur);
        stack.push_back({v, cur});
    }
    return ans;
}
Time: O(n) Space: O(n)