Easy
题目描述
给你一个 m x n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。请你统计并返回 grid 中负数的数目。
示例 1:
输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
输出:8
解释:矩阵中共有 8 个负数。
示例 2:
输入:grid = [[3,2],[1,0]]
输出:0
提示:
m == grid.lengthn == grid[i].length1 <= m, n <= 100-100 <= grid[i][j] <= 100
**进阶:**你可以设计一个时间复杂度为 O(n + m) 的解决方案吗?
解题思路
这道题有三种主要解法:
方法一:暴力遍历 最直观的方法是遍历整个矩阵,统计负数个数。时间复杂度为 O(m×n)。
方法二:二分查找优化 由于每行都是非递增排序的,可以对每一行使用二分查找来找到第一个负数的位置。这样时间复杂度为 O(m×log n)。
方法三:从右上角开始遍历(推荐) 利用矩阵的性质:行和列都是非递增的。从右上角开始,如果当前元素为负数,则该列下方所有元素都是负数;如果为非负数,则向左移动。这样可以在 O(m+n) 时间内解决问题。
具体思路:从右上角 (0, n-1) 开始,如果 grid[i][j] < 0,说明第 j 列从第 i 行开始往下都是负数,计数器加上 (m-i),然后向左移动;如果 grid[i][j] >= 0,向下移动。
代码实现
class Solution {
public:
int countNegatives(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
int count = 0;
int i = 0, j = n - 1;
while (i < m && j >= 0) {
if (grid[i][j] < 0) {
count += m - i;
j--;
} else {
i++;
}
}
return count;
}
};
class Solution:
def countNegatives(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
count = 0
i, j = 0, n - 1
while i < m and j >= 0:
if grid[i][j] < 0:
count += m - i
j -= 1
else:
i += 1
return count
public class Solution {
public int CountNegatives(int[][] grid) {
int m = grid.Length, n = grid[0].Length;
int count = 0;
int i = 0, j = n - 1;
while (i < m && j >= 0) {
if (grid[i][j] < 0) {
count += m - i;
j--;
} else {
i++;
}
}
return count;
}
}
var countNegatives = function(grid) {
const m = grid.length, n = grid[0].length;
let count = 0;
let i = 0, j = n - 1;
while (i < m && j >= 0) {
if (grid[i][j] < 0) {
count += m - i;
j--;
} else {
i++;
}
}
return count;
};
复杂度分析
| 方法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 从右上角遍历 | O(m + n) | O(1) |
| 二分查找 | O(m log n) | O(1) |
| 暴力遍历 | O(m × n) | O(1) |