Facebook面试题3 | Search a 2D Matrix II

241 阅读4分钟

专栏 | 九章算法
网址 | www.jiuzhang.com

题目描述

在一个 m*n 整数矩阵中找到指定值 target。

这个整数矩阵有如下性质:

  1. 每行从左到右数值递增
  2. 每列从上到下数值递增

Example:

有如下矩阵:

指定值 target = 5,返回True。
指定值 target = 20,返回False。

解题思路分析

1. 简单粗暴法:扫描整个矩阵,找出要找的指定值。算法复杂度:O(m*n)。

2. 能不能优化?必须可以!根据矩阵的性质,会联想到二分查找。要如何让矩阵像数组那样每次减少一部分不需要进行比较的呢?我们分析一下二分查找算法,之所以每次可以舍弃掉一半,是因为我们通过中间的一个数(split_num)把数组分成了两部分,左边部分都不大于 split_num,右边部分都不小于 split_num。然后通过比较 target 跟 split_num 的大小可以知道target在左边还是右边,从而舍弃掉另外一半。注意:切分后,左右两部分跟切分前一样都是一个数组,所以我们才能继续按照同样的标准对被选取的那一半进行处理。

1)现在数组变成了矩阵,要如何选取这个 split_num 呢?由于在数组中,我们取的是最中间的元素作为 split_num,那么在这里我们尝试几个处于矩阵中特殊位置、有可能切分矩阵的元素:

A. 矩阵中心位置:以上面为例,取 matrix[2][2] = 9 这个元素,若 target < 9 那么 target 在左上角的这个矩阵里;但如果 target > 9,那么 target 可能在 matrix[2][2] 的右边,也可能在 matrix[2][2] 的下边,这两部分合起来形成一个类似 J 的形状,并不是一个矩阵,那么接下来我们便不能按照同样的标准进行切分了。与上面说的二分查找算法的想法相违背。

B. 矩阵对角线位置:如果是在对角线上任意取一个元素,那么情况与上述一致,所以这个不可行。那尝试对角线顶点元素?左上角 matrix[0][0] 和右下角 matrix[4][4] 的这两个元素,因为是最小值和最大值,所以并不能起到切分的作用,同样舍弃。而左下角 matrix[4][0] 和右上角 matrix[0][4] 这两个元素呢?以左下角 matrix[4][0] = 18 为例,若 target < 18,那么 target 在 matrix[4][0] 上方的这个矩阵里;若 target > 18,那么 target 在 matrix[4][0] 右边的这个矩阵里。不管 target 在哪一边,被选取的那部分都是一个矩阵!那我们就能继续在被选取的矩阵里比较其左下角元素和 target 的大小,进而继续缩小 target 所在的矩阵,直到找到 target!(同理,右上角这个元素也是可行的。)

2) 由此,我们可以用“左下角元素”或“右上角元素”作为 split_num(我这里就选择了左下角元素):
a. 如果 target == 左下角元素(当前位置),那么已经完成任务!
b. 如果target > 左下角元素 matrix[m][0],那么与 matrix[m][0] 同一列的元素全都小于 target, target 位于右边的矩阵 matrix[0..m][1..n]。
c. 如果 target < 左下角元素 matrix[m][0],那么与 matrix[m][0] 同一行的元素全都大于 target, target 位于上边的矩阵 matrix[0..m-1][0..n]。
d. 这个算法的复杂度是 O(m+n)。

参考代码

Search A 2D Matrix-ii 参考程序

面试官角度分析

这道题如果能够答案O(m+n)就可以拿到offer。

LintCode相关练习题

Search A 2D Matrix


推荐阅读



欢迎关注我的微信公众号:九章算法(ninechapter)。
精英程序员交流社区,定期发布面试题、面试技巧、求职信息等

九章算法,IT教育领域的深耕者
九章算法,IT教育领域的深耕者