class Solution:
def countNegatives(self, grid):
rows = len(grid)
cols = len(grid[0])
count = 0
row = 0
col = cols - 1
while row < rows and col >= 0:
if grid[row][col] < 0:
count += rows - row
col -= 1
else:
row += 1
return count
class Solution {
public:
int countNegatives(vector<vector<int>>& grid) {
int rows = grid.size();
int cols = grid[0].size();
int count = 0;
int row = 0, col = cols - 1;
while (row < rows && col >= 0) {
if (grid[row][col] < 0) {
count += rows - row;
col--;
} else {
row++;
}
}
return count;
}
};
class Solution {
public int countNegatives(int[][] grid) {
int rows = grid.length;
int cols = grid[0].length;
int count = 0;
int row = 0, col = cols - 1;
while (row < rows && col >= 0) {
if (grid[row][col] < 0) {
count += rows - row;
col--;
} else {
row++;
}
}
return count;
}
}
var countNegatives = function(grid) {
let rows = grid.length;
let cols = grid[0].length;
let count = 0;
let row = 0, col = cols - 1;
while (row < rows && col >= 0) {
if (grid[row][col] < 0) {
count += rows - row;
col--;
} else {
row++;
}
}
return count;
};
You are given a m x n
matrix called grid
, where each row and each column of the matrix is sorted in non-increasing order (from left to right and from top to bottom). Your task is to count the total number of negative numbers present in the entire matrix.
Constraints:
At first glance, the most straightforward way to solve this problem is to check every number in the matrix and count how many are negative. However, this approach does not take advantage of the fact that the matrix is sorted in non-increasing order both row-wise and column-wise.
If we think carefully, the sorting property allows us to skip checking certain parts of the matrix. For example, if we find a negative number in a row, all numbers to its right are also negative because the row is sorted in decreasing order. Similarly, if we find a non-negative number, all numbers above it in the same column must be greater or equal, so we don't need to check them.
Our goal is to find an efficient way to traverse the matrix that leverages the sorting to minimize unnecessary checks, moving from a brute-force approach to an optimized solution.
Let's break down the steps for an optimized solution:
rows - current_row
.
This approach is efficient because it skips over large blocks of numbers that are guaranteed to be negative or non-negative, thanks to the matrix's sorting.
Let's consider the following matrix as input:
grid = [ [4, 3, 2, -1], [3, 2, 1, -1], [1, 1, -1, -2], [-1, -1, -2, -3] ]
grid[0][3] = -1
(negative).
grid[0][2] = 2
(not negative). Move down to row 1.grid[1][2] = 1
(not negative). Move down to row 2.grid[2][2] = -1
(negative).
grid[2][1] = 1
(not negative). Move down to row 3.grid[3][1] = -1
(negative).
grid[3][0] = -1
(negative).
m
rows and n
columns, that's O(m * n)
time.
O(1)
(not counting the input matrix).
m + n
steps (since each move is either down or left, and we can only move down m
times or left n
times before going out of bounds).
O(m + n)
.
O(1)
.
The optimized approach is much faster, especially for large matrices.
By leveraging the matrix's sorting property, we can efficiently count all negative numbers without scanning every element. Starting from the top-right and moving only left or down allows us to skip over large portions of the matrix, making the solution both elegant and fast. The key insight is recognizing when entire blocks of the matrix are guaranteed to be negative, allowing us to count them in a single step.