《剑指offer》二维数组中的查找
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
代码
以下是第一次想出来的暴力解法,会报错:
public class Solution {
public boolean Find(int target, int [][] array) {
int i,j=0;
for(i=0;i<array.length;i++)
{
if(array[i][0]<target)
{
for(j=0;j<array[i].length;j++)
{
if(array[i][j]==target)
return true;
if(array[i][j]>target)
break;
}
}
if(array[i][0]==target)
return true;
if(array[i][0]>target)
break;
}
return false;
}
}
分析
该方法无法处理数组为空的情况,会出现数组索引访问越界。
array[i][0]会强制访问空数组的第一列,然后报错:java.lang.ArrayIndexOutOfBoundsException
正确做法:
删除以下代码
if(array[i][0]==target)
return true;
if(array[i][0]>target)
break;
方法的不足:该解法属于暴力破解,时间复杂度高(O(m*n)),以后像这种简单的题目,1是要注意特殊的输入比如空输入,0输入等,2是要寻找题目的规律。
修改错误后的正确代码
暴力解法:
public class Solution {
public boolean Find(int target, int [][] array) {
int i,j=0;
for(i=0;i<array.length;i++)
{
if(array[i][0]<target)
{
for(j=0;j<array[i].length;j++)
{
if(array[i][j]==target)
return true;
if(array[i][j]>target)
break;
}
}
}
return false;
}
}
最佳解法
解法1、从左下角查找
思想:数组从左到右递增,从上到下递增。最佳解法是从左下角的点出发,往上走是递减,往右走是递增,每次只用走一条路。我的方法一开始从左上角查,往右往下都是递增,所以要走两条路,明显耗费更多时间。
我这份代码的时间是221ms,竟然比我的暴力破解还要慢!因为我还是遍历了所有的行和列,所以并真正的实现该方法的思想。
我的实现:
public class Solution {
public boolean Find(int target, int [][] array) {
for(int i=(array.length-1);i>=0;i--)
{
for(int j=0;j<array[i].length;j++)
{
if(array[i][j]==target)
return true;
if(array[i][j]>target)
break;
}
}
return false;
}
}
修改后的代码:
这份代码时间复杂度是O(m+n),m是行,n是列。明显比之前方法O(m*n)要好。
不过这份代码运行时间是199 ms,反正只要在1s内就好,时间复杂度越低,在大规模数据上的效果会越好。
public class Solution {
public boolean Find(int target, int [][] array) {
int i=array.length-1,j=0;
int col=array[0].length;
while(i>=0&&j<col)
{
if(array[i][j]==target)
return true;
if(array[i][j]>target)
{
i--;
continue;
}
if(array[i][j]<target)
{
j++;
continue;
}
}
return false;
}
}
分析
没有写continue的时候,算法会出数组越界的错误,因为i–后,还会执行
if(array[i],,,这条命令,i=0的时候就会越界。
写代码的时候一定要思维缜密,这种小错误要避免。
解法2、二分查找
思想:该数据在行和列上是有序递增的,符合二分查找的要求。
我的实现:
public class Solution {
public boolean Find(int target, int [][] array) {
int collef,colrig,midcol;
int i=0;
while(i<array.length)
{
collef=0;
colrig=array[0].length-1;
while(collef<=colrig)
{
midcol=(collef+colrig)/2;
if(array[i][midcol]==target)
return true;
if(array[i][midcol]>target)
{
colrig=midcol-1;
}
if(array[i][midcol]<target)
{
collef=midcol+1;
}
}
i++;
}
return false;
}
}
分析:colrig=array[0].length-1;这个地方一定不能少-1.不然会出现数据边界溢出的错误。