1293. (消除k个障碍物)网格中的最短路径(Hard)/ 174. 地下城游戏(计算骑士所需的最低生命值,Hard)/ 1368. 使网格图至少有一条有效路径的最小代价(H)/ 迷宫系列!!!

在这里插入图片描述

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.迷宫

在这里插入图片描述

  • 题目(CSDN)

  • 题目(知乎)

  • 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

499. 迷宫 III(【490.迷宫】的扩展,需要打印出最短路径的方向)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值