题目难度: 简单
原题链接
今天继续更新剑指 offer 系列, 这道题的优化空间非常大, 个人感觉很适合作为面试题, 值得一做. 大家在我的公众号"每日精选算法题"中的聊天框中回复 offer 就能看到该系列当前已经更新的文章了
大家有什么想法建议和反馈的话欢迎随时交流, 包括但不限于公众号聊天框/知乎私信评论等等~

题目描述

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

0 <= n <= 1000

0 <= m <= 1000

题目样例

示例

现有矩阵 matrix 如下:

[[1,   4,  7, 11, 15],[2,   5,  8, 12, 19],[3,   6,  9, 16, 22],[10, 13, 14, 17, 24],[18, 21, 23, 26, 30]
]

  • 给定 target = 5,返回 true。
  • 给定 target = 20,返回 false。

题目思考

  1. 如何充分利用两个递增条件?

解决方案

思路

分析

  • 相信大家都不难想出暴力遍历所有数字二分查找每行的方法, 前者时间复杂度为 O(RC), 后者有所优化, 达到了 O(RlogC). (RC 分别代表行和列的数目)
  • 当然, 对于二分查找, 我们还可以稍作优化. 因为行和列都是递增, 所以二分查找既可以横向查找, 也可以纵向查找, 具体选哪种就看行数还是列数更多: 行数多的话就纵向查找, 否则横向查找. 这样就充分利用了二分查找对数复杂度的特性, 减小较大项对速度的影响, 使得复杂度降低为O(min(R,C)*log(max(R,C)))
  • 但到这里大部分面试官可能都还不满意, 会追问有没有更优的方案. 因为即使是上面的二分查找, 也只用到了行或列递增的单一条件, 没有把两个递增条件同时用上, 我们如何同时用上这两个条件呢?

推导

  • 回顾两个递增性质, 假设当前我们遍历到的下标为(r,c), 那么它和 target 的关系可以分为下面三种情况:

    • 值等于 target, 直接返回 true 即可
    • 值小于 target, 那么以该点为右下角的左上矩形中的所有值都必然小于 target, 可以安全被排除, 而其余部分则说不好
    • 值大于 target, 正好与上面相反, 以该点为左上角端点的右下矩形都可以被排除
  • 重点关注上面的两个排除关系, 我们如果可以从某个起点开始, 一次排除一片区域, 然后朝一个方向继续线性遍历, 这样很快就能排查完整个矩阵
  • 而为了满足线性遍历的条件, 起点的可选值只能是左下角或者右上角, 这里可以用反证法证明: 假设我们从矩阵左上角或右下角或中间某个地方开始的话, 排除完一块区域后, 我们接下来总有两个方向选择: 排除了右下矩阵, 则可以向左或者向上继续遍历, 同理排除左上矩阵也会有向右和向下两个方向可选.
  • 而如果起点选在左下角或者右上角, 情况就不同了, 只会有一种选择. 这里以左下角起点为例, 我们可以通过递推来得出结论:
    • 如果初始值小于 target, 因为下边没元素, 所以只能向右不能向下;
    • 如果初始值大于 target, 因为左边没元素, 所以只能向上不能向左;
    • 如果第一步操作是向右, 那么第二个值如果小于 target, 还只能向右, 因为下边仍然没元素; 而如果大于 target, 还只能向上, 因为左边的整列都已经在上一次被排除掉了, 结果不可能存在于左边
    • 而如果第一步操作是向上, 按照同样的分析, 仍然可得还是只能向右或者向上继续遍历
    • 以此类推, 每次都是要么向右, 要么向上, 就能排查完矩阵所有的数字得出结果

实现

  • 初始化坐标为左下角(当然右上角也可以, 大家可以想想看代码要怎么改), 然后判断当前点与 target 的关系, 大于的话行号减 1, 小于的话列号+1, 直到找到等于 target 的点, 或者超出矩阵范围
  • 下面代码中对必要的步骤都有注释, 方便大家理解

复杂度

  • 时间复杂度 O(R+C)

    • 循环每次要么行号-1, 要么列号+1, 最多只用循环 R+C 次
  • 空间复杂度 O(1)
    • 只使用了几个变量

代码

class Solution:def findNumberIn2DArray(self, matrix: List[List[int]],target: int) -> bool:if not matrix:return Falserows, cols = len(matrix), len(matrix[0])# 起点为左下角r, c = rows - 1, 0while r >= 0 and c < cols:if matrix[r][c] > target:# 大于target, 向上r -= 1elif matrix[r][c] < target:# 小于target, 向右c += 1else:# 找到target, 返回Truereturn True# 遍历整个矩阵都找不到, 返回Falsereturn False


