在准备Amazon Virtual Interview 中,遇到了这么一道面试题
给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 请你统计并返回 grid 中 负数 的数目。
实际上,它是来自LeetCode中的原题: 1351. 统计有序矩阵中的负数
这是属于有序矩阵中的搜索问题 这一大类问题。在这里我们学习一下此题解法(思路来自于连接)感谢原作者。
这道原题在面试中被要求用O(n)的时间复杂度内做出来。如果加上这个要求,反而比下面几个medium的题更难。
解题思路:阶梯查找【时间复杂度O(m+n)】
-
思路:如果在每一行的正负数之间画一个分割竖线,连接起来就是一个自左下到右上的阶梯,如下图:
[4,3,2,|-1]
[3,2,1,|-1]
[1,1,|-1,-2]
[|-1,-1,-2,-3]
-
一次遍历:从右上到左下按照行遍历(左下到右上也可),起始位置(0,n)
- 在每一行,j一直向左遍历,直到j-1小于0越界 或者 grid[i][j-1] > 0, 那么这一行从 grid[i][j]到grid[i][n-1]都是负数,我们可以得出负数个数为 n - j,累加到负数总数目。
- 然后开始迭代下一行,i++, 下一行从grid[i][j]继续向左遍历。直到行i==m越界
-
时间复杂度分析:遍历的次数就如上图的阶梯,竖着的阶梯m个,横着的n个,加起来O(m+n)
class Solution {
public:
int countNegatives(vector<vector<int>>& grid) {
int count = 0;
//find the little box that is exactly next to the first negative ans;
for(int i = 0, j = grid[0].size()-1; i < grid.size(); i++){
while(j>=0 && grid[i][j] < 0) j--;
count += grid[0].size() - j -1;
}
return count;
}
};
自己根据这个思路自己写的解。非常有意思的解。要注意具体那根线是怎么移动的,在while区怎么复盘,很重要。 原思路题解来自LeetCode解题区
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
//searching: worst case: O(mn), go through each small block and find that one
//Since it is sorted and the last one in the first row smaller than the first one in the second row
//we can use divide and conquer: O(logn); treat it as a line
//we can also use steps to conqure it O(m+n)
int i = 0, j = matrix[0].size() - 1;
while(i < matrix.size() && j >= 0){
if(target == matrix[i][j]) return true;
else if(target < matrix[i][j]) j--;
else if(target > matrix[i][j]) i++;
}
return false;
}
};
//Time Complexity: O(m+n) Space Complexity: O(1)
相同思路,反而更简单。 最好再用二分法再做一遍
这道题算是上面题的加强版,因为上一行的最后一个数字不再小于本行的第一个数字,因此不能再用二分查找法做,只能用阶梯法解决。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int i = 0, j = matrix[0].size()-1;
while(j >= 0 && i < matrix.size()){
if(matrix[i][j] == target) return true;
else if(matrix[i][j] < target) i++;
else if(matrix[i][j] > target) j--;
}
return false;
}
};