Minimum Operations to Make Columns Strictly Increasing
EasyPrompt
You are given a m x n matrix grid consisting of non-negative integers.
In one operation, you can increment the value of any grid[i][j] by 1.
Return the minimum number of operations needed to make all columns of grid strictly increasing.
Example 1:
Input: grid = [[3,2],[1,3],[3,4],[0,1]]
Output: 15
Explanation:
- To make the
0thcolumn strictly increasing, we can apply 3 operations ongrid[1][0], 2 operations ongrid[2][0], and 6 operations ongrid[3][0]. - To make the
1stcolumn strictly increasing, we can apply 4 operations ongrid[3][1].

Example 2:
Input: grid = [[3,2,1],[2,1,0],[1,2,3]]
Output: 12
Explanation:
- To make the
0thcolumn strictly increasing, we can apply 2 operations ongrid[1][0], and 4 operations ongrid[2][0]. - To make the
1stcolumn strictly increasing, we can apply 2 operations ongrid[1][1], and 2 operations ongrid[2][1]. - To make the
2ndcolumn strictly increasing, we can apply 2 operations ongrid[1][2].

Constraints:
m == grid.lengthn == grid[i].length1 <= m, n <= 500 <= grid[i][j] < 2500
Approaches
2 approaches with complexity analysis and trade-offs.
This approach solves the problem for each column independently using dynamic programming. For each column, we build a DP table to find the minimum operations. The state dp[i][v] represents the minimum cost to make the prefix of the column of length i+1 strictly increasing, with the i-th element's new value being v. This is a valid but less efficient method compared to a simpler greedy strategy.
Algorithm
- The core idea is that operations on one column are independent of others. We can calculate the minimum operations for each column and sum them up.
- For a single column, we can use dynamic programming. Let
dp[i][v]be the minimum cost to make the prefix of the column of lengthi+1(i.e.,col[0...i]) strictly increasing, with the final value ofcol[i]beingv. - The state transition is:
dp[i][v] = (v - col[i]) + min_{u < v} {dp[i-1][u]}. This means the cost is the operations to changecol[i]tov, plus the minimum cost for the previousi-1elements to be strictly increasing, ending in a valueuthat is less thanv. - The base case for
i=0isdp[0][v] = v - col[0]for allv >= col[0]. - To make the computation efficient, we can optimize finding
min_{u < v} {dp[i-1][u]}. For each rowi, we can pre-calculate a running minimum of thedp[i-1]row. This reduces the complexity of calculating eachdp[i][v]fromO(V_max)toO(1). - The final answer for a column is the minimum value in the last row of the DP table,
min(dp[m-1]). - We can optimize space by only keeping track of the previous and current rows of the DP table.
Walkthrough
The problem can be broken down by columns, as the modifications in one column do not affect any other. The total minimum operations is the sum of minimum operations required for each individual column.
For a single column, we can formulate a dynamic programming solution. Let dp[i][v] be the minimum number of operations to make the first i+1 elements (from row 0 to i) of the column strictly increasing, with the element at row i having the final value v.
The state transition is derived as follows: to have the element at row i become v, we need v - grid[i][j] operations (assuming v >= grid[i][j]). The element at row i-1 must have a final value u that is strictly less than v. To minimize the total cost, we should choose the u that resulted in the minimum operations for the prefix up to i-1. Thus, the recurrence relation is:
dp[i][v] = (v - grid[i][j]) + min_{u < v} {dp[i-1][u]}.
The base case is for the first row (i=0): dp[0][v] = v - grid[0][j] for v >= grid[0][j].
The range for v needs to be determined. A safe upper bound is the maximum possible initial value in the grid plus the number of rows m, as in the worst case, we might need to increment by 1 for each subsequent row. Let's call this V_max.
A naive implementation of the transition would be slow. We can optimize the calculation of min_{u < v} {dp[i-1][u]}. For each row i, we can compute a running minimum of the dp[i-1] values. This allows us to find the minimum cost for the previous state in O(1) time.
We can also optimize space from O(m * V_max) to O(V_max) by only storing the DP results for the previous and current rows.
import java.util.Arrays; class Solution { public int minOperations(int[][] grid) { int m = grid.length; int n = grid[0].length; long totalOperations = 0; int maxInitialVal = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { maxInitialVal = Math.max(maxInitialVal, grid[i][j]); } } int V_MAX = maxInitialVal + m; for (int j = 0; j < n; j++) { long[] prevDp = new long[V_MAX]; Arrays.fill(prevDp, Long.MAX_VALUE); // Base case: i = 0 for (int v = grid[0][j]; v < V_MAX; v++) { prevDp[v] = v - grid[0][j]; } // Iterate through rows i = 1 to m-1 for (int i = 1; i < m; i++) { long[] currentDp = new long[V_MAX]; Arrays.fill(currentDp, Long.MAX_VALUE); long minPrevCost = Long.MAX_VALUE; for (int v = 1; v < V_MAX; v++) { minPrevCost = Math.min(minPrevCost, prevDp[v - 1]); if (v >= grid[i][j] && minPrevCost != Long.MAX_VALUE) { currentDp[v] = (long)(v - grid[i][j]) + minPrevCost; } } prevDp = currentDp; } long minColOps = Long.MAX_VALUE; for (long ops : prevDp) { minColOps = Math.min(minColOps, ops); } if (minColOps != Long.MAX_VALUE) { totalOperations += minColOps; } } return (int)totalOperations; }}Complexity
Time
O(n * m * V_max), where `n` is the number of columns, `m` is the number of rows, and `V_max` is the upper bound on element values. For each of the `n` columns, we iterate `m-1` times. In each iteration, we compute a DP row of size `V_max`, which takes `O(V_max)` time.
Space
O(V_max), where `V_max` is a calculated upper bound for element values (e.g., `max_initial_val + m`). This is because we use two arrays of size `V_max` to store DP states for the current and previous rows for each column.
Trade-offs
Pros
It is a systematic approach that correctly finds the optimal solution.
Demonstrates the application of dynamic programming to solve this type of optimization problem.
Cons
Significantly more complex to understand and implement compared to the greedy approach.
Worse time complexity
O(n * m * V_max).Worse space complexity
O(V_max).Requires determining a safe upper bound
V_maxfor the element values, which adds a layer of analysis.
Solutions
Solution
class Solution {public int minimumOperations(int[][] grid) { int m = grid.length, n = grid[0].length; int ans = 0; for (int j = 0; j < n; ++j) { int pre = -1; for (int i = 0; i < m; ++i) { int cur = grid[i][j]; if (pre < cur) { pre = cur; } else { ++pre; ans += pre - cur; } } } return ans; }}Video 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.