题目
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
我的解法
思路
从左上角开始,向右/向下都是递增的。用循环来写。
循环条件:数组没有溢出并且当前的值小于目标值
- 选择当前值
- 比较当前值与目标值
- 决定下一步往哪里走,或者是找到
- 当前值和目标值相同,下一步不用移动
- 右边的值比较小,下一步向右走
- 下边的值比较小,下一步向下走
- 到边界,只往一个方向走
问题:
- 可能出现右边的值比较小,但下边的值是目标值的情况
- 可能出现右边的值比较小,但目标值的下边的下边的情况
解决:
- 加上条件判断,“右边的值比较小&&下边的值不是目标值,下一步向右走”
- 无法解决,该算法本身有问题
代码:
function find(target, array) {
debugger
const row = array.length
const col = array[0].length
let rp = 0
let cp = 0
if (row === 0 || col === 0) {
return false
} else if (array[0][0] > target || array[row - 1][col - 1] < target) {
return false
} else {
while (rp < row && cp < col && array[rp][cp] <= target) {
// 当array[rp][cp]没有溢出并且小于目标值循环
if (array[rp][cp] === target) {
return true
} else if (rp + 1 === row) {
// 如果到最后一行了,每次只增加列数
cp++
} else if (cp + 1 === col) {
// 如果到最后一列了,每次只增加行数
rp++
} else if (array[rp + 1][cp] <= array[rp][cp + 1] && array[rp][cp + 1] !== target) {
// 往增量小的方向移动,并且另一个方向不是目标结果
rp++
} else {
cp++
}
}
return false
}
}
正确解法
思路
从数组的最右上角开始,如果目标值小于当前值,下一步向右;如果目标值大于当前值,下一步向下。
- 初始化要选择的位置
- 循环条件:要选择的位置没有发生溢出
- 取当前值
- 比较当前值和目标值
- 如果相同,返回
- 目标值大于当前值,向下走
- 目标值小于当前值,向左走
分析
跟上面的算法思路很类似,每移动一步相当于删去了一行/一列(向下移动删去了一行,向左移动删去了一列),但是上面的算法没有办法保证删去的那一行/一列中一定不存在目标值。
而这种算法类似于二分查找,目标值大于当前值,比当前值小的都可以舍去;目标值小于当前值,比当前值大的都可以舍去。
实现
function find(array, target) {
const row = array.length
const col = array[0].length
let rp = 0
let cp = col - 1
let current
while (rp < row && cp >= 0) {
current = array[rp][cp]
if (current === target) {
return true
} else if (current < target) {
rp++
} else {
cp--
}
}
return false
}
总结
while循环的思路
- 初始化选择条件
- 判断循环条件
- 根据选择条件选择初始化的值
- 分支语句修改选择条件
所以代码是这样的格式
初始化选择条件
while(){
**选择**
if(){
修改选择条件
} else if() {
修改选择条件
} else {
return
}
}
return