搜索二维矩阵

题目理解

matrix 是一个 行排序矩阵,即:

• 每一行的元素从 左到右递增。

• 每一行的 最右元素 一定大于等于该行所有元素,且小于等于下一行的所有元素(如果有下一行)。

目标:判断 target 是否在 matrix 中。

解法思路

我们采用 两阶段二分查找 进行优化:

  1. 第一步 :遍历每一行,找到可能包含 target 的行。

• 如果 target 大于 当前行的最后一个元素,则 target 只能在后面的行,继续下一行。

• 否则,该行 可能包含 target ,进入 第二步。

  1. 第二步 :在该行使用 二分查找 搜索 target。

• 如果找到,返回 true。

• 否则,返回 false(因为 target 只可能在当前行,不在其他行)。

代码解析

cpp 复制代码
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int n = matrix.size();     // 矩阵行数
        int m = matrix[0].size();  // 矩阵列数

        for (int i = 0; i < n; i++) {  // 遍历每一行
            if (target > matrix[i][m - 1]) continue; // `target` 大于该行最后一个元素,跳过
            
            // 二分查找
            int left = 0, right = m - 1;
            while (left <= right) {
                int mid = left + (right - left) / 2;  // 防止溢出

                if (matrix[i][mid] == target) return true; // 找到 `target`
                else if (matrix[i][mid] > target) right = mid - 1; // 缩小右边界
                else left = mid + 1;  // 缩小左边界
            }
            break;  // 只可能在这一行找到,找不到就退出
        }
        return false;  // 遍历完所有可能行,仍找不到
    }
};

详细运行步骤

示例 1

复制代码
vector<vector<int>> matrix = {
    {1, 3, 5, 7},
    {10, 11, 16, 20},
    {23, 30, 34, 60}
};
int target = 3;

矩阵表示:

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

执行过程

第一步:寻找目标行

• 遍历第 0 行,最后元素 7:

• target = 3 ≤ 7,可能在当前行 ,进入 二分查找。

第二步:二分查找

• left = 0, right = 3, mid = (0+3)/2 = 1

• matrix01 = 3 == target,返回 true。

✅ 最终结果:true

示例 2

复制代码
vector<vector<int>> matrix = {
    {1, 3, 5, 7},
    {10, 11, 16, 20},
    {23, 30, 34, 60}
};
int target = 13;

第一步:寻找目标行

• 第 0 行 :7 < 13,跳过。

• 第 1 行 :20 ≥ 13,进入 二分查找。

第二步:二分查找

• left = 0, right = 3, mid = 1

• matrix11 = 11 < target → left = mid + 1 = 2

• left = 2, right = 3, mid = 2

• matrix12 = 16 > target → right = mid - 1 = 1

• left > right,找不到,返回 false。

❌ 最终结果:false

示例 3

复制代码
vector<vector<int>> matrix = {
    {1, 3, 5, 7},
    {10, 11, 16, 20},
    {23, 30, 34, 60}
};
int target = 60;

第一步:寻找目标行

• 第 0 行 :7 < 60,跳过。

• 第 1 行 :20 < 60,跳过。

• 第 2 行 :60 ≥ 60,进入 二分查找。

第二步:二分查找

• left = 0, right = 3, mid = 1

• matrix21 = 30 < target → left = mid + 1 = 2

• left = 2, right = 3, mid = 2

• matrix22 = 34 < target → left = mid + 1 = 3

• left = 3, right = 3, mid = 3

• matrix23 = 60 == target,返回 true。

✅ 最终结果:true

复杂度分析

时间复杂度

  1. 遍历行:O(N)

• 最坏情况,可能要遍历所有行。

• 最优情况,第一行就满足条件。

  1. 二分查找:O(log M)

• 在选定的一行内,二分查找 O(log M)。

总复杂度:

通常 M 很大时,log M 远小于 N,所以二分查找优化明显。

空间复杂度

• 只使用了常数变量 left、right、mid,不需要额外的数组。

优化建议

当前算法在最坏情况下需要遍历所有行。可以使用 一次性二分查找 代替两次:

  1. 把矩阵视为一个一维数组,索引映射:

  2. 直接对整个矩阵二分查找。

cpp 复制代码
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int n = matrix.size(), m = matrix[0].size();
        int left = 0, right = n * m - 1;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            int val = matrix[mid / m][mid % m];  // 计算对应的行列索引

            if (val == target) return true;
            else if (val > target) right = mid - 1;
            else left = mid + 1;
        }
        return false;
    }
};

时间复杂度:O(log (N * M))

空间复杂度:O(1)

这个方法比你的方法 更快 ,适用于 行列均递增的矩阵。

总结

✅ 你的方法

• 两步二分(O(N + log M))。

• 适用于行递增的矩阵。

✅ 优化方案

• 一维二分(O(log (N*M)),更快)。

• 适用于行列均递增的矩阵。

👉 如果 matrix 行列都递增,建议用 O(log(N*M)) 版本!

相关推荐
ZhengEnCi3 小时前
Agent 架构怎么选:从单 Agent 到多 Agent 编排的选型决策指南
算法·架构
秋天的怀念_David4 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Pniubi4 小时前
力扣283移动零(双指针法)
算法·leetcode·职场和发展
hhb_6184 小时前
大模型落地三重优化实战
人工智能·算法·机器学习
云和数据.ChenGuang5 小时前
光哥说Python RAG 系统需要哪些评估指标:从检索到生成的全链路评测指南
网络·人工智能·python·算法·langchain
2601_970703836 小时前
工业除湿机租赁:把一份租金合同拆开看
大数据·数据结构·算法·数据库架构·推荐算法
心中有你02146 小时前
Java实现Dijkstra最短路径算法(邻接表 + 优先队列)
java·数据库·算法
ZhengEnCi7 小时前
同样的模型,为什么本地和云 API 差别那么大:量化精度、聊天模板与采样参数的三大元凶
人工智能·算法·llm
Flynn Liang8 小时前
RAG 答非所问/幻觉怎么破?Spring AI QuestionAnswerAdvisor 召回优化实战(TopK/重排/混合检索)
人工智能·算法·spring·rag·幻觉·springai
liminla!8 小时前
SQL 从入门到进阶:语法速查与实战练习(完整优化版)
数据库·sql·算法