算法
(单调性扫描) $O(n + m)$
核心在于发现每个子矩阵右上角的数的性质:
- 如下图所示,x左边的数都小于等于x,x下边的数都大于等于x。
因此我们可以从整个矩阵的右上角开始枚举,假设当前枚举的数是 $x$:
- 如果 $x$ 等于target,则说明我们找到了目标值,返回true;
- 如果 $x$ 小于target,则 $x$ 左边的数一定都小于target,我们可以直接排除当前一整行的数;
- 如果 $x$ 大于target,则 $x$ 下边的数一定都大于target,我们可以直接排序当前一整列的数;
排除一整行就是让枚举的点的横坐标加一,排除一整列就是让纵坐标减一。
当我们排除完整个矩阵后仍没有找到目标值时,就说明目标值不存在,返回false。
时间复杂度分析
每一步会排除一行或者一列,矩阵一共有 $n$ 行,$m$ 列,所以最多会进行 $n+m$ 步。所以时间复杂度是 $O(n + m)$。
C++ 代码
class Solution {
public:
bool searchArray(vector<vector<int>> array, int target) {
if (array.empty() || array[0].empty()) return false;
int i = 0, j = array[0].size() - 1;
while (i < array.size() && j >= 0) {
if (array[i][j] == target) return true;
if (array[i][j] > target) j -- ;
else i ++ ;
}
return false;
}
};
想请问一下array.empty()不是就能确认array是不是空数组了吗,为什么还要加一个array[0].empty()呢?
我也不太懂不过测试了一下,不加array[0].empty()不管是Acwing还是LeetCode都能AC
array可能不是empty,比如包含一个空的vector,这样array.empty() 为false,但是array[0].empty()为true
能举一个具体的例子吗?
[[ ][ ][ ]]应该是这样,外面的[]里面包含若干空的vector[],所以array.empty()为false,但里面的vector是空的,array[0].empty()为true。[ ]这样的情况,array.empty()才是true。
是的是的 tql
我不加ac不了
请问如果是[[][1, 2][2, 3]]呢,这样不会误判吗
那就不是矩阵了
为什么不用array.size()==0 return false; 呢
if(array.empty()||array[0].empty())return false;
这个语句中array.empty()和array[0].empty()的位置反过来这个题过不了。这个位置为啥还有讲究啊?
因为有[]选项,它的array[0]是不存在的,需要先判断array为空,if语句就不会看后面了
奥~是这样啊 谢谢你~
为什么只检查了第一行是否为空的情况,如果第一行不为空,但是其他行为空呢?这样不会出现问题吗?
只判断了array[0].empty();不应该所有行都判断是否为空最合理吗?
递归搜索,每次丢弃1/4,时间复杂度O(logm + logn)
太牛了
you le mei
为什么这样当target比矩阵中元素都大的时候就会segmentation fault??
因为你的for条件是逗号运算符
条件判断用
&&
应该就行从左上角枚举
这个应该是从左下角开始枚举的吧
依次对列,行做二分查找,时间复杂度更低o(log(nm))
不行吧,代码呢
你的写法有问题。会漏掉部分答案。
我构造一个数据给你:
target = 5。
题目里面说的应该是严格递增
看了下,没有提到。而且就算是严格递增也是错的。
target = 5
老哥牛
递归搜索,时间复杂度o(logm + logn)
直接暴力循环O(n2)也能过,是不是应该加强一下数据 - -
剑指offer的题考察注重怎么优化吧= =
if (array[i][j] > target) j – ;
else i ;
或者
if (array[i][j] > target) j – ;
if(array[i][j] < target) i;
或者
if(array[i][j] < target) i;
else j–;
都过了;
但是写成如下:
if(array[i][j] < target) i;
if(array[i][j] > target) j–; 会报segmentation fault,为什么呢?
我也有这个疑问,请问您解决了没
如果把这两行颠倒过来,就是先写下面那行,然后在判断是否为空,它会报segmentation fault,就是输入空数组,没有输出。为什么会这样?
if (array.empty() || array[0].empty()) return false;
int i = 0, j = array[0].size() - 1;
交换之后可能会访问到不存在的下标。
对空数组进行 int row=array.size() 操作没问题,但col=array[0].size() 操作,报 Segmentation Fault。意思是空数组size为0,但是不存在array[0];还是说存在array[0],但是array[0]不能进行size()操作?
不存在array[0]。
样例不够完整,似乎样例都是方阵?
有6个数据不是方阵。
一开始写的代码没注意不是方阵,沿着对角线扫的,从而确定在那一行或者那一列的那一段,然后找从里面找的,但却AC了
私信我一下错误代码,我们来加强个数据。
光看描述我觉的应该可以出现不是矩形的情况, 有的行应该可以是凹凸的,是我理解错了吗?
先写 if (array[i][j] > target) j – ; else i ++ ;再写if (array[i][j] == target) return true; 为什么就不对了??
这俩也没有交集 啊????
先写
if (array[i][j] > target) j – ; else i ++ ;
else 里面的隐含条件就是array[i][j] <=target
所以如果array[i][j] == target
这个条件成立则运行i++
这个条件,则就不会运行后面的if (array[i][j] == target) return true;
厉害
楼上同学解释地不错。
为什么这些题目偏要用return,不可以用输入输出??
这里只是写函数,不是写完整的程序
评测器中已经帮大家把输入输出写好了。
左下角也是可以的
对滴,左下角和右上角是对称的,都是可以的~
你好,我是新手小白,我想问一下array.empty( ) || array[0].empty( )是什么意思?我查了资料是不是这两句话的作用是表示二维数组是空的,array.empty( )的意思是该二维数组是一个零行的数组, array[0].empty( )表示该二维数组是一个零列的数组,使用或条件,表示只要满足其一,该二维数组是一个空的二维数组,谢谢你。
对滴。在leetcode上可以把这句话去掉试试,如果不对了会给出错误数据,一目了然。
真的谢谢你。