《剑指offer》面试题4:二维数组的查找(C++实现)

题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

解决思路

对于一个二维数组而言,我们可以很轻松地想到,我们用暴力解法的O(N2),遍历这个二维数组就可以找这个元素。

//运行时间:13ms
//运行内存:1358K
class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int rows = array.size();
        int columns = array[0].size();
        for(int i=0;i<rows;i++)
            for(int j=0;j<columns;j++)
                if(array[i][j]==target)
                    return true;
                
        return false;
        
    }
};

但是,很显然,这不是最佳的解法,我们没有充分利用每一行,每一列都是单调递增顺序,所以这道题的关键在于如何活用这个条件。

思路一:二分法查找

这里我们很快会想到,一种活用单调递增顺序的元素查找方法–二分查找法。

//运行时间:16ms
//运行内存:1492K
class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int rows = array.size();
        int columns = array[0].size();
        for(int i=0;i<rows;i++)
        {   int left=0;
            int right=columns-1;
            while(left<=right)
            {   
                int mid=left+(right-left)/2;
                if(array[i][mid]==target)
                     return true;
                if(array[i][mid]<target)
                     left = mid+1;
                else right = mid - 1;
            }
        }
        return false;
        
    }
};

理论上来说
结果发现运行起来比暴力解法还花费时间,我估计是因为测试用例的二维矩阵比较小导致的。因为理论上来说这是一个O(nlogn)复杂度的算法。

但这也不是最优的思路。

思路二:通过归纳总结数组查找规律

我们可以实际的自己画一个矩阵出来,会发现如下的查找规律:

  • 首先选取二维数组当中右上角的数字。

    • 1.如果该数字等于target,则查找过程结束。
    • 2.如果该数字大于target,则剔除这个数字的所在列(由于该列是递增顺序,这个数字是这一列里的最小的数字,这一列的数字都会比target大)
    • 3.如果该数字小于target,则剔除这个数字的所在行(同理,这个数字是这一行里最大的数字,所以这一行的数字都要比target小)
  • 此时再次选取剩余区域的右上角的数字,然后重复上述的过程。

每一次都会缩小范围,直到找到我们的数字,或者查找范围为空。

整理清楚了以后,就不难写出我们的代码

//运行时间:12ms
//占用内存:1372K
class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int rows = array.size();
        int columns = array[0].size();
        
        if(rows>0&&columns>0)
        {    int row = 0 ;//代表搜索时,被比较元素的行
             int column = columns-1;//代表搜索时,被比较元素的列
                
             while(row<rows&&column>=0)
             {
                 if(array[row][column]==target)
                     return true;
                 else if(array[row][column]>target)
                     column--;
                 else row++;
             }
        }
        return false;
    }
};

显然,这是一个最佳的解决方案,最大限度的减小了我们搜索的范围,只要观察到我们查找范围的这个规律就可以实现了。

小结

解决思路里虽然代码可以提交,但是没有对有序的数组这个条件进行有效的使用。
思路一对于这个有序的数组的条件进行了使用,使用二分查找法,将算法复杂度降低到了O(nlogn)。
思路二最大限度的减小了我们搜索的范围。

整体而言,思路二最佳。

参考文献

《剑指offer》

牛课网刷题链接link.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值