LeetCode 240. 搜索二维矩阵 II:单调性剪枝详解
1. 算法思想
这题属于:
text
矩阵搜索 / 单调性剪枝
也常被称为 Z 字形搜索。它不是普通二分查找:每一行、每一列分别有序,但整个矩阵按行展开后并不整体有序。
例如:
text
[
[1, 4, 7],
[2, 5, 8],
[3, 6, 9]
]
按行展开是 1, 4, 7, 2, 5, 8, 3, 6, 9,其中 7 后面是 2,因此不能把它当一维数组二分。
本题的关键是:从右上角开始,每次比较都能确定排除一整行或一整列。
2. 为什么从右上角开始
右上角 matrix[0][n - 1] 有两个相反的单调方向:
text
左边都更小。
下面都更大。
因此当前位置 matrix[row][col] 与 target 比较后,移动方向是确定的:
text
current > target:向左,排除当前列。
current < target:向下,排除当前行。
current == target:找到答案。
当前值过大,为什么排除当前列
如果:
text
current > target
当前列从上到下递增。从当前行往下的元素都满足:
text
matrix[i][col] >= current > target
整列都太大,不可能有答案,因此:
java
col--;
当前值过小,为什么排除当前行
如果:
text
current < target
当前行从左到右递增。当前剩余区域中,这一行从左边界到当前列的所有元素都满足:
text
matrix[row][j] <= current < target
整行都太小,不可能有答案,因此:
java
row++;
3. 用 target = 5 完整模拟
text
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]
]
从右上角开始:
text
row = 0, col = 4,当前值 15
15 > 5,向左。
row = 0, col = 3,当前值 11
11 > 5,向左。
row = 0, col = 2,当前值 7
7 > 5,向左。
row = 0, col = 1,当前值 4
4 < 5,向下。
row = 1, col = 1,当前值 5
找到目标。
路径是:
text
15 -> 11 -> 7 -> 4
|
v
5
因此这类搜索也叫 Z 字形搜索。
4. 为什么不会漏掉答案
当前位置始终是当前剩余区域的右上角。
text
当前值大于 target:当前列下面的值更大,整列排除安全。
当前值小于 target:当前行左边的值更小,整行排除安全。
每一步删除的都是确定不可能包含 target 的区域。搜索会在找到目标,或剩余区域为空时结束,因此不会漏掉答案。
5. Java 代码完整注释
java
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
// 空矩阵中不存在目标。
if (matrix.length == 0 || matrix[0].length == 0) {
return false;
}
int m = matrix.length;
int n = matrix[0].length;
// 从右上角开始。
int row = 0;
int col = n - 1;
// row 只向下移动,col 只向左移动。
// 任一指针越界时,说明剩余区域为空。
while (row < m && col >= 0) {
int current = matrix[row][col];
if (current == target) {
return true;
}
if (current > target) {
// 当前列从上到下递增,下面的元素只会更大。
// 所以当前列不可能有 target,向左排除它。
col--;
} else {
// 当前行从左到右递增,左边的元素只会更小。
// 所以当前行不可能有 target,向下排除它。
row++;
}
}
return false;
}
}
6. 左下角也可以
左下角同样有相反的单调方向:上面更小,右边更大。
因此从左下角开始也可以:
text
当前值大于 target:向上。
当前值小于 target:向右。
它与右上角写法本质相同。学习时固定记住右上角版本即可:
text
大了向左,小了向下。
7. 复杂度分析
每一步只会向左移动一列,或者向下移动一行。
text
最多向左 n 次。
最多向下 m 次。
所以时间复杂度是:
text
O(m + n)
额外空间复杂度是:
text
O(1)
8. 总结
这题属于矩阵搜索 / 单调性剪枝。
从右上角开始:
text
当前值 > target:当前列全都太大,向左。
当前值 < target:当前行全都太小,向下。
每一步排除一整行或一整列,因此效率是 O(m + n)。
一句话记忆:
text
从右上角开始:大了向左,小了向下。