原题
二分与排序中等2 种解法

#240搜索二维矩阵 II

在每行从左到右、每列从上到下都升序的矩阵中判断 target 是否存在。

#数组#矩阵#二分查找#分治

原题

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

示例 1:

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

示例 2:

输入: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 = 20
输出:false

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= n, m <= 300
  • -109 <= matrix[i][j] <= 109
  • 每行的所有元素从左到右升序排列
  • 每列的所有元素从上到下升序排列
  • -109 <= target <= 109

查看原题

解题主线

  1. 每一行本身有序,可以独立二分;行之间的列序关系还可进一步利用。
  2. 右上角同时是所在行最大方向的端点和所在列最小方向的端点:值过大就左移,过小就下移。
  3. 阶梯搜索每一步排除一整行或一整列,因此最多移动 m + n 次。

解法 1:逐行二分查找

对每个有序行执行标准二分;任一行命中即返回。

  • 时间复杂度: O(m log n)

  • 空间复杂度: O(1)

JAVA
final class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        // 读取首行长度前先排除空矩阵与空行。
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        for (int[] row : matrix) {
            int left = 0;
            int right = row.length - 1;
            // 搜索区间始终为闭区间 [left, right]。
            while (left <= right) {
                int middle = left + (right - left) / 2;
                if (row[middle] == target) return true;
                if (row[middle] < target) left = middle + 1;
                else right = middle - 1;
            }
        }
        return false;
    }
}

解法 2:右上角阶梯搜索

从右上角出发:当前值大于 target 就排除当前列并左移,小于 target 就排除当前行并下移。

  • 时间复杂度: O(m + n)

  • 空间复杂度: O(1)

JAVA
final class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        // 阶梯搜索需要有效的右上角起点。
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }

        int row = 0;
        int column = matrix[0].length - 1;
        // 未排除区域始终位于当前位置的左下方。
        while (row < matrix.length && column >= 0) {
            int value = matrix[row][column];
            if (value == target) return true;
            // 当前值过大可排除整列,过小可排除整行。
            if (value > target) column--;
            else row++;
        }
        return false;
    }
}

边界与易错点

  • 本题各行首元素不保证大于上一行尾元素,不能像第 74 题那样把矩阵整体拉平成有序数组。
  • 旧文件两个逐行二分实现算法同构,整理后合并为一个。
  • 读取 matrix[0] 前必须处理空矩阵。

整理来源

由旧仓库源码复核、去重并整理;展示代码已按 Java 21 语义修正明显问题。

  • leetcode/src/main/java/medium/Q240_searchMatrixII.java