剑指Offer04:二维数组中的查找(解决matrix[0].length数组越界异常)
1、题目描述
在一个 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。
2、解题思路
(1)题目说了要高效的搜索方法,所以排除暴力循环。
(2)数组是从左到右从上往下递增的,所以每一行同列的数都比前一行大,每一行第一个数是当前行最小的。
(3)这里选择的方法是从左下角开始找,因为如果target比对比的数小,那就直接排除当前行,j--;如果比当前数大,直接j++排除前一列。
(4)也就是一次排除一行或者一列,效率较高。
tips:数组越界异常
在写代码的时候我发现:
int row = matrix[0].length;//会出现数组越界异常
就算是数组判空之后还是会出错,于是搜索了下,发现java里面即使数组不为空,但长度也可能为0,此时就会报错。具体的在代码里详细做了笔记。
String[] s0={}; 此时s0不为空,但长度为0,开辟了内存,但内存中没有放任何东西,所以其长度为0,但不为空(已经开辟内存了)
3、代码
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
//java中数组为空和数组长度为0的区别
// String[] s0={};
// String[] s1={null,null};
// Strign s2=new String[2];
// String[] s3=null;
// 此时s0不为空,但长度为0,开辟了内存,但内存中没有放任何东西,所以其长度为0,但不为空(已经开辟内存了)
// s1不为空,长度为2,开辟内存的同时,将两个null放入内存中,所以长度为3.
// s2不为空,长度为2,虽然没有初始化但s2[0],s2[1]有默认值null,和s1类似.
// s3为空,没有长度,调用s3.length会空指针异常,虚拟机不会为其开辟内存,s3不指向任何地方
// 注:一旦等号右边有大括号产生,或者长度已经定,在内存中都会为其开辟内存,而数组的长度则取决于开辟的内存中放入东西的个数,数组为空时,不存在长度这一说,但当长度为0是数组却不一定为空
//if (matrix.length==0) return false;
//行数=数组名.length,列数=数组名[0].length
int col = matrix.length;
//int row = matrix[0].length;//这样写在数组长度为0时会报错,所以要先判数组长度是否为0
int i=col-1,j=0;
//先判断i>=0就相当于判断了数组是不是空数组,防止后面matrix[0].length越界报错,或者是在第一句的时候判断数组是否为0
while(i>=0 && j<matrix[0].length){
//从数组左下角开始找,如果大于左下角的就列数加1,去掉前一列,小于就行数减一,去掉后一行
//不能从右下角开始找,不好排除,应该从本行最小又比上面同一列的都大的开始找
if (target==matrix[i][j]) return true;
else if(target<matrix[i][j]) i--;
else if(target>matrix[i][j]) j++;
}
return false;
}
}