返回

LeetCode 1263. Minimum Moves to Move a Box to Their Target Location(Python)使用 BFS 思想解题

后端

题目

给你一个大小为 m x n 的网格,其中包含箱子、墙壁和目标位置。箱子可以水平或垂直移动。

箱子不能穿过墙壁。

目标位置是箱子需要到达的最终位置。

从起始位置开始,返回将箱子移动到目标位置所需的 最少 移动次数。

如果箱子无法到达目标位置,返回 -1。

示例

示例 1:

输入:grid = [[0, 0, 0],
             [0, 1, 0],
             [0, 0, 0]]
起点:start = [0, 0]
目标:target = [2, 2]
输出:5
解释:箱子需要向右移动一次,向上移动两次,向右移动一次,然后向下移动两次。

示例 2:

输入:grid = [[0, 0, 0, 0, 0],
             [1, 1, 1, 0, 1],
             [0, 0, 0, 0, 0],
             [0, 1, 0, 0, 1],
             [0, 1, 0, 0, 0]]
起点:start = [4, 3]
目标:target = [3, 0]
输出:11
解释:首先,箱子需要向上移动一次,然后向右移动三次。然后,箱子需要向右移动两次,向上移动一次,向右移动一次,向上移动一次,向右移动一次,然后向上移动一次。最后,箱子需要向左移动一次,到达目标位置。

示例 3:

输入:grid = [[0, 0, 0],
             [1, 0, 0],
             [0, 0, 0]]
起点:start = [0, 0]
目标:target = [2, 0]
输出:-1
解释:箱子无法到达目标位置。

解题思路

我们可以使用广度优先搜索 (BFS) 来解决这个问题。

BFS 是从起始位置开始,然后向各个方向扩展。如果箱子能够移动到目标位置,则返回移动的总次数。否则,继续 BFS,直到找到目标位置。

为了实现 BFS,我们可以使用队列。我们将起始位置加入队列中,然后从队列中取出一个位置,并尝试向各个方向移动箱子。如果箱子能够移动到目标位置,则返回移动的总次数。否则,将新的位置加入队列中,并继续 BFS。

需要注意的是,我们需要使用 visited 数组来记录已经访问过的位置。这样,我们可以避免重复访问同一个位置。

Python 代码

from collections import deque

def min_moves_to_target(grid, start, target):
  """
  计算将箱子移动到目标位置所需的最小移动次数。

  参数:
    grid: 一个大小为 m x n 的网格,其中包含箱子、墙壁和目标位置。
    start: 箱子的起始位置。
    target: 箱子的目标位置。

  返回:
    将箱子移动到目标位置所需的最小移动次数。如果箱子无法到达目标位置,返回 -1。
  """

  # 检查网格是否有效
  if not grid or not start or not target:
    return -1

  # 创建一个队列来存储要访问的位置
  queue = deque([start])

  # 创建一个 visited 数组来记录已经访问过的位置
  visited = set()
  visited.add(start)

  # BFS
  min_moves = 0
  while queue:
    # 从队列中取出一个位置
    current_position = queue.popleft()

    # 检查箱子是否已经到达目标位置
    if current_position == target:
      return min_moves

    # 尝试向各个方向移动箱子
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
      # 计算箱子移动后的位置
      next_position = (current_position[0] + dx, current_position[1] + dy)

      # 检查箱子是否能够移动到下一个位置
      if next_position[0] < 0 or next_position[0] >= len(grid) or next_position[1] < 0 or next_position[1] >= len(grid[0]) or grid[next_position[0]][next_position[1]] == 1 or next_position in visited:
        continue

      # 将箱子移动到下一个位置
      queue.append(next_position)

      # 将下一个位置标记为已访问
      visited.add(next_position)

    # 增加移动次数
    min_moves += 1

  # 如果箱子无法到达目标位置,返回 -1
  return -1


if __name__ == "__main__":
  # 测试用例 1
  grid1 = [[0, 0, 0],
           [0, 1, 0],
           [0, 0, 0]]
  start1 = [0, 0]
  target1 = [2, 2]
  print(min_moves_to_target(grid1, start1, target1))  # 5

  # 测试用例 2
  grid2 = [[0, 0, 0, 0, 0],
           [1, 1, 1, 0, 1],
           [0, 0, 0, 0, 0],
           [0, 1, 0, 0, 1],
           [0, 1, 0, 0, 0]]
  start2 = [4, 3]
  target2 = [3, 0]
  print(min_moves_to_target(grid2, start2, target2))  # 11

  # 测试用例 3
  grid3 = [[0, 0, 0],
           [1, 0, 0],
           [0, 0, 0]]
  start3 = [0, 0]
  target3 = [2, 0]
  print(min_moves_to_target(grid3, start3, target3))  # -1

复杂度分析

  • 时间复杂度:O(mn),其中 m 和 n 分别是网格的行数和列数。
  • 空间复杂度:O(mn),其中 m 和 n 分别是网格的行数和列数。