问题描述
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
- 每行中的整数从左到右按升序排列。
- 每行的第一个整数大于前一行的最后一个整数。
示例1:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true
示例2:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:false
提示:
- m == matrix.length
- n == matrix[i].length
- 1 <= m, n <= 100
- -104 <= matrix[i] [j], target <= 104
问题思路
思路1:两次顺序查找
由题目可知,每一行、每一列的元素都是单调递增的。因此,可以首先对第一行进行一次顺序扫描,找到 target 可能存在的行,然后对那一行进行再一次的顺序扫描,即可得到结果。
实现代码如下,空间复杂度O(nm),时间复杂度O(1)。运行时间0 ms。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int n = matrix.length;
for(int i = 0; i < n; i++){
if(i == n - 1 || matrix[i+1][0] > target){
for(int j = 0; j < matrix[0].length; j++){
if(matrix[i][j] == target){
return true;
}
}
}
}
return false;
}
}
思路2:两次二分查找
思路1用到了顺序扫描,效率低下,可以考虑改成二分查找,降低算法时间复杂度。
实现代码如下,空间复杂度O(log m + log n)= O(log mn),时间复杂度O(1)。运行时间0 ms。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int row = findRow(matrix, target);
if(row < 0){
return false;
}
int col = findCol(matrix[row], target);
if(matrix[row][col] == target){
return true;
}else{
return false;
}
}
public int findRow(int[][] matrix, int target){
int left = -1;
int right = matrix.length - 1;
while(left < right){
int mid = (right - left + 1) / 2 + left;
if(matrix[mid][0] > target){
right = mid - 1;
}else{
left = mid;
}
}
return left;
}
public int findCol(int[] array, int target){
int left = 0;
int right = array.length - 1;
while(left < right){
int mid = (right + left) / 2;
if(array[mid] < target){
left = mid + 1;
}else{
right = mid;
}
}
return left;
}
}
思路3:一次二分查找
对思路2的代码可以进一步简化,即如果将matrix的每一行末尾与下一行开头进行拼接,就得到一个长度为mn的递增序列,我们对这个递增序列进行一次二分查找,即可得到结果。
实现代码如下,空间复杂度 O(log mn),时间复杂度O(1)。运行时间0 ms。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length
int n = matrix[0].length;
int left = 0;
int right = m * n - 1;
while (left <= right) {
int mid = (right - left) / 2 + left;
int x = matrix[mid / n][mid % n];
if (x < target) {
left = mid + 1;
} else if (x > target) {
right = mid - 1;
} else {
return true;
}
}
return false;
}
}