背景
今天偶然进入牛客网,看到《剑指offer》模块有算法题,就开始试着答题
题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
一开始我的思路比较笨,不就直接遍历二维数组嘛?
输入以下代码提交了
<?php
function Find($target, $array)
{
// write code here
for($i = 0; $i < count($array[0]); $i++){
for($j = 0; $j < count($array[1]); $j++){
if($target === $array[$i][$j]){
return 1;
}
}
}
}
虽说第一次直接提交成功了,但是感觉好像这个时间复杂度有点高
仔细审了题,使用另外一种思路作答
思路:
- 由于题目中的二维数组是有序排列的,而且是根据每一行从左到右递增,每一列从上到下递增,那么在查找二维数组的时候,可以通过这个规律来改变实现方法
- 从每一个二维数组的左下角跟右上角开始查找比较方便(至于为什么方便,大家可以自己思考一下)
1、假设从右上角开始查找
如果$target < $array[$i][$j],则往左边移动一个单位(即$j--);
如果$target > $array[$i][$j],则往下边移动一个单位(即$i++);
如果$target = $array[$i][$j],则返回true;
2、假设从左下角开始查找
如果$target < $array[$i][$j],则往上边移动一个单位(即$i--);
如果$target > $array[$i][$j],则往右边移动一个单位(即$j++);
如果$target = $array[$i][$j],则返回true;
代码实现:
<?php
function Find($target, $array)
{
$length = count($array[0]); //一维数组的长度
$i = 0; //起始横坐标
$j = $length - 1; //起始纵坐标
for($n = 0; $n < ($length - 1) + (count($array) - 1); $n++){ //最多移动$length减1 + 二维数组长度减1次
if($array[$i][$j] === $target){//查找到目标,返回true
return true;
}
if($array[$i][$j] < $target){//查找目标大于右上角元素,则$i++,下移
$i++;
continue;
}
if($array[$i][$j] > $target){//查找目标小于右上角元素,则$j--,左移
$j--;
continue;
}
}
}
代码讲解:
for循环中,最多只需要移动$length减1 + 二维数组长度减1 次,什么意思呢?
画个图你们就明白了
假设有如下二维数组:
我们从右上角开始查找22这个数
由于22比8大,所以我们先下移,22比18大,我们继续下移,由于22比28小,我们需要左移......
最终我们移动了8次才找到22这个数,而且8次是移动次数最多的,为什么呢?
因为每一次只能下移或者左移,所以
左移次数最多6次(即一维数组长度减1次)
下移次数最多2次(即二维数组长度减1次)
这就是为什么for循环中,最多需要循环$length减1 + 二维数组长度减1次,$length就是一维数组的长度
因此这个算法的时间复杂度为O(n+m),其中n为一维数组的长度,m为二维数组的长度(忽略减去的2次)
相比之前的O(n*m),还是快了些的。
总结
牛客网真的是一个很不错的网址,上面不仅有大量的试题,而且还有很多大佬的经验分享,值得大家去好好利用这个资源,相信牛客网能给各位带来许多帮助,一起加油!