二维数组中的查找

二维数组中的查找

http://www.nowcoder.com/questionTerminal/abc3fe2ce8e146608e868a70efebf62e

  1. 题目难度:二星
  2. 考察点:数组,二分查找
  3. 简要说明:这是一道对二维数组进行二分查找的算法,考察对二分查找的灵活运用。

方法1: 暴力算法

  1. 分析:直接遍历一遍数组,即可判断目标target是否存在。
  2. 复杂度分析
    时间复杂度:O(n^2),因为最坏情况下,数组中的元素都需要遍历一次。
    空间复杂度:O(1)
  3. 代码:
    class Solution {
    public:
     bool Find(int target, vector<vector<int> > array) {
         // 判断数组是否为空
         if (array.size() ==0 || array[0].size() ==0) return false;
         for (const auto& vec : array) {
             for (const int val : vec) {
                 if (val == target) 
                     return true;
             }
         }
         return false;
     }
    };

方法2:二分查找

  1. 分析:对于方法一,此题有额外信息没有利用上,数组从左到右递增,从上到下递增。有序的数组很显然应该想到二分。那么应该如何二分呢?
    回想一下一维有序数组查找某个值二分的过程,如下图所示:
    图片说明
    假设目标tar在arr[1]处,那么我们的二分过程就是:
    1)设初始值:定义一个二分的开始下标为l,结束下标为r,如图所示:
    2)二分一半,中间位置为 mid = l + ((r - l) >> 1), val>>1, 表示val右移一位相当于val/2,相当于 l+(r-l)/2,这样的写法是防止溢出。如果写成 mid = (l+r)/2; l+r可能会溢出。
    3) 如果 tar == arr[mid],说明找到tar
    4)比较:如果tar > arr[mid], 说明tar在区间[mid+1, r]中,l = mid + 1
    5)如果tar < arr[mid],说明tar在区间[l, mid-1]中, r = mid - 1

图中的例子就是步骤4)的情况,一次比较之后,如图所示,表示找到了tar。

错误的想法:将一维扩展到二维。照葫芦画瓢,


假设我们设二分的开始下标为左上角坐标(0,0)为上图的l,结束下标为(4,5)为图中的r,二分一次下标为(2,2)图中的mid,假设tar > arr[mid],
由一维二分可知,接下来应该找大于arr[mid]的位置,可是根据图可知,?处可能大于,也可能小于,所以就不能按照之前的规则进行二分了。所以说,这样是错的。

总结一下:错误的原因是:之前二分之后,无法确定下一次二分应该往哪边分,由此无法进行二分下去。如果我们找个位置,每次都能确定的往哪个部分二分,即可达到我们想要的结果。

新想法

假设arr数组,val,tar如下图所示:
如果我们把二分值定在右上角或者左下角,就可以进行二分。这里以右上角为例,左下角可自行分析:
图片说明
1)我么设初始值为右上角元素,arr[0][5] = val,目标tar = arr[3][1]
2)接下来进行二分操作:
3)如果val == target,直接返回
4)如果 tar > val, 说明target在更大的位置,val左边的元素显然都是 < val,间接 < tar,说明第 0 行都是无效的,所以val下移到arr[1][5]
5)如果 tar < val, 说明target在更小的位置,val下边的元素显然都是 > val,间接 > tar,说明第 5 列都是无效的,所以val左移到arr[0][4]
6)继续步骤2)

  1. 复杂度分析
    时间复杂度:O(m+n) ,其中m为行数,n为列数,最坏情况下,需要遍历m+n次。
    空间复杂度:O(1)
  2. 代码
    class Solution {
    public:
     bool Find(int target, vector<vector<int> > array) {
         // 判断数组是否为空
         int m = array.size();
         if (m == 0) return false;
         int n = array[0].size();
         if (n == 0) return false;
         int r = 0, c = n-1; // 右上角元素
         while (r<m && c>=0) {
             if (target == array[r][c]) {
                 return true;
             }
             else if (target > array[r][c]) {
                 ++r;
             }
             else {
                 --c;
             }
         }
         return false;
     }
    };
