240. 搜索二维矩阵 II(Search a 2D Matrix II)

频次 ★★★★ · 难度 🟡 · 高频:字节/腾讯/美团

题目

m×n 矩阵,每行从左到右升序,每列从上到下升序,判断 target 是否存在。与 74 题不同,本题不保证每行第一个元素大于上一行最后一个(即全局不完全有序)。

示例

输入:
[
  [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

思路

Z 字形查找(右上角出发):从右上角 (0, n-1) 开始,每次比较当前值与 target:

  • 相等 → 找到,返回 true
  • 当前值 < target → 下移一行(该行左侧都更小,整行排除)
  • 当前值 > target → 左移一列(该列下方都更大,整列排除)

每次排除一行或一列,至多 m+n 步。

代码

public boolean searchMatrix(int[][] matrix, int target) {
    if (matrix == null || matrix.length == 0 || matrix[0].length == 0)
        return false;
    int m = matrix.length, n = matrix[0].length;
    int r = 0, c = n - 1;              // 从右上角出发
    while (r < m && c >= 0) {
        if (matrix[r][c] == target)
            return true;
        if (matrix[r][c] < target)
            r++;                       // 排除当前行
        else
            c--;                       // 排除当前列
    }
    return false;
}

复杂度

  • 时间:O(m + n) —— 最多走 m 行 + n 列
  • 空间:O(1)

边界条件

  • 空矩阵:返回 false,开头防御
  • 单行单列:走水平或垂直一条线即可
  • target 小于矩阵最小值或大于最大值:从右上角出发会一路左移或下移到边界,返回 false

变式

  • 74. 搜索二维矩阵:全局有序,可用一次二分 O(log(mn))
  • 每行分别二分:遍历每一行做二分,O(m log n);适用于 m << n 的场景
  • 从左下角出发:对称思路,当前值 < target 右移,当前值 > target 上移

易错点

  • 本题不能用一维二分(全局不完全有序,74 题才适用),但可以每行单独二分
  • 从右上角出发时,矩阵为空或第一行为空都会导致 matrix[0].length 空指针,必须前置判空
  • 移动方向容易搞反:matrix[r][c] < target → 向(行号增大),> target → 向(列号减小)

面试追问

  • 从左上角或右下角出发行不行? 不行——左上角向右向下都增大,右下角向左向上都减小,无法判断往哪个方向走。只有右上(左小下大)和左下(上小右大)两个拐角能提供唯一决策方向
  • 怎么证明每次排除一行/列的正确性? 右上角 matrix[r][c] 是当前行最大、当前列最小。如果 target > matrix[r][c],说明 target 大于整行最大,所以整行不可能有 target,r++ 排除该行;如果 target < matrix[r][c],说明 target 小于整列最小,所以整列不可能有 target,c— 排除该列。每次排除的都是「不可能区域」
  • m 远大于 n 或反之时怎么优化? 对短的维度做二分:如果 m > n,可以遍历行二分列(O(m log n)),或遍历列二分行(O(n log m)),选短的那维做外层遍历

关联题