题目来源于力扣(LeetCode)
一、题目
题目相关标签:数组、二分查找
说明:
m == grid.length
n == grid[i].length
1 <= m, n <= 100
-100 <= grid[i][j] <= 100
二、解题思路
2.1 线性扫描法
-
据题意:矩阵元素无论是按行还是按列,都以非递增顺序排列。
-
遍历矩阵,再每次遍历一个一维数组
-
判断当前一维数组中的元素是否为负数
-
为负数时,即其后的元素也必定为负数,则该数组中负数的个数为数组长度 - 当前索引
-
结束当前一维数组的遍历
2.2 二分查找法
-
遍历矩阵,每次遍历一个一维数组
-
对一维数组进行二分查找的操作
-
如二分计算得到的中间索引,其在一维数组上的元素大于等于 0 时,左指针等于中间索引加 1,继续在缩小后的范围中查找第一个负数出现索引位
-
中间索引上的元素为负数时,右指针等于中间索引减 1,继续在缩小后的范围中查找第一个负数出现索引位
-
循环结束后,最后的左指针索引位一定是指向第一个负数的所在索引,则该数组中的负数个数等于数组长度 - 左指针所在索引
三、代码实现
3.1 线性扫描法
public static int countNegatives(int[][] grid) {
int ans = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
// 当前遍历元素为负数时,则索引后的元素也必定为负数(非递增数组)
if (grid[i][j] < 0) {
ans += grid[i].length - j;
// 结束当前矩阵行的遍历,开始下一行矩阵数组的遍历
break;
}
}
}
return ans;
}
3.2 二分查找法
public static int countNegatives(int[][] grid) {
int ans = 0;
for (int i = 0; i < grid.length; i++) {
int[] arr = grid[i];
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
// 中间索引上的值大于等于 0 时,向右边缩小范围
if (arr[mid] >= 0) {
left = mid + 1;
} else {
// 中间索引上的值小于 0 时,向左边缩小范围,判断前边元素是否也小于 0
right = mid - 1;
}
}
// 最后 left 索引所在的位置即是第一个负数所在的索引(其之后的元素也是负数)
// 数组中负数个数 = 数组长度 - left 索引
ans += arr.length - left;
}
return ans;
}
四、执行用时
4.1 线性扫描法
4.2 二分查找法
五、部分测试用例
public static void main(String[] args) {
int[][] grid = {{4, 3, 2, -1}, {3, 2, 1, -1}, {1, 1, -1, -2}, {-1, -1, -2, -3}}; // output:8
// int[][] grid = {{3, 2}, {1, 0}}; // output:0
// int[][] grid = {{1, -1}, {-1, -1}}; // output:3
// int[][] grid = {{-1}}; // output:1
int result = countNegatives(grid);
System.out.println(result);
}