作为一个冒的感情的机器人,如果我们把他放在一个m*n的矩阵中,并且加上限制条件,会发生什么呢?
原题链接:剑指 Offer 13. 机器人的运动范围 (提示:本题是剑指Offer系列题目,有会员权限,有可能无法打开链接)
一、先看题
地上有一个m行n列的方格,从坐标 到坐标 。一个机器人从坐标 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 ,因为。但它不能进入方格 ,因为。请问该机器人能够到达多少个格子?
示例:
输入: m = 2, n = 3, k = 1
输出: 3
示例2:
输入: m = 3, n = 1, k = 0
输出: 1
提示:
二、整理思路
根据题目,我们可以得知:
- 棋盘大小为
- 机器人的起始点为
- 到达一个格子后,只能往相邻的格子上下左右移动
- 不能斜对角和跳跃,坐标的数字之和不能大于K
第一步:
确认输入输出:
输入:三个number;输出:一个number
第二步
怎么处理输入才能得到输出?
根据题目来看,我们只要统计符合条件的格子个数,那就可以得到结果了。看到矩阵,再想到“翻格子”,立马就能想起来要造一个状态矩阵。
因此我们遍历数组,如果当前的格子符合条件,就统计进去,不符合的话就跳过。
那怎么样才算符合条件呢??
因为只有前一个格子是符合条件的,同时这个格子坐标也符合条件,才能算真正的符合条件的格子,毕竟机器人是不会跳的嘛。
因此我们在判断完格子本身的坐标是否符合条件之后,还要看他相邻的格子是否有符合条件的。这时候重点来了!由于我们是将状态矩阵初始化为0填充,因此,我们只需要将当前格子的状态和他前方以及上方的格子状态进行或运算,就可以得到他的最终状态!
因此得到下面的代码:
/**
* @param {number} m
* @param {number} n
* @param {number} k
* @return {number}
*/
//用于计算数字之和
function sum(i, j) {
let sum = 0
for (let x of i+'') {
sum += Number(x)
}
for (let y of j+'') {
sum += Number(y)
}
return sum
}
var movingCount = function (m, n, k) {
//创建状态矩阵
let status = new Array(m).fill(0)
for(let x=0;x<m;x++){
status[x]= new Array(n).fill(0)
}
status[0][0] = 1
let res = 0
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (i > m || j > n || sum(i, j) > k) {
continue
}
//与相邻格子进行或运算
if (i >= 1) {
status[i][j] |= status[i - 1][j]
}
if (j >= 1) {
status[i][j] |= status[i][j - 1]
}
//统计
if(status[i][j]==1) {res++}
}
}
return res;
};
除了这种递推的解法外,官方还给出了一种广度优先的解法,因为我对那种解法理解的还不算太好,因此就不在这里展示了,大家有兴趣的可以去官网查看,或者自行思考。
原题链接:剑指 Offer 13. 机器人的运动范围 (提示:本题是剑指Offer系列题目,有会员权限,有可能无法打开链接)
三、总结
知识点:矩阵翻格子
解题法:递推;广度优先算法
难点: 在解题的时候,比较难想到的一点就是通过或运算来处理格子的状态,其次就是,在创建矩阵的时候发现了JavaScript的不方便,只有层层遍历才能创建多维数组。
JavaScript留意点:本来想使用Array.fill()来填充,结果意外发现,当fill中填充的是引用类型的值时,对于一个填充元素的更改会导致所有的填充元素同时修改,因此又换回了遍历法填充。
如果你也有所收获,点个赞吧!
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情