小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
从下列矩阵中, 查找数字7, 有则返回true; 没有则返回false.
自己的思路
当看到这个题目时, 我脑瓜里跳出的想法是可以从矩阵的对角线上入手, 拿当前对角线上的值与要查找的目标值进行比较, 如果相等, 则返回true; 如果该值大于查找值, 则应该在当前位置的上边或者左边; 如果该值小于查找值, 则查找值应该在当前位置的下边或者右边.
出现的问题
假设该矩阵是一个方形矩阵, 而且对角线的值大于查找值, 在这种情况下, 需要在当前行中向左遍历和在当前列中向上遍历.
如果该矩阵不是一个方形矩阵, 那么遇到的问题就更加复杂了.
随着遍历对角线的次数, 问题规模并没有大幅度减小, 而且还要处理非方形矩阵的情况, 所以当前思路想到这里的时候, 我就放弃了.
比较好的思路
- 从右上角进行作为切入点, 如果当前位置的值是我们的查找值, 则返回true.
- 如果当前位置的值小于查找值, 则表明当前行所有的值都是小于查找值的, 进向下移动一行进行查找.
- 如果当前位置的值大于查找值, 则表明当前列所有的值都是大于查找值的, 则向左移动一列进行查找.
- 重复1, 2, 3步, 进到找到查找值, 返回true; 或者遍历完当前矩阵没有找到查找值, 返回false.
当然也可以从左下角作为切入点, 原理同上.
代码
以右上角作为切入点
private boolean searchDstFromRightTop(int[][] list, int dst) {
// 边界判断
if (list == null || list.length == 0 || list[0].length == 0) {
return false;
}
int rows = list.length;
int cols = list[0].length;
// 以右上角作为切入点, 因此坐标为第0行, 列为总列数-1列
int row = 0;
int col = cols - 1;
// 循环条件: 最大行数为总行数-1, 最小列数为0
while (row < rows && col >= 0) {
// 如果当前值为查找值, 则返回true
if (list[row][col] == dst) {
return true;
} else if (list[row][col] > dst) { // 如果当前值大于查找值, 则列数-1, 继续查找
System.out.println("col--, row: " + row + ", col: " + col);
col--;
} else { // 如果当前值小于查找值, 则行数+1, 继续查找
System.out.println("row++, row: " + row + ", col: " + col);
row++;
}
}
return false;
}
以左下角作为切入点
private boolean searchDstLeftBottom(int[][] list, int dst) {
// 边界判断
if (list == null || list.length == 0 || list[0].length == 0) {
return false;
}
// 总行数
int rows = list.length;
// 总列数
int cols = list[0].length;
// 以左下角作为切入点, 因此坐标为总行数-1行, 第0列
int row = rows - 1;
int col = 0;
// 循环条件: 最小行数为第0行, 最大列为总列数-1列
while (col < cols && row >= 0) {
// 如果当前值为查找值, 则返回true
if (list[row][col] == dst) {
return true;
} else if (list[row][col] > dst) { // 如果当前值大于查找值, 则行数-1, 继续查找
System.out.println("col--, row: " + row + ", col: " + col);
row--;
} else { // 如果当前值小于查找值, 则列表+1, 继续查找
System.out.println("row++, row: " + row + ", col: " + col);
col++;
}
}
return false;
}
总结
解决本题需要了解数组的各种特性以及分析问题的能力. 也就是将复杂问题化解为简单问题的能力, 将抽象问题化解为具体问题的能力.
当我们需要解决一个复杂的问题时候, 应该从一个具体的问题入手, 通过分析简单具体的问题, 来寻找普遍的规律.