《剑指offer》二维数组中的查找

《剑指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.不然会出现数据边界溢出的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值