1、题目描述:
2、题解:
数位之和计算:
def sums(x):
s = 0
while x != 0:
s += x % 10
x = x // 10
return s
此题数据范围[1,100],而且x只能x+1或者x-1
(x + 1) % 10 =0 时,s(x+1) = s(x) - 8,如19,20的数位之和分别是10,2;
(x + 1) % 10 !=0 时,s(x+1) = s(x) + 1,如2,3的数位之和分别是2,3;
代码如下:
s_x + 1 if (x + 1) % 10 else s_x - 8
搜索方向简化:
机器人仅通过向下或者向右,可以访问所有点
方法1:广度优先搜索BFS
通常利用队列实现广度优先遍历。像水的波纹:一圈一圈向外扩散
初始化: 将机器人初始点 (0,0)加入队列 queue ;
迭代终止条件: queue 为空。代表已遍历完所有可达解。
迭代工作:
单元格出队: 将队首单元格的索引弹出,作为当前搜索单元格。
判断是否跳过: 若 ① 行、列索引越界 或 ② 数位和超出目标值 k 或 ③ 当前元素已访问过 时,执行 continue 。
标记当前单元格 :将单元格索引 (i, j) 存入 visited 中,代表此单元格 已被访问过 。
单元格入队: 将当前元素的 下方、右方 单元格的 索引加入 queue 。
返回值: visited 的长度 len(visited) ,即可达解的数量。
代码如下:
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
#BFS
#计算数位之和
def digitsum(x):
s = 0
while x != 0:
s += x % 10
x = x // 10
return s
queue,visited = [(0,0)],set()
while queue:
i,j = queue.pop(0)
if i >= m or j >= n or digitsum(i) + digitsum(j) > k or (i,j) in visited:
continue
visited.add((i,j))
queue.append((i+1,j))
queue.append((i,j+1))
return len(visited)
方法2:深度优先搜索DFS
可以理解为暴力法模拟机器人在矩阵中的所有路径。DFS通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。
剪枝: 在搜索中,遇到数位和超出目标值、此元素已访问,则应立即返回,称之为可行性剪枝
终止条件:若 ① 行、列索引越界 或 ② 数位和超出目标值 k 或 ③ 当前元素已访问过 时 返回0
递推工作:
1)标记当前单元格:将索引(i,j)存入visited中,代表此单元格已被访问
2)搜索下一个单元格:计算当前元素的下,右两个方向元素的数位和,并开启下层递归
回溯返回值:返回1 + 右方搜索的可达解数量 + 下方搜索的可达解总数,代表从本单元格递归搜索的可达解总数
代码如下:
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
#DFS
# 计算数位之和
def digitsum(x):
s = 0
while x != 0:
s += x % 10
x = x // 10
return s
def dfs(i,j):
if i >= m or j >= n or digitsum(i) + digitsum(j) > k or (i,j) in visited:
return 0
visited.add((i,j))
return 1 + dfs(i + 1,j) + dfs(i,j + 1)
visited = set()
return dfs(0,0)
3、复杂度分析:
时间复杂度都是O(MN),M,N分别是行和列的长度
空间复杂度都是O(MN)