🚀 从暴力解法到线性查找:LeetCode 240 题解
摘要:本文深入剖析 LeetCode 240 题「搜索二维矩阵 II」。面对行与列均有序的矩阵,我们不能简单套用二分查找,而应利用其特性从右上角开始线性查找,将时间复杂度优化至 。
🔑 核心知识点:有序矩阵的特性与“Z 字形”查找
在解决这道题之前,我们需要理解二维矩阵中行有序和列有序意味着什么,以及如何利用这个特性。
1. 二分查找的局限性
对于普通的有序数组,我们习惯使用二分查找。但在二维矩阵中,如果直接对每一行进行二分查找,时间复杂度是 。
- 问题:这虽然可行,但没有充分利用“列也是有序”这一条件。
2. 为什么从“右上角”开始?
这是本题最精妙的思路。我们选择从矩阵的右上角(或者左下角)作为起点,可以将矩阵看作一棵二叉搜索树:
- 当前元素 >> 目标值:由于该行右边的数都比当前数大,该行无解,只能向下走(寻找更大的数)。
- 当前元素 << 目标值:由于该列下方的数都比当前数大,该列无解,只能向左走(寻找更小的数)。
- 当前元素 == 目标值:找到答案,返回
True。
这种策略每一步都能排除一行或一列,最终形成一个类似“Z”字形的搜索路径,时间复杂度仅为 。
💻 题目解析:LeetCode 240. 搜索二维矩阵 II
📝 题目描述
- 每行的元素从左到右升序排列。
- 每列的元素从上到下升序排列。
📊 示例
输入: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
💻 代码实现(Python)
根据上述思路,我们从右上角开始遍历,利用指针模拟“向下”和“向左”的移动。
from typing import List
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
if not matrix or not matrix[0]:
return False
# 初始化指针在右上角
# row: 行索引,col: 列索引
row, col = 0, len(matrix[0]) - 1
# 当指针在矩阵范围内时循环
while row < len(matrix) and col >= 0:
if matrix[row][col] == target:
return True
elif matrix[row][col] > target:
# 当前数大于目标,向左走(缩小列)
col -= 1
else:
# 当前数小于目标,向下走(增大行)
row += 1
# 遍历结束未找到
return False
📊 复杂度分析
| 维度 | 分析结果 | 说明 |
|---|---|---|
| 时间复杂度 | O(m+n) | 最坏情况下,指针需要从右上角走到左下角,遍历 m+n 个元素。 |
| 空间复杂度 | O(1) | 只使用了常数级别的额外空间(row, col 指针)。 |
📝 总结
这道题是经典的算法思维题。关键在于打破常规,不要试图把二维问题强行降维成一维去套用二分查找。利用矩阵的有序性,通过选取合适的起点(右上角或左下角),可以将查找过程转化为线性时间复杂度的高效操作。