↓Skip to main content
  1. LeetCode/

LeetCode 3989: Maximum Consistent Columns in a Grid

·2 mins· ·
LeetCode Hard Dynamic-Programming Matrix Array
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-07-13

  • Submissions: Accepted ×2 (memoized → LIS-style loop)

Approach
#

The kept columns stay in order, forming a subsequence of columns. The condition only involves adjacent kept columns: every row’s difference is <= limit.

That is exactly LIS: dp[j] = the most columns kept ending at column j.

dp[j] = 1 + max(dp[i]) over i < j where columns i and j are compatible

Checking compatibility takes m rows, so it is O(n^2 · m) overall.

My Solution
#

class Solution:
    def maxConsistentColumns(self, grid: List[List[int]], limit: int) -> int:
        m, n = len(grid), len(grid[0])

        def compatible(a: int, b: int) -> bool:
            return all(abs(grid[r][b] - grid[r][a]) <= limit for r in range(m))

        dp = [1] * n                               # dp[j]: ending at column j
        for j in range(n):
            for i in range(j):
                if dp[i] + 1 > dp[j] and compatible(i, j):
                    dp[j] = dp[i] + 1
        return max(dp)

Comparing dp[i] + 1 > dp[j] before the compatibility check skips checks that could not improve the answer.

My first accepted version memoized dp(cur, prev) (at column cur, last kept column prev), also O(n^2) states but with recursion overhead.

Complexity
#

Time O(n^2 · m), space O(n).

Mistakes to Avoid
#

  • At least one column must remain, so dp starts at 1.
  • The condition is about columns adjacent after removal, not originally adjacent columns.

Interview Explanation
#

The kept columns form a subsequence and the condition only checks neighbors after removal, so this is LIS: dp[j] is the most columns kept ending at column j, trying every earlier kept column i and extending it when every row differs by at most limit. Time O(n^2 · m).

Related

LeetCode 3651: Minimum Cost Path with Teleportations
·2 mins
LeetCode Hard Dynamic-Programming Grid-Dp Matrix Array
LeetCode 3651 note: compute layer by layer over teleports; arriving at a cell by teleport costs the previous layer’s minimum over cells with value >= it, found with a running minimum after sorting, followed by the usual right / down grid DP
LeetCode 1402: Reducing Dishes
·2 mins
LeetCode Hard Dynamic-Programming Greedy Sorting Array
LeetCode 1402 note: sort and take dishes from most satisfying down; each new dish goes first and shifts the chosen ones one slot later, adding the current chosen sum, so keep going while that sum is positive
LeetCode 1526: Minimum Number of Increments on Subarrays to Form a Target Array
·1 min
LeetCode Hard Dynamic-Programming Greedy Monotonic-Stack Array
LeetCode 1526 note: scanning left to right, every rise above the previous height needs that many new operations; drops reuse earlier operations
LeetCode 1335: Minimum Difficulty of a Job Schedule
·2 mins
LeetCode Hard Dynamic-Programming Interval-Dp Array
LeetCode 1335 note: partition DP into d segments; dp(i, k) = the least difficulty starting at job i with k days left, enumerating where today ends while updating today’s maximum
LeetCode 312: Burst Balloons
·2 mins
LeetCode Hard Dynamic-Programming Interval-Dp Array
LeetCode 312 note: choose the last balloon k burst in the range (i, j); at that moment its neighbors are i and j, and the two sides are independent subproblems
LeetCode 1537: Get the Maximum Score
·3 mins
LeetCode Hard Dynamic-Programming Two-Pointers Greedy Array
LeetCode 1537 note: two sorted arrays can switch only at shared values; merge with two pointers, keep a running sum per path, and at a shared value set both to the larger sum plus that value