标签: 深度优先搜索 广度优先搜索 图 拓扑排序 记忆化搜索 数组 动态规划 矩阵
难度: Medium
标签: 深度优先搜索 广度优先搜索 图 拓扑排序 记忆化搜索 数组 动态规划 矩阵
难度: Medium
运行时间: 64 ms
内存: 23.0 MB
DIRS = ((0, 1), (1, 0), (0, -1), (-1, 0)) # 右下左上(顺时针) class Solution: def ballGame(self, num: int, plate: List[str]) -> List[List[int]]: m, n = len(plate), len(plate[0]) def check(x: int, y: int, d: int) -> bool: left = num while plate[x][y] != 'O': if left == 0: return False # 无剩余步数 if plate[x][y] == 'W': d = (d + 3) % 4 # 逆时针 elif plate[x][y] == 'E': d = (d + 1) % 4 # 顺时针 x += DIRS[d][0] y += DIRS[d][1] if not (0 <= x < m and 0 <= y < n): return False # 出界 left -= 1 return True ans = [] for j in range(1, n - 1): if plate[0][j] == '.' and check(0, j, 1): ans.append([0, j]) # 上边 if plate[-1][j] == '.' and check(m - 1, j, 3): ans.append([m - 1, j]) # 下边 for i in range(1, m - 1): if plate[i][0] == '.' and check(i, 0, 0): ans.append([i, 0]) # 左边 if plate[i][-1] == '.' and check(i, n - 1, 2): ans.append([i, n - 1]) # 右边 return ans
解题思路是通过模拟弹珠的运动路径来确定哪些初始位置可以让弹珠最终落入洞中。首先定义了四个基本方向对应的坐标变化。对于盘边的每个空白位置,根据其在边上的位置确定其初始方向,并使用check函数模拟弹珠的运动。在这个函数中,弹珠会根据当前位置的字符改变方向或直接前进,直至弹珠落入洞中、走出边界或步数耗尽。最后,将所有可以使弹珠入洞的初始位置记录并返回。
时间复杂度: O((m+n) * num)
空间复杂度: O(m+n)
DIRS = ((0, 1), (1, 0), (0, -1), (-1, 0)) # 右下左上(顺时针) class Solution: def ballGame(self, num: int, plate: List[str]) -> List[List[int]]: m, n = len(plate), len(plate[0]) def check(x: int, y: int, d: int) -> bool: left = num while plate[x][y] != 'O': if left == 0: return False # 若步数用尽,返回失败 if plate[x][y] == 'W': d = (d + 3) % 4 # 遇逆时针转向器,转向 elif plate[x][y] == 'E': d = (d + 1) % 4 # 遇顺时针转向器,转向 x += DIRS[d][0] y += DIRS[d][1] if not (0 <= x < m and 0 <= y < n): return False # 检测是否出界 left -= 1 return True ans = [] for j in range(1, n - 1): if plate[0][j] == '.' and check(0, j, 1): ans.append([0, j]) # 检查上边界 if plate[-1][j] == '.' and check(m - 1, j, 3): ans.append([m - 1, j]) # 检查下边界 for i in range(1, m - 1): if plate[i][0] == '.' and check(i, 0, 0): ans.append([i, 0]) # 检查左边界 if plate[i][-1] == '.' and check(i, n - 1, 2): ans.append([i, n - 1]) # 检查右边界 return ans
DIRS数组用于表示弹珠在二维平面上的移动方向,其中每个元组的两个元素分别对应x轴和y轴的移动步长。数组中的四个元组分别表示向右、向下、向左、向上的方向,这对应于顺时针旋转。这样的顺序是因为在题解中,需要处理弹珠遇到转向器时的方向变化。顺时针转向器('E')使得弹珠方向序号增加1,而逆时针转向器('W')则使方向序号增加3(等价于顺时针方向减1)。通过模运算保证方向序号在0到3之间循环,从而覆盖所有可能的方向变化。
这个边界检查条件确保了弹珠的坐标(x, y)始终在有效的游戏板范围内。条件`0 <= x < m`和`0 <= y < n`分别检查弹珠的x坐标和y坐标是否在游戏板的行和列的有效索引范围内。如果弹珠的任意坐标超出这个范围,即意味着弹珠已经移动到了游戏板的外面,因此函数返回False表示弹珠不能继续在板上合法移动。
在模拟过程中,当弹珠遇到字符'W',意味着需要将弹珠的移动方向顺时针转动270度(等同于逆时针转动90度),在DIRS数组中实现这一转向是通过将当前方向d的值增加3再对4取模来完成。同理,当弹珠遇到字符'E',表示需要将弹珠的移动方向顺时针转动90度,这是通过将当前方向d的值增加1再对4取模来实现。这些操作保证了弹珠的方向始终处于DIRS数组定义的四个方向中的一个,并能正确地响应转向器的效果。