二维递增数组中判断是否存在某一个整数

2019.7.16 争取一天一个博客,记录自己每天的进步!

第一次写博客,感觉这里很高大上,作为一名计算机专业的研究生,却没有与之匹配的编程能力,真的是令人羞愧!闲话少说,开始今天的学习经历。

来自牛客网剑指offer的题目

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

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
    ......
       }
};

可能在各位大佬看来很简单的题目,却把我难住了,只能想到用两个for循环遍历所有元素暴力破解,真的想哭?。
后来和学弟讨论了一下,学弟大概思考了10秒想到了二分法,由于这个二维数组从左到右,从上到下都是
递增的,因此取中间元素判断和待搜索元素进行大小比较。后来我就开始思考怎么写代码(二分法我也学过,但是我这呆脑子真的是想不到,数据结构学了不知道几遍了,就是不开窍!)。
二分法需要有一个起点一个终点,起点好说是 a r r a y [ 0 ] [ 0 ] array[0][0] array[0][0],但是终点我又懵了,这个初始代码没有给我呀,印象中vector这类模板类是自带函数可以调用的,但是百度了半天只看到array.Length()这个函数,关键是这个函数求的还是二维数组中元素的个数,其实这里我把vector和普通的二维数组搞混乱了,说起来就是审题没审清楚。后来自己琢磨加敲代码试了试,应该算是搞清楚了。

普通的二维数组 a [ 2 ] [ 3 ] = 1 , 2 , 3 , 4 , 5 , 6 a[2][3]={1,2,3,4,5,6} a[2][3]=1,2,3,4,5,6,虽然是一个2行3列的二维数组,但是其实按照地址排序而言其实1-2-3-4-5-6,因此a.Length()=6. 而这里的array数组,它其实是一个一维数组,但是它的每个数组元素都是一个数组,因此形成了一个二维数组,这两者有什么区别我不太懂,但是我感觉它们的地址排序是不一样的。而且很明显 a r r a y . L e n g t h ( ) = c o l array.Length()=col array.Length()=col也就是这个二维数组的列数,而不是所有元素的个数。这里我氪是好好的体会了一下。后来看了大佬做这题的用了size()函数,发现这两个函数是一样的,具体可以看这位大佬的博客 https://blog.csdn.net/z_qifa/article/details/77744482。 因此array的行数 r o w = a r r a y [ 0 ] . s i z e ( ) row=array[0].size() row=array[0].size().

解决了这个二维数组的行列数的问题,突然感觉二分法有点复杂,思路一直不是很清晰,于是偷偷的去看了大佬的想法(我真的不是故意的,下次一定要自己先试着写一下)。但是大佬的代码和解题思路真的把我惊艳到了(不知道是不是病句),反正就是很震撼:

  • 矩阵是有序的,从左下角来看,向上数字递减,向右数字递增,因此从左下角开始查找,当要查找数字比左下角数字大时,右移。要查找数字比左下角数字小时,上移。

反正我是当场懵了,果然是人比人气死人。于是我就开始自己傻乎乎的写代码了

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int row=array.size();
        int col=array[0].size();
        int i=0,j=col-1;\\从左下角的这个元素开始比较
        for (i=0;i<=row-1&&j>=0;)\\这里是个坑
        {
            if(target==array[i][j])
            {
                return true;
            }
           if(target<array[i][j])\\如果搜索值比当前数组值小,数组的列数减一
           {j--;
            continue;}
            if(target>array[i][j])\\如果搜索值比当前数组值大,数组的行数减一
            {i++;
            continue;}
        }
        return false;
    }
};

代码通过了,运行时间12ms,内存1400K,顺便吐槽一下这个编程工具有多坑,在return true 那里被坑了,这些内置的函数和关键字必须要用这个编译器提供的,自己手打出来的无法识别。
在for循环那里要注意边界的问题,刚开始我的代码循环是

for (i=0;i<=row-1;)
{
}

调试结果是部分数据无法通过,因此我又加入了边界的检测,测试数据中肯定存在某些数组的 r o w &lt; &lt; c o l row&lt;&lt;col row<<col.
调试通过以后,我去看了大佬的代码,大部分都是采用这个思路,其中也有二分法的。我又发现了一个新的东西,有的大佬采用的是while循环,于是我把我的代码改成了while循环

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int row=array.size();
        int col=array[0].size();
        int i=0,j=col-1;
        while(i<=row-1&&j>=0)
        {
            if(target==array[i][j])
                return true;
           if(target<array[i][j])
                j--;
            if(target>array[i][j])
                i++;
        }
        return false;
    }
};

运行时间变成了11ms,内存位1388K。因此采用while循环更好,这里我又开始纠结while和for的选择了,
https://blog.csdn.net/weixin_42747717/article/details/83031272 这篇博客讲了两个区别,是否已知循环次数,和内存是否清除的问题,但是如果while循环没有清除局部变量的内存,那为什么第二种方法的内存更小呢,还是为什么花费的时间更少,这两个问题留着我明天解决,哈哈哈!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值