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
<
<
c
o
l
row<<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循环没有清除局部变量的内存,那为什么第二种方法的内存更小呢,还是为什么花费的时间更少,这两个问题留着我明天解决,哈哈哈!!!