题目:
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
示例 1:
输入:m = 2, n = 3, k = 1
输出:3
示例 2:
输入:m = 3, n = 1, k = 0
输出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
解析:
这道题一看题目就很明显的是路径搜索题,和《矩阵中的路径》这道题特别相似,都是在单元格中上下左右移动进行搜索,找出满足题目条件的路径。不过区别在于本题可以使用深度优先搜索也可以使用广度优先搜索,而《矩阵中的路径这道题》只能用深度优先搜索,因为这道题要求按照单词必须按照字母顺序,通过相邻的单元格内的字母构成,相邻指的是水平或者垂直,这样,就限定了从一个点开始只能沿着左右上下的顺序,而不能按照层次的顺序,也就是按照某条给定路径走。(
例如:[["a","b"],["c","d"]] ,不能得到路径abcd,因为a,b之后,b相邻的节点不是c。应该是abdc。这个给出了具体路径,而且路径只能按照某个点水平或者垂直去走。不能层次去遍历
)。本题是机器人每次可以上下左右移动,然后求机器人满足条件的所有经过的格子,这样可以深度优先从一个点开始找,或者直接按照层次一层一层去找都是可以的。
第一种方法:DFS(深度优先搜索)-非递归形式:
def movingCount(m: int, n: int, k: int) -> int:
stack1, stack2 = [], []
stack1.append((0, 0)) #用栈来保存元素,实现DFS
while stack1:
x, y = stack1[-1][0], stack1[-1][1] #拿到栈顶元素,先别出栈(其实直接出栈也是可以的,拿到栈顶元素进行处理罢了)
numloc = (x % 10 + x // 10 + x // 100) + (
y % 10 + y // 10 + y // 100) # 因为题目给的是n,m<=100,所以计算到百位即可。这个地方可以写一个函数代替计算操作。
if numloc > k or x < 0 or x > m - 1 or y < 0 or y > n - 1: #当当前元素指针越界或者不符合条件,栈中元素出栈
stack1.pop()
elif numloc <= k and (x, y) not in stack2:
stack2.append((x, y)) #将看到的元素加入栈2,当下一个元素不在栈2中且符合要求时再进行处理
# 将当前节点的上下左右邻接点加入队列中(也就是当前节点下一步的所有路径),#优化:我们在搜索的过程中搜索方向可以缩减为向右和向下,而不必再向上和向左进行搜索(因为左上已经访问)。
stack1.append((x, y + 1))
stack1.append((x, y - 1))
stack1.append((x + 1, y))
stack1.append((x + 1, y))
else:
stack1.pop() #当元素不满足条件时,从栈中退出。
return len(stack2)
第二种方式:DFS(深度优先搜索)-递归形式:(推荐使用这种,代码量少,不过要确定好递归条件和终止条件)
def get_numlocsum(n):
res = 0
while n > 0:
res += n % 10 #获取整数位的末尾数字,然后将每一次的都相加就可以求的整数每个数位的和
n = n // 10 #整数位向前移动一位
return res
def movingCount2(m: int, n: int, k: int) -> int:
# 这个地方队列和set都可以,队列保证了路径的顺序(要是输出路径时可以用到),set保证了不重复(但顺序是乱的)。
#这个序列中的元素不会重复,因为这个序列保存的是处理过的元素,必须是之前没处理的才能加进去,处理过的元素不能二次加进去
seed = set()
def dfs(i, j):
#递归终止条件:指针越界;元素处理过了;不符合题目中的小于等于k的条件
if i < 0 or j < 0 or i > m - 1 or j > n - 1 or (i, j) in seed or get_numlocsum(i) + get_numlocsum(j) > k:
return 0
seed.add((i,j))
# 沿着四个地方递归。
return 1+dfs(i,j+1)\
+dfs(i,j-1)\
+dfs(i+1,j)\
+dfs(i-1,j)
return dfs(0,0
第三种方法:BFS(广度优先搜索):(这个可没有递归形式哈,按照他的性质来的)
# 一般来说,能采用DFS解决的问题,也能采用BFS解决,只是搜索策略不同(在题目没有给定要求的情况下,例如矩阵的路径这道题就只能使用DFS。)
def movingCount3(m: int, n: int, k: int) -> int:
queue, seed = [], []
queue.append((0, 0))
while queue:
s = queue.pop(0)
x, y = s[0], s[1] #这个跟上边的DFS比,直接将元素出栈,减少了一些步骤,减少了一些时间。但采用不出栈,当不满足条件出栈时,这种情况便于理解。
numloc = get_numlocsum(x) + get_numlocsum(y) # 因为题目给的是n,m<=100,所以计算到百位即可。这个地方可以写一个函数代替计算操作。
if numloc > k or x < 0 or x > m - 1 or y < 0 or y > n - 1:
continue
elif numloc <= k and (x, y) not in seed:
# 将当前节点的上下左右邻接点加入队列中(也就是当前节点下一步的所有路径),#优化:我们在搜索的过程中搜索方向可以缩减为向右和向下,而不必再向上和向左进行搜索(因为左上已经访问)。
seed.append((x, y))
queue.append((x, y + 1))
queue.append((x, y - 1))
queue.append((x + 1, y))
queue.append((x + 1, y))
return len(seed)
执行结果:
输入7,2,3