LeetCode 74. Search a 2D Matrix

题目给了一个 m×n 的整数矩阵 matrix,满足两个条件:

  1. 每一行从左到右非递减排序。
  2. 下一行的第一个元素严格大于上一行的最后一个元素。

再给一个整数 target,要求判断 target 是否存在于矩阵中,存在返回 true,否则返回 false,并且时间复杂度要达到 O(log(m×n))。

从这两个性质可以看出,如果把整个矩阵按行顺序读成一维数组,这个"虚拟的一维数组"是有序的,非常适合用二分查找。

初始思路:先确定行,再二分列

一个很自然的想法是分两步来做:

第一层二分:在行上二分查找

维护两个指针 top 和 bottom 指向行号范围 [0, m-1]。

取中间行 mid_row = (top + bottom) / 2。

用这一行的第一个元素 matrix[mid_row][0] 和最后一个元素 matrix[mid_row][n-1] 来判断 target 可能在什么位置:

  • 如果 target < matrix[mid_row][0],目标只能在更上面的行,缩小到上半区。
  • 如果 target > matrix[mid_row][n-1],目标只能在更下面的行,缩小到下半区。
  • 如果 matrix[mid_row][0] <= target <= matrix[mid_row][n-1],说明目标只可能在 mid_row 这一行里。

注意:列数是 n == matrix[i].length,最后一列的下标是 n - 1,C 里 matrixColSize[0] 代表列数,最后一列下标是 matrixColSize[0] - 1。

第二层二分:在这一行中二分查找

在列区间 [0, n-1] 上再做一次普通二分查找:

  • 如果 matrix[mid_row][mid_col] == target,返回 true。
  • 如果当前值大于 target,移动右边界;小于则移动左边界。
  • 如果查完这一行都没找到,则返回 false。

这个两层二分的时间复杂度是 O(log m + log n),和 O(log(m×n)) 同一个量级,完全满足题目的要求。

官方推荐思路:把矩阵当成一维数组二分

在官方题解和很多教程中,更常见的一种写法是直接把整个矩阵看作一个有序的一维数组,在这个一维空间上做一次二分。思想如下:

核心思路

  • 矩阵整体有 m 行、n 列,总元素个数是 m * n。
  • 把这 m * n 个元素看成一维有序数组,下标从 0 到 m * n - 1。
  • 对这个一维下标区间 [0, m*n-1] 做标准二分查找。
  • 关键在于:如何把"一维下标"映射回"二维坐标"

映射关系:

假设一维下标为 mid,则

  • 行号 row = mid / n
  • 列号 col = mid % n

这样 matrix[row][col] 就对应虚拟一维数组的 mid 位置。

二分过程:

  1. 初始化 left = 0,right = m * n - 1。
  2. 循环条件 left <= right:
    • 取中点 mid = (left + right) / 2。
    • 通过上面的公式计算 row 和 col。
    • 比较 matrix[row][col] 与 target:
      • 相等直接返回 true。
      • 当前值小于 target,说明目标在右半区,令 left = mid + 1。
      • 当前值大于 target,目标在左半区,令 right = mid - 1。
  3. 循环结束还没返回,说明没找到,返回 false。

时间复杂度是一次二分,长度为 m*n,所以是 O(log(m×n)),空间复杂度 O(1)。

两种方法对比

方案 思路说明 时间复杂度 代码实现感受 典型使用场景
方法一:两层二分 先在行上二分,找到可能的行,再在行内二分 O(log m + log n) 容易和"行、列"思路对应 便于讲解"如何利用行首和行尾界定范围"
方法二:一维化二分 把矩阵当成长度为 m*n 的一维有序数组 O(log(m×n)) 代码非常简洁,逻辑集中 官方题解、刷题模板、库式写法常用

从刷题和复用二分模板的角度,很多人会更推荐"整体当一维数组"的方法;从直观理解矩阵结构的角度,两层二分也非常适合初学者。两种方法本质上利用的是同一个有序性,只是视角不同。

关于 n、matrixColSize 和下标

在 C 的函数签名中,通常会有类似参数:int** matrix, int matrixSize, int* matrixColSize

  • matrixSize 就是行数 m。
  • matrixColSize[0] 通常就是列数 n(题目保证每行长度相同)。
  • 如果有 n 列,那么合法列下标是 [0, n-1],最后一列的下标是 n - 1 或 matrixColSize[0] - 1。

这点在你写"比较 matrix[mid_row][0] 和这一行最后一个元素"时非常关键,容易写成越界的下标。

总结

整体来说,你一开始提出的"先锁定行,再二分列"的思路在大方向上是完全正确的,只需要在边界和下标上更严谨,同时理解官方常用的一维化写法,可以在面试中灵活切换表达。

相关推荐
数智工坊30 分钟前
【数据结构-树与二叉树】4.6 树与森林的存储-转化-遍历
数据结构
晚霞的不甘39 分钟前
Flutter for OpenHarmony 可视化教学:A* 寻路算法的交互式演示
人工智能·算法·flutter·架构·开源·音视频
望舒51342 分钟前
代码随想录day25,回溯算法part4
java·数据结构·算法·leetcode
独好紫罗兰1 小时前
对python的再认识-基于数据结构进行-a006-元组-拓展
开发语言·数据结构·python
C++ 老炮儿的技术栈1 小时前
Qt 编写 TcpClient 程序 详细步骤
c语言·开发语言·数据库·c++·qt·算法
KYGALYX1 小时前
逻辑回归详解
算法·机器学习·逻辑回归
铉铉这波能秀1 小时前
LeetCode Hot100数据结构背景知识之集合(Set)Python2026新版
数据结构·python·算法·leetcode·哈希算法
参.商.1 小时前
【Day 27】121.买卖股票的最佳时机 122.买卖股票的最佳时机II
leetcode·golang
踢足球09291 小时前
寒假打卡:2026-2-8
数据结构·算法
IT猿手1 小时前
基于强化学习的多算子差分进化路径规划算法QSMODE的机器人路径规划问题研究,提供MATLAB代码
算法·matlab·机器人