二维数组中的查找
题目描述
在一个二维数组中,每一行都按照从左至右递增的顺序排列,每一列都按照从上到下的顺序排列。请完成一个函数,输入这样一个二维数组和一个整数,判断数组中是否含有该整数。
分析
以如下所示的二维数组(3x4)为例。
2 4 5 9
4 7 12 14
5 11 25 30
本题显然有暴力解法,也即顺序遍历这个二维数组,判断是否存在目标数字,对于n*m的数组,其时间复杂度为O(nm)。根据题意,这个数组的每一行、每一列都是有序的,那么我们可以考虑类似二分查找的思想。二分法每次可以排除掉潜在范围内的一半,而本题的查找为了时间效率,也是要尽可能的通过一次比较就大幅地缩小查找范围。通过题意我们知道,对于处在这样的矩阵右上角或左下角的数是具有一定特点的。对于右上角的数,处于所在行的最右,所以一定是该行最大的数;同时处于所在列的最上边,则一定是该列最小的数,左下角的数则相反。
我们以右上角的数为例,若待查找的数target大于当前右上角的数,则它比这一整行都大,可以下移一行;反之若target小于右上角数字,则它比这一整列都小,可以左移一列;然后在子矩阵中继续查找,直到找到这个数或搜索完全部行列。例如在上述矩阵中查找整数11是否存在,首先在行号0,列号3的右上角有数字9,显然11>9,则11不可能在第0行;于是下移一行,右上角变为14,11<14,不可能在第3列;左移一列,11<12;左移一列,11>7;下移一行,找到11,返回true。
C++代码如下:
bool findNumInMatrix(vector<vector<int>> & matrix, int target) {
int rows = matrix.size();
int cols = matrix[0].size();
int r = 0, c = cols - 1;
while (r < rows && c > -1) {
if (target == matrix[r][c])
return true;
else if (target > matrix[r][c])
++r;
else
--c;
}
return false;
}
从右上角[0][cols-1]的位置开始,每次比较可以排除一行或一列,直到找到target返回true,或行列遍历完返回false。最差的情况是遍历了所有行和列,时间复杂度 O(n+m)。