Problem Description
Given an m x n matrix grid and a non‐negative integer k, count the number of submatrices (i.e. contiguous blocks in the grid) that satisfy both of the following:
- The maximum element in the submatrix is at most k.
- In the submatrix, every row (when read from left to right) is sorted in non‑increasing order.
A submatrix is defined by four indices (x1, y1, x2, y2) such that the submatrix contains grid[x][y] for all x1 ≤ x ≤ x2 and y1 ≤ y ≤ y2.
For example, given grid = [[4,3,2,1],[8,7,6,1]] and k = 3, the answer is 8.
Key Insights
- The “maximum element ≤ k” condition is equivalent to requiring every element in the submatrix is ≤ k.
- The “each row sorted in non‑increasing order” condition means that for any chosen contiguous subarray from a row, the natural order in that row must not “violate” non‑increasing order.
- For each row, it is useful to precompute:
- A “non‑increasing” left index array: for each column j, the earliest column index L such that the subarray from L to j is non‑increasing.
- A “validity” segment with respect to k: while scanning a row, if an element is > k then no subarray including that element can be used.
- Once the per‑row “effective left index” is computed (as the maximum of the two constraints – non‑increasing and ≤k), a subarray of a row (columns [c1, c2]) is valid if and only if effectiveLeft[i][c2] ≤ c1.
- The final answer is obtained by iterating over every possible contiguous column interval [c1, c2] and “merging” rows. For fixed column indices, one can count contiguous groups of rows such that for every row in that block, the corresponding effective left index (at column c2) does not force the starting column to be greater than c1.
- Then for each column pair, if a block of L consecutive rows are valid, there are L*(L+1)/2 submatrices from that vertical block with these fixed columns.
Space and Time Complexity
Time Complexity: O(m * n^2) in the worst-case because we iterate over all pairs of columns (O(n^2)) and for each such pair scan all m rows. Space Complexity: O(m * n) for storing the precomputed effective left indices.
Solution
We can solve the problem in two main phases:
-
Preprocessing per row:
- For each row, compute an array named “left” where left[j] is the smallest index such that the subarray from left[j] to j is non‑increasing. This is done in one pass per row.
- Also, while scanning the row, maintain a pointer (say lastInvalid) which resets whenever we encounter an element > k. Thus, for column j, if grid[i][j] ≤ k the subarray is only valid if we start from an index ≥ lastInvalid.
- Combine these two constraints by defining an “effective left” value: effectiveLeft[i][j] = max(left[j], lastInvalid). If grid[i][j] > k then mark effectiveLeft[i][j] as “invalid” (for example, set to a value larger than any valid column index).
-
Count submatrices:
- For every possible column interval [c1, c2] (with c1 ≤ c2), scan over rows.
- For each row i, the subarray (row i, columns [c1, c2]) is valid if effectiveLeft[i][c2] ≤ c1.
- Count consecutive rows that are valid. For a contiguous block of L valid rows, these rows yield L*(L+1)/2 submatrices (by choosing any contiguous subset of these rows).
- Sum over all column intervals.
This approach “reduces” the two-dimensional submatrix counting to two nested loops over columns and one loop over rows.
A few key points and potential pitfalls:
- Make sure to correctly update the “non‑increasing” left boundary because it “spills over” the entire row.
- Reset the lastInvalid pointer when an element > k is encountered.
- When scanning rows for a fixed column interval, use a running count of consecutive valid rows and add it to the answer when an invalid row is hit (or at the end of the row).
Code Solutions
Below are code solutions in four languages with detailed line‐by‐line comments.