📅  最后修改于: 2023-12-03 15:09:36.232000             🧑  作者: Mango
给定一个 $n \times n$ 的方阵,每个单元格内填充了 0 或 1。需要找到一种最小步骤的方法,将所有的 1 移动到一个指定的单元格中。在每一步,可以执行以下操作之一:
要求输出最小的操作步数。
此问题可以转换成最短路径问题。首先将方阵中的所有 1 看作节点,将其互相连接。因为只能做上下或左右交换,所以节点之间的距离为 1。将指定的单元格看作终点,从任意一个 1 开始做广度优先搜索,每到达一个 1 就将其设为起点,一直搜索到终点。这样,搜索到终点的时间就是所有节点到终点的最小步数之和。
from collections import deque
def minStepsToMoveOnes(matrix, row, col, targetRow, targetCol):
"""
:param matrix: List[List[int]]
:param row: int
:param col: int
:param targetRow: int
:param targetCol: int
:return: int
"""
dx, dy = [0, 1, 0, -1], [1, 0, -1, 0]
start, end = row*col, targetRow*col+targetCol
que = deque([(start, 0)])
visited = set([start])
node2Idx = {}
cnt = 0
# convert nodes to indices
for i in range(row):
for j in range(col):
if matrix[i][j]:
node2Idx[i*col+j] = cnt
cnt += 1
# convert problem to shortest path problem and run bfs
while que:
curr, distance = que.popleft()
if curr == end:
return distance
currX, currY = curr // col, curr % col
for i in range(4):
nextX, nextY = currX+dx[i], currY+dy[i]
if nextX >= 0 and nextX < row and nextY >= 0 and nextY < col:
nextNode = nextX*col+nextY
if matrix[nextX][nextY] and nextNode not in visited:
nextIdx = node2Idx[nextNode]
que.append((nextNode, distance+abs(nextIdx-cnt)))
visited.add(nextNode)
return -1
时间复杂度为 $O(n^2 \log n)$,空间复杂度为 $O(n^2)$,其中 $n$ 为方阵的边长。搜索中最多遍历 $n^2$ 个节点,每个节点都需要用 $O(\log n)$ 的时间计算其在公式中的值。空间复杂度分别为 visited、que 和 node2Idx 的空间和。其中 visited 和 que 的空间复杂度均为 $O(n^2)$,node2Idx 的空间复杂度均为 $O(\text{number_of_ones})$,其中 number_of_ones 为 1 的个数,一定不超过 $n^2$。