在一个 n * m 的二维数组中,每一行都按照从左到右 非递减 的顺序排序,每一列都按照从上到下 非递减 的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 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。
给定 target = 20,返回 false。
限制:
0 <= n <= 1000
0 <= m <= 1000
解题思路:
若使用暴力法遍历矩阵 matrix ,则时间复杂度为 O(NM) 。暴力法未利用矩阵 “从上到下递增、从左到右递增” 的特点,显然不是最优解法。
如下图所示,我们将矩阵逆时针旋转 45° ,并将其转化为图形式,发现其类似于 二叉搜索树 ,即对于每个元素,其左分支元素更小、右分支元素更大。因此,通过从 “根节点” 开始搜索,遇到比 target 大的元素就向左,反之向右,即可找到目标值 target 。
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if (matrix.length == 0 || matrix[0].length == 0) {
return false;
}
int n = matrix.length;
int m = matrix[0].length;
int i = n - 1, j = 0;
while (i >= 0 && j <= m - 1) {
if (matrix[i][j] == target) {
return true;
}
if (matrix[i][j] > target) {
i--;
} else if (matrix[i][j] < target) {
j++;
}
}
return false;
}
}
方法二:剪枝暴力法
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if (matrix.length == 0 || matrix[0].length == 0) {
return false;
}
int n = matrix.length;
int m = matrix[0].length;
if (target < matrix[0][0] || target > matrix[n - 1][m - 1]) {
return false;
}
int i = 0, j = n - 1, targetN = 0;
while (i < n || j > 0) {
if (matrix[i][0] == target || matrix[j][0] == target) {
return true;
}
if (matrix[i][0] < target) {
i++;
} else {
targetN = --i;
break;
}
if (matrix[j][0] > target) {
j--;
} else {
targetN = j;
break;
}
}
i = 0;
j = m - 1;
int targetM = 0;
while (i < m || j > 0) {
if (matrix[0][i] == target || matrix[0][j] == target) {
return true;
}
if (matrix[0][i] < target) {
i++;
} else {
targetM = --i;
break;
}
if (matrix[0][j] > target) {
j--;
} else {
targetM = j;
break;
}
}
for (int p = 1; p <= targetN; p++) {
for (int q = 1; q <= targetM; q++) {
if (matrix[p][q] == target) {
return true;
}
}
}
return false;
}
}