搜索二维矩阵 II
题目描述:
编写一个高效的算法来搜索 m x n
矩阵 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
提示:
m == matrix.length
n == matrix[i].length
1 <= n, m <= 300
-109 <= matrix[i][j] <= 109
- 每行的所有元素从左到右升序排列
- 每列的所有元素从上到下升序排列
-109 <= target <= 109
方法一思路分析:
最先想到的暴力解法,不考虑数组特性挨个遍历一遍。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
for(int[] row : matrix){
for(int num : row){
if(num == target)
return true;
}
}
return false;
}
}
方法二思路分析:
二分法,即在每行查找时使用二分法
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
// 遍历矩阵的每一行
for (int[] row : matrix) {
// 对当前行进行二分查找
int index = search(row, target);
// 如果找到了目标值,则返回 true
if (index >= 0) {
return true;
}
}
// 遍历完所有行都没有找到目标值,返回 false
return false;
}
// 使用二分查找算法在当前行中查找目标值
// 如果找到目标值,返回其索引;否则返回 -1
public int search(int[] nums, int target) {
int low = 0, high = nums.length - 1;
// 当 low 小于等于 high 时,继续查找
while (low <= high) {
// 防止 (high + low) 直接相加导致溢出,使用 low + (high - low) / 2
int mid = low + (high - low) / 2;
int num = nums[mid];
// 如果找到了目标值,返回其索引
if (num == target) {
return mid;
} else if (num > target) {
// 如果中间值大于目标值,则在左半部分继续查找
high = mid - 1;
} else {
// 如果中间值小于目标值,则在右半部分继续查找
low = mid + 1;
}
}
// 没有找到目标值,返回 -1
return -1;
}
}
方法三思路分析:
观察下图:
以9为例可以看到9的正上方和左边全是小于9的数值,而9的下方和右边是大于9的数值。
根据这个矩阵的排序特性,我们可以从矩阵的右上角或左下角开始搜索,因为从这两个角开始搜索可以让我们同时利用行和列的排序特性来排除大量不可能包含目标值的区域。
我们使用右上角为例的搜索算法步骤:
- 初始化行索引
row
为 0(矩阵的最上面一行),列索引col
为n-1
(矩阵的最右边一列)。 - 当
row < m
且col >= 0
时,执行以下步骤:- 如果
matrix[row][col] == target
,则找到目标值,返回true
。 - 如果
matrix[row][col] > target
,由于列是升序的,当前列中row
以下的元素都大于target
,因此将col
减 1(向左移动一列)。 - 如果
matrix[row][col] < target
,由于行是升序的,当前行中col
左边的元素都小于target
,因此将row
加 1(向下移动一行)。
- 如果
- 如果遍历完整个矩阵都没有找到目标值,则返回
false
。
代码实现:
public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || 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;
while (row < m && col >= 0) {
if (matrix[row][col] == target) {
return true;
} else if (matrix[row][col] > target) {
col--; // 目标小于当前值,向左移动
} else {
row++; // 目标大于当前值,向下移动
}
}
return false;
}
}