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

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

相关推荐
程序猿阿森1 小时前
C语言预处理完全指南:宏定义、条件编译与头文件规范,一篇搞懂工程化编程
c语言·c++·编译
艾莉丝努力练剑1 小时前
【AI大模型接入SDK】LLMManager类架构与智能指针选型
网络·c++·人工智能·学习·面试·架构
6Hzlia1 小时前
【Classic 150 刷题计划】 LeetCode 209. 长度最小的子数组 | C++ 滑动窗口(毛毛虫算法)经典模板
c++·算法·leetcode
6Hzlia1 小时前
【Classic 150 刷题计划】 LeetCode 28. 找出字符串中第一个匹配项的下标 | C++ 滑动窗口与子串比对
c++·算法·leetcode
wuminyu9 小时前
Kafka中sendfile与mmap实现机制解析
java·linux·c语言·jvm·c++
GreenTea10 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
Bode_200210 小时前
多资源规划(含生产调度、库存管理及产能规划)的创新优化算法
算法·调度
Logic10111 小时前
C语言/数据结构位运算题解:异或XOR找出蛋糕订单中的“VIP独特口味“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
土司大王11 小时前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode