题目:
题目链接: https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/
解题思路:
这个题有个隐含条件:可走的区域必须是从0,0点开始连续的,如果不连续,机器人没办法走到,如下图
机器人无法直接从黄色区域,飞到红色区域
所以不能直接将所有位数之和小于k的区域全部计算入内
方法一:BFS(时间O(MN),空间O(MN))
从0,0点开始搜索,如果当前格子满足条件,则将当前格子右边和下边的格子放入到队列中继续搜索;如果不满足条件,则当前格子的右边和下边的格子也无法到达,不新加格子到队列中,流程入下图所示:
变量:
- queue : 待搜索队列,初始化时只有起点(0,0)点
- rec : 符合条件的已搜索队列,初始化为空
流程:
首先将(0,0)点加入待搜索队列:
0,0点的数位之和为0,小于k = 2,将(0,0)点加入到rec中,继续搜索(0,0)点的右边和上边的格子:
queue中的两个格子(1,0)和(0,1)的位数之和均为1,符合条件,加入到rec中,继续向右边和上边搜索:
方法二:DP(时间O(MN),空间O(N))
从(0,0)开始,遍历每行数据,遍历时的规则如下:
- 如果当前位数和大于k,则继续
- 如果左边和下边的格子都不可到达,则继续
- 其他情况,更新可到达的格子数加1
其中,dp数组并不需要创建m × n的数组,因为其实我们只需要知道当前格子左边格子的情况和下边格子的情况就可以
所以只创建一个1 * n的数组,就可以满足条件,流程如下图所示:
从0,0点开始逐行遍历
继续遍历第二行,此时dp数组保存的是第一行的状态,当遍历第二行的时候,判断对应位置的dp数组值,就相当于是判断了第一行的状态
当判断第二行第二格时,dp数组的每个元素表示的状态如下:
- dp[0] = 第2行第1格
- dp[1] = 第1行第2格
- dp[2] = 第1行第3格
- ...
所以,对第2行第2格判断时,只需要判断dp[0]和dp[1],就相当于判断了两个必要位置了:
按照此逻辑,直到遍历完全
代码实现:
方法一:
import queue
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
rec = queue.Queue()
rec.put((0,0))
res = set()
while not rec.empty():
x, y = rec.get()
tmp = sum([int(a) for a in str(x)]) + sum([int(a) for a in str(y)])
if tmp > k:
continue
elif x >= m or y >= n:
continue
elif (x, y) in res:
continue
res.add((x, y))
rec.put((x + 1, y))
rec.put((x, y + 1))
return len(res)
方法二:
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
# 多创建一个位置,可以避免每次都进行越界检查
rec = [0] * (n + 1)
rec[1] = 1
num = 0
for x in range(m):
# 如果上一行全部无法到达,本行也一定都无法到达,退出以提高效率
if 0 == sum(rec):
break
for y in range(1, n + 1):
tmp = sum([int(a) for a in str(x)]) + sum([int(a) for a in str(y - 1)])
if tmp > k:
rec[y] = 0
continue
# 当前右值中的rec[y],就是下面一行是否可到达的值
rec[y] = max(rec[y], rec[y - 1])
if 1 == rec[y]:
num += 1
return num