大家可以在下面这些地方找到我~
我的知乎专栏
我的 CSDN
我的 Leetcode
我的牛客网博客
我的公众号: 每日精选算法题, 欢迎大家扫码关注~

数组中其余的排除_[leetcode 剑指offer系列] 面试题04. 二维数组中的查找相关推荐

  1. Java利用二维数组判断节假日_《剑指offer》面试题3 二维数组中的查找 Java版

    (二维数组,每行递增,每列递增.输入二维数组和一个整数,判断数组中是否含有此数.) 我的方法:拿到题目,根据题目条件我提取出这样一个特性:一个数的右边和下面的数都比它大.于是就可以写出一种递归的方法: ...

  2. 剑指offer:面试题04. 二维数组中的查找

    题目:二维数组中的查找 在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该 ...

  3. 《剑指offer》c++版本 4.二维数组中的查找

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

  4. 【剑指Offer,JS版本】二维数组中的查找

    Time: 20190918 Type: 数组 题目描述 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数, ...

  5. 剑指offer笔记(四)二维数组中的查找

    二维数组中的查找 题目:在一个二维数组中,每一行都按照从左到右的顺序递增,每一列都按照从上到下的顺序递增,判断一个数是否在数组中 例如: 1 2 8 9 2 4 9 12 4 7 10 13 6 8 ...

  6. leetcode 打印_剑指 Offer 总结 - leetcode 剑指offer系列

    剑指 Offer 系列完结撒花!! 本篇文章是对整个系列的精华总结, 对系列的每篇文章进行了分类, 并用一句话概括每道题的思路, 方便大家理解和记忆, 当然也包含原文完整链接供大家参考 总的来说, 写 ...

  7. 在要求输入数字处找到非数字字符_剑指 Offer 67. 把字符串转换成整数 leetcode 剑指offer系列...

    点击专辑上方"蓝字"关注我吧 题目难度: 中等 原题链接[1] 今天继续更新剑指 offer 系列, 老样子晚上 6 点 45 分准时更新公众号 每日精选算法题, 大家记得关注哦~ ...

  8. 二叉树代码 java面试题_《剑指offer》面试题39 二叉树的深度(java)

    摘要: 今天翻到了<剑指offer>面试题39,题目二中的解法二是在函数的参数列表中通过指针的方式进行传值,而java是没有指针的,所以函数要进行改造.然而我翻了下别人的java版本(我就 ...

  9. 【剑指offer】面试题04:二维数组中的查找(java)

    在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 示例: 现有矩阵 ...

最新文章

  1. python3下载文件-在Python 3中从web下载文件?
  2. linux boost内存池,C++ boost库教程之内存池
  3. SBO业务单据类型(总结)
  4. Java集合框架体系(超详细)
  5. 关于“using namespace std”
  6. windows media player html5,Chrome安装Windows Media Player插件的方法
  7. 《天天数学》连载16:一月十六日
  8. 手机照片局部放大镜_手机摄影,竟然有3种对焦方式,想拍出专业水准,你必须了解...
  9. 53 岁张亚勤官宣:正式加入清华!
  10. HDU6135 拓展KMP模板
  11. php批量百万微信模板消息,PHP实现快速推送微信模板消息
  12. 微信小程序跳转视频号直播
  13. win10有一个隐藏的超级管理员帐户,拥有全部权限,如何启用它
  14. 基于circom、snarkjs实现零知识证明不透漏具体地理位置的区域监控
  15. 【SSH项目实战】国税协同平台-1.项目介绍
  16. 基于SpringBoot+vue的前后端分离学生成绩管理系统的设计与实现--毕业设计
  17. 如何确定MessageBox哪个按钮被点击。
  18. 入木三分学网络第一篇--VRRP协议详解-----(1)
  19. 自动驾驶入门技术(4)—— 摄像头
  20. Linux小项目-行车记录仪项目设计

热门文章

  1. 计算机底纹不起作用,CSS - 背景颜色在IE11中不起作用(CSS - background-color not working in IE11)...
  2. dsp呼吸灯C语言编程,DSP28335 呼吸灯程序
  3. 基于matlab的升压斩波实验,升降压斩波电路matlab仿真
  4. linux 目录 读写,Linux C 文件与目录3 文件读写(示例代码)
  5. c++ 原子操作 赋值_多线程操作可见性
  6. android评论数据如何返回@用户_教你如何用JavaScript来驯服服务端返回的数据
  7. 遍历字典_十三、Python字典三种遍历方法
  8. linux使用什么ide编译安卓,抛弃IDE,使用gradle命令与vim构建安卓应用
  9. 玩转 SpringBoot 2.x 之自定义Starter依赖
  10. 核心对象+持久对象全析(2)