Hot 100 --- 搜索二维矩阵

本文概览:本文讲解搜索二维矩阵的核心思路:利用矩阵完全递增的性质,通过两次二分查找快速定位目标值


一、题目


二、题目分析

这题的矩阵有一个关键性质:完全递增

  • 每行从左到右递增
  • 下一行所有的数都比上一行大
  • 按照"一行一行从左到右"的顺序遍历,所有数字是递增的

比如这个矩阵:

复制代码
 1   3   5   7
10  11  16  20
23  30  34  60

展开后就是 [1, 3, 5, 7, 10, 11, 16, 20, 23, 30, 34, 60],完全递增。

基于这个性质,我们可以采取两次二分查找的方法快速找到目标值:

  1. 第一次二分:确定 target 在哪一行
  2. 第二次二分:在确定的行内查找 target

思路概览

Java 实现代码如下

java 复制代码
public boolean searchMatrix(int[][] matrix, int target) {
    int height = matrix.length;
    int width = matrix[0].length;

    int row;
    int bottom = 0;
    int top = height - 1;
    while(bottom <= top) {
        int mid = bottom + (top - bottom) / 2;
        // 目标在当前行
        if(matrix[mid][0] <= target && matrix[mid][width - 1] >= target) {
            row = mid;
            // 目标在当前行, 二分查找
            int left = 0;
            int right = width - 1;
            while(left <= right) {
                int col = left + (right - left) / 2;
                if(matrix[row][col] == target) {
                    return true;
                } else if(matrix[row][col] > target) {
                    right = col - 1;
                } else {
                    left = col + 1;
                }
            }
            return false;
        }
        // 目标在当前行之前
        else if(matrix[mid][0] > target) {
            top = mid - 1;
        }
        // 目标在当前行之后
        else if(matrix[mid][width - 1] < target) {
            bottom = mid + 1;
        }
    }
    return false;
}

思路简要说明:

  1. 第一次二分 :对行进行二分,判断 target 是否在当前行的范围内(>= 第一个元素<= 最后一个元素
  2. 第二次二分:在确定的行内,用标准的二分查找找 target
  3. 时间复杂度:O(log m + log n),m 是行数,n 是列数

三、思路详解

第一步:矩阵的关键性质

矩阵的关键性质是完全递增。这意味着:

  • 每行的第一个元素是这一行的最小值
  • 每行的最后一个元素是这一行的最大值
  • 第 i 行的所有元素都小于第 i+1 行的所有元素

所以我们可以用每行的首尾元素来判断 target 是否在这一行:

复制代码
matrix[mid][0] <= target && matrix[mid][width-1] >= target
第二步:第一次二分------确定行

对行进行二分查找,每次取中间行 mid,判断 target 是否在这一行的范围内:

  • matrix[mid][0] <= target && matrix[mid][width-1] >= target:target 在这一行,进入第二次二分
  • matrix[mid][0] > target :target 在这一行之前(上面的行),更新 top = mid - 1
  • matrix[mid][width-1] < target :target 在这一行之后(下面的行),更新 bottom = mid + 1
第三步:第二次二分------确定列

确定了行 row 之后,在这一行内用标准的二分查找找 target:

  • left = 0right = width - 1
  • mid = left + (right - left) / 2
  • matrix[row][mid] == target:找到,返回 true
  • matrix[row][mid] > target:target 在左边,right = mid - 1
  • matrix[row][mid] < target:target 在右边,left = mid + 1
第四步:完整执行过程

以这个矩阵为例,target = 11

复制代码
 1   3   5   7
10  11  16  20
23  30  34  60

第一次二分:确定行

复制代码
初始:bottom=0, top=2

第 1 轮:
  mid = 0 + (2-0)/2 = 1
  matrix[1][0] = 10, matrix[1][3] = 20
  10 <= 11 && 11 <= 20 → target 在第 1 行 ✓
  进入第二次二分

第二次二分:确定列

复制代码
初始:left=0, right=3

第 1 轮:
  col = 0 + (3-0)/2 = 1
  matrix[1][1] = 11 == 11 → 找到!返回 true ✓

再举一个找不到的例子,target = 13

第一次二分:确定行

复制代码
初始:bottom=0, top=2

第 1 轮:
  mid = 1
  matrix[1][0] = 10, matrix[1][3] = 20
  10 <= 13 && 13 <= 20 → target 在第 1 行 ✓
  进入第二次二分

第二次二分:确定列

复制代码
初始:left=0, right=3

第 1 轮:
  col = 1, matrix[1][1] = 11 < 13
  left = 2

第 2 轮:
  left=2, right=3
  col = 2, matrix[1][2] = 16 > 13
  right = 1

第 3 轮:
  left=2, right=1
  left > right,退出循环
  返回 false
第五步:时间复杂度分析
  • 第一次二分:对行进行二分,时间复杂度 O(log m),m 是行数
  • 第二次二分:对列进行二分,时间复杂度 O(log n),n 是列数
  • 总时间复杂度:O(log m + log n)

如果直接遍历整个矩阵,时间复杂度是 O(m × n)。二分查找的优势非常明显。


四、总结

搜索二维矩阵的核心是利用矩阵完全递增的性质,通过两次二分查找快速定位目标值:

  1. 第一次二分:确定 target 在哪一行(用每行的首尾元素判断范围)
  2. 第二次二分:在确定的行内查找 target

这个思路可以推广到所有"有序矩阵查找"类题目。

相关推荐
M78佐菲17 分钟前
Linux学习笔记:进程
linux·笔记·学习·算法
liangshanbo121533 分钟前
虚拟列表深度面试题整理
java·开发语言·前端
gugucoding1 小时前
59. 【Java】Spring Boot 入门:第一个 Web 应用
java·开发语言·spring boot
lilian2331 小时前
Harmony os 技术实战|拼豆制图43:压缩字符矩阵上线前如何拦住错位图纸
开发语言·前端·华为·矩阵·harmonyos
10mAh2 小时前
【Java】HashMap 的 put 到底做了什么?——冲突、扩容与树化实测
java·开发语言·hash
徐小夕2 小时前
表格、文档、甘特、大屏、表单一站打通:pxcharts超级表格4.0正式上线!
前端·算法·github
ASKED_20192 小时前
从矩阵到秩:理解大模型参数与 LoRA 微调
线性代数·矩阵
Xin7702 小时前
LeetCode 23.合并 K 个升序链表(分治递归)
leetcode
我命由我123452 小时前
人脸识别 - 勒克斯(光线照射到物体表面上的明亮程度)
android·java·学习·java-ee·人脸识别·学习方法·android runtime