Leetcode 74-搜索二维数组
1. 题目描述
编写一个高效的算法来判断?m x n?矩阵中,是否存在一个目标值。该矩阵具有如下特性:
- 每行中的整数从左到右按升序排列。
- 每行的第一个整数大于前一行的最后一个整数。
1 | 示例?1: |
2. 思路
这个题目思路也很清晰,肯定是采用两次二分查找,先二分查找到所在的行,再在这行里二分查找。
我觉得这个题目的亮点就在于在查找所在的行时略微有点不一样,例如:1
2
3
4
5matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
假如target=13,如果在行的那轮二分查找时,我们真的只naive地二分查找,此时中值为20,哦,我要找的值比中值小,右指针指向mid的前一位。
这样就错了!!!我们的target反而是落在了mid所在的那行,所以这里不仅要和行的尾部元素进行对比,也不能忘了行的头元素。
在第一次提交代码的时候,我的确考虑了这一点,不过当时用的是mid那一行的上一行的尾元素。代码大概长这样:1
2
3
4
5
6
7
8
9
10
11
12
13
14 while (row_b < row_e) {
if (target == matrix[row_m][cols - 1])
return true;
else if (target > matrix[row_m][cols - 1])
row_b = row_m + 1;
else if (target < matrix[row_m][cols - 1]) {
// 如果比上一列的最后一个大
if (target > matrix[row_m - 1][cols - 1]) // Notice: 数组越界异常
row_e = row_m;
else
row_e = row_m - 1;
}
row_m = (row_b + row_e) / 2;
}
这里有个严重的错误,当target是第一行的元素时,必然会存在数组越界,所以要略微改一下。
改成不去比较mid行的上一行的尾元素,而比较mid所在行的头元素。
3. 代码
两次二分查找AC代码,执行用时超过100%,内存消耗超过37%,这里的时间复杂度为O(log(M*N))
,空间复杂度O(1)
。
这里用的是两次二分查找,所以虽然是常数级别的内存开销,还是偏大!因为,可以完全看作是一次二分查找啊!!!
1 | /** |
下面是官方提供的一次二分查找代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
if (m == 0) return false;
int n = matrix[0].length;
// 二分查找
int left = 0, right = m * n - 1;
int pivotIdx, pivotElement;
while (left <= right) {
pivotIdx = (left + right) / 2;
pivotElement = matrix[pivotIdx / n][pivotIdx % n];
if (target == pivotElement) return true;
else {
if (target < pivotElement) right = pivotIdx - 1;
else left = pivotIdx + 1;
}
}
return false;
}
}
作者:LeetCode
链接:https://leetcode-cn.com/problems/search-a-2d-matrix/solution/sou-suo-er-wei-ju-zhen-by-leetcode/
来源:力扣(LeetCode)
666.