【矩阵-2】240.搜索二维矩阵 II

题目描述:

编写一个高效的算法来搜索 m xn 矩阵 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

解题思路:

我本来想的很简单,就是分别从左上角的横向和纵向开始往后遍历寻找,但如果对每一行遍历一遍,再对每一列遍历一遍,同一个元素会被检查两次,浪费时间。想法方向是对的 ,但需要明确一点:如果对每一行和每一列都独立遍历,那本质上还是暴力搜索,时间复杂度是 O(m × n),无法利用矩阵的单调性优势。

核心思路:从右上角开始搜索

为什么从右上角开始?

观察矩阵的特性:

  • 右上角元素 matrix[0][n-1] 是当前行最大的 ,也是当前列最小的

  • 如果 target < matrix[0][n-1]:说明 target 不可能在这一列(因为这一列下面的都更大),向左移动

  • 如果 target > matrix[0][n-1]:说明 target 不可能在这一行(因为这一行左边的都更小),向下移动

  • 如果相等:找到了

具体过程示例:

target = 5

复制代码
matrix = [
  [1,  4,  7, 11, 15],   ← 从右上角 15 开始
  [2,  5,  8, 12, 19],
  [3,  6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

第1步: 15 > 5 → 向左移动到 11
第2步: 11 > 5 → 向左移动到 7
第3步: 7 > 5  → 向左移动到 4
第4步: 4 < 5  → 向下移动到 5
第5步: 5 == 5 → 找到!返回 true

搜索路径:

text

复制代码
[15] → [11] → [7] → [4]
                      ↓
                     [5] ✅

代码实现:

cpp 复制代码
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if (matrix.empty() || matrix[0].empty()) return false;
        
        int m = matrix.size();       // 行数
        int n = matrix[0].size();    // 列数
        
        int row = 0;          // 从右上角开始
        int col = n - 1;
        
        while (row < m && col >= 0) {
            if (matrix[row][col] == target) {
                return true;
            } else if (matrix[row][col] > target) {
                col--;  // 当前值太大,向左移动
            } else {
                row++;  // 当前值太小,向下移动
            }
        }
        
        return false;
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(m + n) 每次移动一行或一列,最多移动 m+n 次
空间复杂度 O(1) 只用了两个指针

为什么不能从左上角开始?

如果从左上角 matrix[0][0] 开始:

  • matrix[0][0] 是当前行最小 ,也是当前列最小

  • 如果 target > matrix[0][0],你不知道是该往右还是往下(两个方向都可能更大)

  • 无法做出唯一决策

同理,右下角也不行(它是当前行最大、当前列最大,两个方向都可能更小)。

只有右上角和左下角可以,因为它们一个是"行最大列最小",一个是"行最小列最大",能做出唯一决策。

另一种写法:从左下角开始

cpp 复制代码
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if (matrix.empty() || matrix[0].empty()) return false;
        
        int m = matrix.size();
        int n = matrix[0].size();
        
        int row = m - 1;  // 从左下角开始
        int col = 0;
        
        while (row >= 0 && col < n) {
            if (matrix[row][col] == target) {
                return true;
            } else if (matrix[row][col] > target) {
                row--;  // 当前值太大,向上移动
            } else {
                col++;  // 当前值太小,向右移动
            }
        }
        
        return false;
    }
};

两种写法完全等价。

四种起点对比:

起点 能否使用 原因
左上角 ❌ 两个方向都增大,无法决策
右上角 ✅ 左减小、下增大,可决策
左下角 ✅ 上减小、右增大,可决策
右下角 ❌ 两个方向都减小,无法决策

总结:

要点 说明
核心思想 从右上角(或左下角)开始,利用行列单调性缩小范围
时间复杂度 O(m + n)
空间复杂度 O(1)
关键决策 当前值 > target → 左移;当前值 < target → 下移
记忆口诀 "右上角出发,大了往左,小了往下。"

这道题是矩阵搜索 的经典题,核心是利用矩阵的行列单调性,每次排除一行或一列。

相关推荐
BK贝壳6 小时前
bool-hybrid-array 落盘我只认 .bha:用 Create_BHA / Ask_BHA 做布尔数组序列化
数据结构·python·numpy·1024程序员节
会编程的小孩6 小时前
C++ qt的安装
c++
企业数字化笔记9 小时前
视频人体姿态怎么做三维可视化?2D关键点、深度局限与技术选型
人工智能·算法·音视频
?abc!9 小时前
(数组)581. 最短无序连续子数组
数据结构·算法·leetcode
小成2023032026512 小时前
C++~07补充
开发语言·c++
小郎君65812 小时前
MPTT树复选框的半选状态:一棵百万节点树从递归到计数器,再到区间覆盖
算法
酌沧12 小时前
MemT让记忆成为模型内生能力
jvm·人工智能·算法
hold?fish:palm12 小时前
40 二叉树的直径
c++·leetcode
Shimeri13 小时前
越卷越像:我用遗传算法做了个"内卷"实验
算法·three.js·数据可视化·遗传算法·进化算法
解决小子13 小时前
【虚幻引擎】【C++】【GAS框架】构建角色基类、属性集、数值钳制
c++·笔记·游戏引擎·虚幻·gas·能力系统