【矩阵-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 → 下移
记忆口诀 "右上角出发,大了往左,小了往下。"

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

相关推荐
星光开发者16 分钟前
基于决策树随机森林算法的小说推荐系统的设计与实现-计算机毕设【课程设计】78485
vue.js·算法·微信小程序·django·php·课程设计·express
-森屿安年-25 分钟前
按身高排序
c++·算法
程序员清风43 分钟前
算法与数据结构入门:复杂度、数组与链表
数据结构·算法·链表
无定义_1 小时前
Codeforces Round 1124 (Div. 2)
算法
(Charon)2 小时前
【C++面试】vector底层原理:扩容、拷贝移动与迭代器失效
c++·面试
朔北之忘 Clancy2 小时前
青少年软编等考七级题解目录
开发语言·c++·青少年编程·gesp·csp·信奥赛·noi
汉克老师2 小时前
GESP2026年9月认证C++七级( 第一部分选择题(8~15题)精讲
c++·gesp·小学生·学c++编程
Mr_Macallon2 小时前
C++回顾(基础)(01)
c语言·开发语言·c++·学习
垆边人似月.2 小时前
任务混部(200 分档)
算法
言乐63 小时前
Python区分广度优先深度优先宽度优先的区别
python·算法·深度优先·广度优先·宽度优先