Given a m x n
matrix grid
which is sorted in non-increasing order both row-wise and column-wise, return the number of negative numbers in grid
.
Example 1:
Input: grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]] Output: 8 Explanation: There are 8 negatives number in the matrix.
Example 2:
Input: grid = [[3,2],[1,0]] Output: 0
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 100
-100 <= grid[i][j] <= 100
Follow up: Could you find an
O(n + m)
solution?This problem involves counting negative numbers within a matrix where both rows and columns are sorted in non-increasing order. Two efficient approaches exist: one with linear time complexity O(m+n) and another with O(m*log n) complexity.
This approach leverages the sorted nature of the matrix to efficiently count negative numbers. We start from the bottom-left corner (or top-right; the choice is symmetrical) of the matrix.
Algorithm:
ans
to 0, and start at the bottom-left corner (i = m-1
, j = 0
).i
is within bounds and j
is within bounds:
grid[i][j] < 0
: This means all elements to the right in this row are also negative. Add n - j
(the number of remaining elements in the row) to ans
, and move up one row (i--
).grid[i][j] >= 0
): Move to the right one column (j++
).ans
.Why this works: Because the matrix is sorted, if an element is non-negative, all elements to its left in the same row are also non-negative. Similarly, if an element is negative, all elements below it in the same column are also negative. This property allows us to efficiently skip sections of the matrix.
Time Complexity: O(m+n) because in the worst case, we traverse at most m rows and n columns.
Space Complexity: O(1) because we use only a constant amount of extra space.
This approach performs a binary search on each row to find the index of the first negative number.
Algorithm:
ans
to 0.bisect_left
function (or equivalent) is efficient for this purpose.ans
.ans
.Time Complexity: O(m * log n) because we perform a binary search (log n time) on each of the m rows.
Space Complexity: O(1).
Approach 1 (Linear Traversal):
def countNegatives(grid):
m, n = len(grid), len(grid[0])
i, j = m - 1, 0
ans = 0
while i >= 0 and j < n:
if grid[i][j] < 0:
ans += n - j
i -= 1
else:
j += 1
return ans
Approach 2 (Binary Search):
import bisect
def countNegatives(grid):
return sum(len(row) - bisect.bisect_left(row, 0) for row in grid)
The code in other languages (Java, C++, Go, JavaScript, TypeScript, Rust) follows similar logic, adapting the syntax and libraries as needed. The choice between these approaches depends on the specific constraints and performance requirements. If the matrix is very large, the linear traversal (Approach 1) might be slightly faster, while for smaller matrices, the difference may be negligible.