全部评论
这不叫二分吧,每次只能去掉一行或一列。如果我直接给你个一维数组,直接退化成线性了,这里应该根据中心位置与target的关系把大矩阵拆成4个小矩阵,这才叫二分(四分)
6 回复 分享
发布于 2021-07-31 05:42
暴力解法,20组用例无法通过!!!!!别再说暴力了。
2 回复 分享
发布于 2021-08-01 18:46
女少口阿
2 回复 分享
发布于 2021-07-20 00:53
} else if (target > array[r][c]) { ++r; c = array[r].size() - 1; 算法有bug,需要增加一行
1 回复 分享
发布于 2022-03-21 18:44
喵喵喵
1 回复 分享
发布于 2021-07-31 22:13
妙啊
1 回复 分享
发布于 2021-04-23 16:17
这怎么就是二分了?
点赞 回复 分享
发布于 2022-11-26 23:56 四川
妙啊
点赞 回复 分享
发布于 2022-09-15 17:44 北京
秒啊
点赞 回复 分享
发布于 2022-03-23 21:13
相当秒啊
点赞 回复 分享
发布于 2022-03-21 19:48
秒啊!
点赞 回复 分享
发布于 2022-03-10 14:43
点赞 回复 分享
发布于 2022-02-25 22:39
妙啊
点赞 回复 分享
发布于 2022-02-04 16:39
妙啊
点赞 回复 分享
发布于 2022-01-20 17:59
秒啊
点赞 回复 分享
发布于 2021-12-19 23:26
妙啊
点赞 回复 分享
发布于 2021-10-09 14:03
妙啊
点赞 回复 分享
发布于 2021-08-31 18:31
妙啊
点赞 回复 分享
发布于 2021-08-06 15:23
暴力貌似不用判断是否为空就能过?
点赞 回复 分享
发布于 2021-08-05 16:49
妙啊~
点赞 回复 分享
发布于 2021-07-24 15:29

相关推荐

2025-12-24 15:25
已编辑
门头沟学院 前端工程师
是腾讯的csig腾讯云,前天晚上九点突然打电话约面,激动的通宵学了一晚上,第二天状态很差改了今天(以后再也不通宵学习了)感觉自己浪费了面试官一个半小时单纯手写+场景,无八股无项目无算法,打击真的很大,全是在面试官提醒的情况下完成的,自己技术方面真的还是有待提高,实力匹配不上大厂和已经面试的两个公司完全不一样,很注重编码能力和解决问题的能力,然而我这两个方面都很薄弱,面试官人很好很耐心的等我写完题目,遇到瓶颈也会提醒我,写不出题也会很耐心的跟我讲解好感动,到最后面试结束还安慰我打算把下周最后一场面试面完之后就不面啦,如果能去实习还是很开心,但是最重要的还是好好努力提高技术以下是面经第一题//&nbsp;实现一个解析&nbsp;url&nbsp;参数的函数function&nbsp;parseUrl(urlStr)&nbsp;{//&nbsp;TODO}parseUrl('*********************************************');//&nbsp;返回&nbsp;{a:&nbsp;1,&nbsp;b:&nbsp;2,&nbsp;c:&nbsp;3}追问:在链接里见过什么部分?用&nbsp;hash&nbsp;路由的话放在哪第二题//&nbsp;考虑有一个异步任务要执行,返回&nbsp;Promise,这个任务可能会失败,请实现&nbsp;retry&nbsp;方法,返回新方法,可以在失败后自动重试指定的次数。/***&nbsp;异步任务重试*&nbsp;@param&nbsp;task&nbsp;要执行的异步任务*&nbsp;@param&nbsp;times&nbsp;需要重试的次数,默认为&nbsp;3&nbsp;次*/function&nbsp;retry(task,&nbsp;times&nbsp;=&nbsp;3)&nbsp;{//&nbsp;TODO:&nbsp;请实现}//&nbsp;---------------测试示例&nbsp;----------------//&nbsp;原方法const&nbsp;request&nbsp;=&nbsp;async&nbsp;(data)&nbsp;=&gt;&nbsp;{//&nbsp;模拟失败if&nbsp;(Math.random()&nbsp;&lt;&nbsp;0.7)&nbsp;{throw&nbsp;new&nbsp;Error('request&nbsp;failed');}const&nbsp;res&nbsp;=&nbsp;await&nbsp;fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;,&nbsp;{method:&nbsp;'POST',body:&nbsp;JSON.stringify(data),});return&nbsp;res.json();}//&nbsp;新的方法const&nbsp;requestWithRetry&nbsp;=&nbsp;retry(request);//&nbsp;使用async&nbsp;function&nbsp;run()&nbsp;{const&nbsp;res&nbsp;=&nbsp;await&nbsp;requestWithRetry({&nbsp;body:&nbsp;'content'&nbsp;});console.log(res);}run();第三题就是给&nbsp;retry&nbsp;函数添加类型注释,用到泛型第四题:在组件库中将&nbsp;Alert&nbsp;用&nbsp;api&nbsp;的形式实现(应该就是&nbsp;message&nbsp;这个组件)怎么渲染到一个浮层里而不是原地渲染出来
不知道怎么取名字_:技术这个东西,太杂了,而且要下功夫的
查看5道真题和解析
点赞 评论 收藏
分享
评论
392
73
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务