题目来源:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/
Problem
在一个 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
Idea
找大小,可以用二分法,快。
考虑空间局部性,计算机再调用数组时会考虑将相邻数据调用到内存中以提高访问效率,所以代码编写应该考虑以行数组进行数据查找。
Navie Solution
先考虑一维数组的二分查找,再扩展为二维的。
0 1 2 3 m =4
0 1 2 m = 3
找 0 找 1 找 -1 找 3 找 4
middleCol = m / 2;
leftBound = -1
rightBound = m
while(true) {
// 终止条件
if (middleCol == leftBound) {// 找到最左边了
return false;
}
if (middleCol == rightBound) {// 找到最右边了
return false;
}
// find 1123
if (arr[middleCol] == target) { // 1123 != 1252
return true;
} else if (arr[middleCol] > target) {
leftShift = ( middleCol - leftBound ) / 2
if (leftShift < 1)
leftShift = 1
rightBound = middleCol;
middleCol = middleCol - leftShift;
} else if (arr[middleCol] < target) {
rightShift = ( rightBound - middleCol) / 2
if (rightShift < 1)
rightShift = 1
leftBound = middleCol;
middleCol = middleCol + rightShift;
}
}
Solution1
for i in m:
result = CALL NAIVE SOLUTIOM in raw[i];
if result == true
return true
return false
Analysis:时间O(M x log(N)),空间O (M)
Debugging
Line 14: java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 5
在执行执行代码的时候,能得到正确结果,但提交代码时程序会出错。
在函数指针进行移动时,出现了超出上下限的结果。原因是在进行分治时,处理的数据上限rightBound和下限leftBound,以及数据量rightBound-leftBound也会跟着改变。
Final Solution
class Solution {
private boolean getRowResult(int[] arr1, int target) {
int rightBound = arr1.length;
int leftBound = -1;
int middleCol = rightBound / 2;
while (true) {
if (middleCol <= leftBound) {
return false;
}
if (middleCol >= rightBound) {
return false;
}
if (arr1[middleCol] == target) {
return true;
}
if (arr1[middleCol] > target) {
int leftShift = (middleCol - leftBound) / 2;
if (leftShift < 1 ) {
leftShift = 1;
}
rightBound = middleCol;
middleCol = middleCol - leftShift;
} else if (arr1[middleCol] < target) {
int rightShift = (rightBound - middleCol) / 2;
if (rightShift < 1) {
rightShift = 1;
}
leftBound = middleCol;
middleCol = middleCol + rightShift;
}
}
}
public boolean findNumberIn2DArray(int[][] matrix, int target) {
int rowNum = matrix.length;
boolean result = false;
for (int i = 0; i < rowNum; i++) {
result = getRowResult(matrix[i], target);
if (result == true) {
return true;
}
}
return false;
}
}
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:44.4 MB, 在所有 Java 提交中击败了79.95%的用户
Rethink
其实可以对列也使用二分法,但是由于操作系统存储的局部性特征,效果可能没有Final Solution好,这点可以从执行用时可以看出来。