题目
二维数组中,每一行按照 从左到右递增 顺序排序,每一列按照 从上到下递增 顺序排序,输入一个二维数组和一个整数,判断数组中是否包含该整数
| 11 | 12 | 13 | 14 | 15 | 16 |
|---|---|---|---|---|---|
| 21 | 22 | 23 | 24 | 25 | 26 |
| 31 | 32 | 33 | 34 | 35 | 36 |
| 41 | 42 | 43 | 44 | 45 | 46 |
| 51 | 52 | 53 | 54 | 55 | 56 |
初始化二维数组
int rowNumber = 5;
int columnNumber = 6;
int[][] arr = new int[rowNumber][columnNumber];
for (int row = 1; row < (rowNumber + 1); row++) {
for (int column = 1; column < (columnNumber + 1); column++) {
arr[row - 1][column - 1] = row * 10 + column;
}
}
方案一:暴力破解
-
判断传入的数组是否是空或者集合长度为0,如果为0说明不存在数据,直接返回不存在
-
通过循环每一行数据,判断二维数组中是否存在该数据,通过需要查找的值与当前位置的值进行比较,判断下一步的动作
-
当前位置值小于需要查询的值,继续查询
-
当前位置值等于需要查询的值,返回存在,跳出查询
-
当前值大于需要查询的值,数据不存在,跳出查询(二维数组从上到下,从左到右都是递增顺序排列,后面的值会比当前值更大,无查询必要)
-
private static Boolean findValue(int[][] arr, int targetValue) {
if (Objects.isNull(arr) || arr.length == 0) {
return Boolean.FALSE;
}
for (int[] rows : arr) {
for (int columnValue : rows) {
if (columnValue == targetValue) {
return Boolean.TRUE;
}
if (columnValue < targetValue) {
continue;
}
return Boolean.FALSE;
}
}
return Boolean.FALSE;
}
优缺点
优点:方案设计简单,容易快速想到,解决问题
缺点: 算法性能不好,极端情况下需要遍历整个二维数组结构
方案二:剔除部分数据
随机选择二维数组中的一个位置,比较位置值与目标值的大小,根据比较结果缩小查询范围。二维数组如下
| 10 | 22 | 33 | 44 | 55 | 66 |
|---|---|---|---|---|---|
| 20 | 25 | 40 | 50 | 60 | 70 |
| 30 | 32 | 45 | 56 | 68 | 75 |
| 40 | 41 | 48 | 59 | 73 | 78 |
| 51 | 54 | 57 | 61 | 76 | 99 |
- 位置值与目标值相等,返回查询到数据
- 位置值大于目标值,那么目标值会存在于当前位置的上方或者左方。如目标值57,选取位置值59,那么目标值可能存在的区域为
| 10 | 22 | 33 | 44 | 55 | 66 |
|---|---|---|---|---|---|
| 20 | 25 | 40 | 50 | 60 | 70 |
| 30 | 32 | 45 | 56 | 68 | 75 |
| 40 | 41 | 48 | |||
| 51 | 54 | 57 |
- 位置值小于目标值,那么目标值会存在于当前位置的右方或下方。如目标值75,选取位置值59
| 55 | 66 | ||||
|---|---|---|---|---|---|
| 60 | 70 | ||||
| 68 | 75 | ||||
| 73 | 78 | ||||
| 61 | 76 | 99 |
根据剔除之后的行列数据进行查询数据是否存在
优缺点
优点:能够提出部分数据,提高效率
缺点:逻辑复杂,代码设计复杂
方案三:剔除行列法
方案二的弊端在于,只能判断出目标数据可能存在的位置,不能够完整的剔除一行或者一列数据,导致代码逻辑过于复杂
那么有没有一种方式可以有效的剔除一行或者一列数据呢?
选取点位置
- 对行数据而言是开始,对列数据而言是结束,即左下角点
- 对行数据而言是结束,对列数据而言是开始,即右上角点
这两个点的位置由于是一组数据的结束,并且是另外一组数据的开始,那么和目标点比较之后都能够有效剔除一行或者一列数据
如:二维数组如下,目标数据为32,选择右上角点作为参考点
| 10 | 22 | 33 | 44 | 55 | 66 |
|---|---|---|---|---|---|
| 20 | 25 | 40 | 50 | 60 | 70 |
| 30 | 32 | 45 | 56 | 68 | 75 |
| 40 | 41 | 48 | 59 | 73 | 78 |
| 51 | 54 | 57 | 61 | 76 | 99 |
-
右上角点66大于32,参考点所在列不会出现小于或等于32数据,所在列剔除,参考点 左移
10 22 33 44 55 20 25 40 50 60 30 32 45 56 68 40 41 48 59 73 51 54 57 61 76 -
新右上角点位置值为55,大于32,参考点所在列不会出现小于或等于32数据,所在列剔除,参考点位置继续 左移
10 22 33 44 20 25 40 50 30 32 45 56 40 41 48 59 51 54 57 61 -
新参考点值位置值44,大于32,参考点所在列不会出现小于或等于32数据,所在列剔除,参考点位置继续 左移
| 10 | 22 | 33 | |||
|---|---|---|---|---|---|
| 20 | 25 | 40 | |||
| 30 | 32 | 45 | |||
| 40 | 41 | 48 | |||
| 51 | 54 | 57 |
- 新参考点值位置值33,大于32,参考点所在列不会出现小于或等于32数据,所在列剔除,参考点位置继续***左移***
| 10 | 22 | ||||
|---|---|---|---|---|---|
| 20 | 25 | ||||
| 30 | 32 | ||||
| 40 | 41 | ||||
| 51 | 54 |
- 新参考点位置值为22,小于目标值32,参考点所在行不会出现大于或等于32数据,参考点位置 下移
| 20 | 25 | ||||
| 30 | 32 | ||||
| 40 | 41 | ||||
| 51 | 54 |
- 新参考点位置值是25,小于目标值32,参考点所在行不会出现大于或等于32数据,参考点所在行剔除,坐标点 下移
| 30 | 32 | ||||
| 40 | 41 | ||||
| 51 | 54 |
- 新参考点值为32,与目标数据相等,查询出所要查找的数据,返回结果
终止条件
当行列循环到边界处还没有查询到数据,退出循环
private static Boolean findValue(int[][] arr, Integer targetValue) {
if (Objects.isNull(arr) || arr.length == 0) {
return Boolean.FALSE;
}
int columnIndex = arr[0].length - 1;
int rowIndex = 0;
while (columnIndex >= 0 && rowIndex <= arr.length - 1) {
int indexValue = arr[rowIndex][columnIndex];
if (indexValue == targetValue) {
return Boolean.TRUE;
}
if (indexValue > targetValue) {
columnIndex--;
} else {
rowIndex++;
}
}
return Boolean.FALSE;
}