编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例 1:
![](https://img-blog.csdnimg.cn/img_convert/8a065768b742ff16029e80a04f9d3b65.jpeg)
输入: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:
![](https://img-blog.csdnimg.cn/img_convert/8a065768b742ff16029e80a04f9d3b65.jpeg)
输入: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
解法思路:
1.直接查找
//给定一个二维数组
// const a = new Array(4).fill(0).map(() => new Array(5).fill(0));
//计算行的长度:4
//let length1 = arr.length;
//计算列的长度:5
//int length2 = arr[0].length;
var searchMatrix = function(matrix, target) {
for(let i = 0; i < matrix.length; i++){
for(let j = 0; j < matrix[i].length; j++){
if(matrix[i][j] == target)
return true;
}
}
return false;
};
复杂度分析
时间复杂度:O(mn)。
空间复杂度:O(1)。
2.二分查找
解法思路
看到有序,第一反应就是二分查找。最直接的做法,一行一行的进行二分查找即可。
此外,结合有序的性质,一些情况可以提前结束。
某一行的第一个元素大于了 target ,当前行和后边的所有行都不用考虑了,直接返回 false。
某一行的最后一个元素小于了 target ,当前行就不用考虑了,换下一行。
var searchMatrix = function(matrix, target) {
for(const row of matrix){
// 取出二维数组的每行 为一个一维数组
let res = erFenSearch(row, target);
// 如果二分查找查到了target 就返回他的数组下标 下标一定是>=0的 此时就是查找到了
if(res >= 0){
return true;
}
}
return false;
};
// 定义二分查找函数
const erFenSearch = (nums, target) => {
let L = 0;
let R = nums.length - 1;
while(L<=R){
let mid = Math.floor((R -L)/2) + L;
if(nums[mid] == target){
return mid;
}else if(nums[mid] < target){
L = mid + 1;
}else{
R = mid - 1;
}
}
return -1;
}
复杂度分析
时间复杂度:O(mlogn)。对一行使用二分查找的时间复杂度为 O(logn),最多需要进行 m 次二分查找。
空间复杂度:O(1)。
3.不一样的二分查找(Z字形查找)
因为这个二维数组组成的表格,无论是从左往右,还是从上往下都是依次增大的数列,那么我们便可以从表格的右上角那个数开始判断,如果target小于这个值,那么那个数所在的那一列就可以去掉;如果target大于这个值,那么那个数所在的那一行就可以去掉,直至找到target或遍历完整个二维数组。
推荐后两种!
var searchMatrix = function(matrix, target) {
// 首先定义出右上角数字的行列下标
for(let i = 0, j = matrix[i].length - 1; i < matrix.length && j >= 0; i++){
// 如果这个数就是target 直接return true
if(matrix[i][j] == target){
return true;
}
// 如果target大于右上角那个数 说明这一行就可以不用看了 直接continue下一次循环 每次循环只操作行的参数i
else if(matrix[i][j] < target){
continue;
}
// 如果target小于右上角那个数 说明这一列就不用看了 直接j-- 到当前列的前一列 但是此时行数不能改变 还是当前这行 所i=i-1
else{
j--;
i = i - 1;
}
}
return false;
};
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix.length == 0 || matrix[0].length == 0) {
return false;
}
int row = 0;
int col = matrix[0].length - 1;
while (row < matrix.length && col >= 0) {
if (target > matrix[row][col]) {
row++;
} else if (target < matrix[row][col]) {
col--;
} else {
return true;
}
}
return false;
}
}
var searchMatrix = function(matrix, target) {
if (matrix.length == 0 || matrix[0].length == 0) {
return false;
}
let H = 0;
let L = matrix[0].length - 1;
while(H < matrix.length && L >= 0){
if(matrix[H][L] == target){
return true;
}else if(matrix[H][L] < target){
H++;
}else{
L--;
}
}
return false;
};
复杂度分析
时间复杂度就是每个节点最多遍历一遍了,O(m + n)。
空间复杂度:O(1)。
![](https://img-blog.csdnimg.cn/img_convert/fcf46bbfe3b8dbbc4139b8ed7f31f675.jpeg)