剑指Offer_#4_二维数组中的查找
Contents
题目
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
限制:
0 <= n <= 1000
0 <= m <= 1000
思路分析
方法1:暴力搜索
两轮循环,暴力搜索,可以通过,但是因为没有利用到题目给出的条件“每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序”,所以肯定不是最优解。
方法2:从右上角(左下角)开始查找
最自然的想法肯定是从左上角开始遍历矩阵,但是如果从左上角开始遍历,是没法利用到题目条件来优化算法的,因为从左上到右下,无论向下走还是向右走,数字都是增大,无法进行决策。
但是如果从右上角开始向左下角查找,我们发现,向左走数字减小,向下走数字增大。那么其实就是类似于在二叉搜索树查找一个数字:
- 如果当前数字小于target,则向下移动,排除当前行
- 如果当前数字大于target,则向左移动,排除当前列
这样就可以不用遍历所有的数字。因为每次移动的时候,就相当于排除掉一行或者一列,时间复杂度变成O(m+n)。
同理,从左下角开始查找也是类似的,不再赘述。
解答
解答1:暴力搜索
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix == null || matrix.length == 0 || matrix[0].length == 0)
return false;
for(int i = 0;i < matrix.length;i++){
for(int j = 0;j < matrix[i].length;j++){
if(matrix[i][j] == target) return true;
}
}
return false;
}
}
复杂度分析
时间复杂度:O(n2)
空间复杂度:O(1)
关于数组和null
- 数组不属于java的基本类型,属于对象。
- 基本类型只有 boolean, byte, short, char, int, long, float, double 8种。
- null只可以赋值给对象的引用变量,不可以赋值给基本类型变量。
所以本题中考虑的特殊情况,不仅仅要考虑数组长度为0的情况,还要考虑输入为null值的情况。
解答2:从右上角开始查找
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix == null || matrix.length == 0 || matrix[0].length == 0)
return false;
int rows = matrix.length;
int cols = matrix[0].length;
//从右上角元素开始查找
int row = 0;
int col = cols - 1;
//循环条件是不超出matrix坐标范围
while(row <= rows - 1 && col >= 0){
if(matrix[row][col] == target) return true;
//ERROR:下面两句不可以写成if,否则col--之后可能已经越界了,到最后一个判断语句就会出现越界
else if(matrix[row][col] > target) col--;
else if(matrix[row][col] < target) row++;
}
//循环结束了还没有找到target,就返回false
return false;
}
}
复杂度分析
时间复杂度:O(m+n)
空间复杂度:O(1)