174. 地下城游戏
class Solution:
def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
n, m = len(dungeon), len(dungeon[0])
mod_val = 10**9
dp = [[mod_val] * (m + 1) for _ in range(n + 1)]
dp[n][m - 1] = dp[n - 1][m] = 1 # 赋初始值
for i in range(n - 1, -1, -1):
for j in range(m - 1, -1, -1):
minn = min(dp[i + 1][j], dp[i][j + 1])
dp[i][j] = max(minn - dungeon[i][j], 1)
return dp[0][0]
1368. 使网格图至少有一条有效路径的最小代价
class Solution:
def minCost(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
BIG = int(1e9)
dist = [0] + [BIG] * (m * n - 1)
seen = set()
q = collections.deque([(0, 0)])
while len(q) > 0:
x, y = q.popleft()
if (x, y) in seen:
continue
seen.add((x, y))
cur_pos = x * n + y
for i, (nx, ny) in enumerate([(x, y + 1), (x, y - 1), (x + 1, y), (x - 1, y)]):
new_pos = nx * n + ny
new_dis = dist[cur_pos] + (1 if grid[x][y] != i + 1 else 0)
if 0 <= nx < m and 0 <= ny < n and new_dis < dist[new_pos]:
dist[new_pos] = new_dis
if grid[x][y] == i + 1:
q.appendleft((nx, ny))
else:
q.append((nx, ny))
return dist[m * n - 1]
490.迷宫
-
BFS:建立一个queue,先将start位置放入队列。每次从队列头部拿出一个位置,如果此位置是终点则直接返回true,否则就看该位置是否被访问过,如果没有被访问,将其四个方向上移动可以停靠的点加入队列,此位置记为已访问。如果队列空了还没有发现可以到达的路径,则说明无法到达
class Solution:
# BFS
def hasPath(self, maze, start, destination):
visited = set()
dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]
row, col = len(maze), len(maze[0])
def bfs(i, j):
queue = collections.deque([[i, j]])
visited.add((i, j))
while queue:
i, j = queue.pop()
if [i, j] == destination:
return True
for a, b in dirs:
# 暂存老坐标
move_i, move_j = i, j
# 尝试新坐标:朝着一个方向移动一步
t1 = move_i + a
t2 = move_j + b
# 未出边界 and 新坐标是可以走到的(不是墙壁)
while 0 <= t1 < row and 0 <= t2 < col and maze[t1][t2] != 1:
# 暂存老坐标
move_i, move_j = t1, t2
# 尝试新坐标:朝着一个方向移动一步(同一个方向)
t1 = move_i + a
t2 = move_j + b
# 若无法进行任何移动,则跳过该方向,去尝试另一个方向
if move_i == i and move_j == j:
continue
# 标记
if (move_i, move_j) not in visited:
visited.add((move_i, move_j))
queue.appendleft([move_i, move_j])
return False
return bfs(start[0], start[1])
- DFS:首先判断是否已经到达了终点,如果是则直接返回true;否则就看该位置是否已经被访问过了,如果是则返回,否则就记当前位置已经被访问。然后用DFS尝试四个不同方向,有任何一个方向可以到达终点就直接返回true
class Solution:
# DFS
def hasPath(self, maze, start, destination):
visited = set()
dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]
row, col = len(maze), len(maze[0])
def dfs(i, j):
if i == destination[0] and j == destination[1]:
return True
for a, b in dirs:
# 暂存老坐标
move_i, move_j = i, j
# 尝试新坐标:朝着一个方向移动一步
t1 = move_i + a
t2 = move_j + b
# 未出边界 and 新坐标是可以走到的(不是墙壁)
while 0 <= t1 < row and 0 <= t2 < col and maze[t1][t2] != 1:
# 暂存老坐标
move_i, move_j = t1, t2
# 尝试新坐标:朝着一个方向移动一步(同一个方向)
t1 = move_i + a
t2 = move_j + b
# 若无法进行任何移动,则跳过该方向,去尝试另一个方向
if move_i == i and move_j == j:
continue
if (move_i, move_j) not in visited:
visited.add((move_i, move_j))
if dfs(move_i, move_j):
return True
return False
return dfs(start[0], start[1])
505 迷宫 II(【490.迷宫】的扩展,需要计算出最短路径的长度)
class Solution:
def shortestDistance(self, maze, start, destination):
# 计算朝着每个合法方向移动后的距离
def move(start):
res = []
# 向上移动
v1 = start[0]
for i in range(start[0] - 1, -1, -1):
if maze[i][start[1]] == 0:
v1 = i
else:
break
if v1 != start[0]:
res.append(((v1, start[1]), start[0] - v1))
# 向下移动
v2 = start[0]
for i in range(start[0] + 1, len(maze), 1):
if maze[i][start[1]] == 0:
v2 = i
else:
break
if v2 != start[0]:
res.append(((v2, start[1]), v2 - start[0]))
# 向左移动
v3 = start[1]
for j in range(start[1] - 1, -1, -1):
if maze[start[0]][j] == 0:
v3 = j
else:
break
if v3 != start[1]:
res.append(((start[0], v3), start[1] - v3))
# 向右移动
v4 = start[1]
for j in range(start[1] + 1, len(maze[0]), 1):
if maze[start[0]][j] == 0:
v4 = j
else:
break
if v4 != start[1]:
res.append(((start[0], v4), v4 - start[1]))
return res
start, destination = tuple(start), tuple(destination)
visited = {start: 0}
queue = collections.deque([(start, 0)])
ans = float("inf")
while queue:
for _ in range(len(queue)):
now, d1 = queue.popleft()
for next_pos, d2 in move(now):
# 到达目的地,更新最短距离
if next_pos == destination:
ans = min(ans, d1 + d2)
if next_pos not in visited or d1 + d2 < visited[next_pos]:
queue.append((next_pos, d1 + d2))
visited[next_pos] = d1 + d2
return ans if ans != float("inf") else -1