LeetCode 240. 搜索二维矩阵 II,为什么从右上角开始查找?
一、题目描述
给定一个矩阵:
- 每一行从左到右递增
- 每一列从上到下递增
判断目标值 target 是否存在于矩阵中。
示例:
python
[
[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]
]
查找:
python
target = 5
返回:
python
True
二、暴力搜索
最直接的方法:
遍历整个矩阵。
python
for row in matrix:
for num in row:
if num == target:
return True
复杂度:
python
O(m*n)
虽然能做出来,但没有利用矩阵有序的特点。
三、为什么选择右上角?
矩阵具有两个方向的有序性:
python
行:从左到右递增
列:从上到下递增
观察右上角:
python
15
它有一个特殊性质:
- 它是当前行最大值
- 它是当前列最小值
因此可以一次排除一整行或一整列。
四、核心贪心思想
假设当前位置:
python
cur = matrix[i][j]
情况1:找到目标
python
cur == target
直接返回:
python
True
情况2:当前值太大
python
cur > target
例如:
python
target = 10
cur = 15
因为这一列从上到下递增。
当前位置已经大于目标。
下面元素只会更大。
所以:
python
这一整列都不可能有答案
直接左移:
python
j -= 1
情况3:当前值太小
例如:
python
cur = 7
target = 10
当前行左边更小。
肯定也不可能是答案。
所以:
python
这一整行都可以排除
直接下移:
python
i += 1
五、为什么不能从左上角开始?
左上角:
python
1
如果:
python
target = 5
你只知道:
python
5 > 1
但:
python
右边更大
下面也更大
不知道该往哪走。
无法排除区域。
六、右上角查找过程演示
查找:
python
target = 5
开始:
python
15
15 > 5
左移:
python
11
11 > 5
继续左移:
python
7
7 > 5
继续左移:
python
4
4 < 5
下移:
python
5
找到目标。
结束。
七、完整代码
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
m = len(matrix)
n = len(matrix[0])
i = 0
j = n - 1
while i < m and j >= 0:
cur = matrix[i][j]
if cur == target:
return True
elif cur > target:
j -= 1
else:
i += 1
return False
八、复杂度分析
每一步:
- 要么删除一整行
- 要么删除一整列
因此:
最多移动:
python
m + n
次。
时间复杂度:
python
O(m+n)
空间复杂度:
python
O(1)
九、高频易错点
1、循环条件写错
正确:
python
while i < m and j >= 0
错误:
python
j >= n - 1
会导致循环提前结束。
2、起点选错
正确:
python
右上角
或:
python
左下角
错误:
python
左上角
右下角
无法确定唯一移动方向。
3、忘记处理空矩阵
必须先判断:
python
if not matrix or not matrix[0]:
否则:
python
matrix[0]
会直接报错。
十、一句话总结
这道题最关键的不是二分查找,而是利用矩阵行列同时有序的特点,从右上角开始,每次排除一整行或一整列,将搜索范围不断缩小,最终实现 O(m+n) 的高效查找。