【LeetCode 每日一题】1263. 推箱子

167 阅读2分钟

1263. 推箱子

难度:困难

时间:2023/05/08


「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。

游戏地图用大小为 m x n 的网格 grid 表示,其中每个元素可以是墙、地板或者是箱子。

现在你将作为玩家参与游戏,按规则将箱子 'B' 移动到目标位置 'T'

  • 玩家用字符 'S' 表示,只要他在地板上,就可以在网格中向上、下、左、右四个方向移动。
  • 地板用字符 '.' 表示,意味着可以自由行走。
  • 墙用字符 '#' 表示,意味着障碍物,不能通行。 
  • 箱子仅有一个,用字符 'B' 表示。相应地,网格上有一个目标位置 'T'
  • 玩家需要站在箱子旁边,然后沿着箱子的方向进行移动,此时箱子会被移动到相邻的地板单元格。记作一次「推动」。
  • 玩家无法越过箱子。

返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1

示例 1:

输入:grid = [["#","#","#","#","#","#"],
             ["#","T","#","#","#","#"],
             ["#",".",".","B",".","#"],
             ["#",".","#","#",".","#"],
             ["#",".",".",".","S","#"],
             ["#","#","#","#","#","#"]]
输出:3
解释:我们只需要返回推箱子的次数。

示例 2:

输入:grid = [["#","#","#","#","#","#"],
             ["#","T","#","#","#","#"],
             ["#",".",".","B",".","#"],
             ["#","#","#","#",".","#"],
             ["#",".",".",".","S","#"],
             ["#","#","#","#","#","#"]]
输出:-1

示例 3:

输入:grid = [["#","#","#","#","#","#"],
             ["#","T",".",".","#","#"],
             ["#",".","#","B",".","#"],
             ["#",".",".",".",".","#"],
             ["#",".",".",".","S","#"],
             ["#","#","#","#","#","#"]]
输出:5
解释:向下、向左、向左、向上再向上。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 20
  • grid 仅包含字符 '.', '#''S' , 'T', 以及 'B'
  • grid 中 'S', 'B' 和 'T' 各只能出现一个。

解题思路:

优先级队列(双端队列)+BFS

class Solution:
    def minPushBox(self, grid: List[List[str]]) -> int:
​
        m, n = len(grid), len(grid[0])
​
        def inArea(i: int, j: int):
            return i >=0 and i < m and j >=0 and j < n and (grid[i][j] == '.' or grid[i][j] == 'T')
​
        bij, sij = None, None
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 'S':
                    sij = [i, j]
                    grid[i][j] = '.'
                if grid[i][j] == 'B':
                    bij = [i, j]
                    grid[i][j] = '.'
​
        
        used = [[[[False] * n for _ in range(m)] for _ in range(n)] for _ in range(m)] # record by arr
        used[sij[0]][sij[1]][bij[0]][bij[1]] = True
        que = deque([[0] + sij + bij, ]) # use deque instead of heap for saving time
        move = [[0, 1], [1, 0], [0, -1], [-1, 0]]
​
​
        while que:
​
            for _ in range(len(que)):
​
                n_move, si, sj, bi, bj = que.popleft()
​
                if grid[bi][bj] == 'T':
                    return n_move
​
                for mi, mj in move:
                    si_, sj_ = si + mi, sj + mj
                    bi_, bj_, n_move_, lor = bi, bj, n_move, 0
                    if si_ == bi and sj_ == bj:
                        # move box
                        bi_, bj_, n_move_, lor = bi + mi, bj + mj, n_move + 1, 1
                        
                    if not inArea(si_, sj_) or not inArea(bi_, bj_): continue
 
                    if not used[si_][sj_][bi_][bj_]:
                        if lor:
                            que.append([n_move_, si_, sj_, bi_, bj_])
                        else:
                            que.appendleft([n_move_, si_, sj_, bi_, bj_])
                        used[si_][sj_][bi_][bj_] = True
​
        return -1