本题代码已上传到:gitbub
题目
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
图1:
题目分析
这题相对简单,就是一个矩阵搜索问题。就是从一个角开始搜索(右上/左下)。因为矩阵是有序的,在右上/左下的数字,必定是这行或这列的极值(最大或最小值),只要通过一次比较,那必定能排除一行或一列,通过不断循环,很快就能找到结果。
图2的流程很形象的解释了解题逻辑,比如搜索整数7,本题是递增序列,那么如果我们从右上角开始,右上角的9,是9所在行的最大值,是9所在列的最小值,只要和给定的数字7比较大小,就知道可以去掉一行或一列了,这里是去掉9所在的第四列。然后进入下次循环,一直比较直到找到数字返回true,或者矩阵为空返回false。
图2:
那么为什么不从中间开始呢,看看下边图3就大致理解了,这个书中的解法里其实有个降维的思想。如果从矩阵中间开始搜索,除边角外任何一个位置都会有4个方向,虽然通过比较,能去掉一个角(图中白色),表面看起来是去掉了2个方向,但是移动比较位置后又会有4个方向(或3个),无穷无尽,也许最后能找到结果,但是程序的逻辑会变得非常复杂(几个方向意味着几次比较和几个可能),而本题的解法,直接从4个方向降为2个方向,直接简化了判断逻辑,且缩小后的矩阵依然符合程序的判断逻辑。
图3:
代码实现
private static boolean checkMatrix(int[][] matrix, int num) {
boolean exist = false;
if (matrix != null && matrix.length > 0 && matrix[0].length > 0) {
// TODO 这里省略对每行长度的检查,只是简单从第1行判断是否为空,如果考虑健壮性,是需要检查的,不在本题的考察范围
int row = matrix.length;
int col = matrix[0].length;
for (int i = 0, j = col - 1; i < row && j >= 0; ) {
if (matrix[i][j] == num) {
exist = true;
break;
} else if (matrix[i][j] > num) {
j--;
} else {
i++;
}
}
} else {
System.out.println("matrix is empty");
}
return exist;
}
测试用例
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 8, 9, 11},
{2, 4, 9, 12, 13},
{4, 7, 10, 13, 16},
{6, 8, 11, 15, 21}};
int num1 = 1;
System.out.println(num1 + " in matrix is " + checkMatrix(matrix, num1));
int num2 = 21;
System.out.println(num2 + " in matrix is " + checkMatrix(matrix, num2));
int num3 = 16;
System.out.println(num3 + " in matrix is " + checkMatrix(matrix, num3));
int num4 = 0;
System.out.println(num4 + " in matrix is " + checkMatrix(matrix, num4));
int num5 = 30;
System.out.println(num5 + " in matrix is " + checkMatrix(matrix, num5));
int num6 = 3;
System.out.println(num6 + " in matrix is " + checkMatrix(matrix, num6));
int num = 4;
matrix = null;
System.out.println(num + " in matrix is " + checkMatrix(matrix, num));
}
测试结果
1 in matrix is true
21 in matrix is true
16 in matrix is true
0 in matrix is false
30 in matrix is false
3 in matrix is false
matrix is empty
4 in matrix is false