SWE · Coding

Meta 最短路必须过某格:两次BFS与可重复路径

求起点到终点且必须经过指定坐标的最短行走路线,区分walk与不能重复格的简单路径。

题目重点:求起点到终点且必须经过指定坐标的最短行走路线,区分walk与不能重复格的简单路径。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练0/1矩形、4邻接、每步1,允许两段重访格;返回坐标path或None。必经点可与起点/终点相同。
  • 如果禁止重复格,分别最短两段可能冲突,当前方法不适用;这一限制必须先问。

解题路线

  1. 任意通过waypoint的walk可拆start→waypoint和waypoint→goal,两段分别至少是各自最短距离。因此总下界d(start,w)+d(w,goal)。
  2. 各做一次BFS求最短段,拼first+second[1:]达到下界,所以全局最优。删第二段首点避免waypoint重复计一个格,但允许其他坐标在两段出现。
  3. 两次搜索各有自己的parent/visited,不能拿第一段visited阻止第二段经过已用格。任一段不可达则整体不可达,先检查三个坐标是否界内/可走。
  4. 方向门或key改变可达状态时,第一段到waypoint可能有多个keyMask,不能只取坐标最短段直接接第二段;需在完整状态图处理“是否已过w”。

手动走一遍

一行0格坐标0..3,start0、w3、goal1,最短walk为0,1,2,3,2,1,允许重访2/1。如果要求简单路径则无解,这说明两次BFS的合同必要。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

from collections import deque


def shortest_via(grid,start,waypoint,goal):
    """0 open/1 blocked, four neighbors, revisits allowed across the two legs."""
    if not grid or not grid[0]:return None
    rows,cols=len(grid),len(grid[0])
    if any(len(row)!=cols or any(v not in (0,1) for v in row) for row in grid):raise ValueError('rectangular binary grid')
    for r,c in (start,waypoint,goal):
        if not 0<=r<rows or not 0<=c<cols:raise ValueError('coordinate outside grid')
        if grid[r][c]:return None
    def route(source,destination):
        queue=deque([source]);parent={source:None}
        while queue:
            current=queue.popleft()
            if current==destination:
                result=[]
                while current is not None:result.append(current);current=parent[current]
                return result[::-1]
            r,c=current
            for dr,dc in ((-1,0),(1,0),(0,-1),(0,1)):
                rr,cc=r+dr,c+dc;p=(rr,cc)
                if 0<=rr<rows and 0<=cc<cols and grid[rr][cc]==0 and p not in parent:
                    parent[p]=(r,c);queue.append(p)
        return None
    first=route(start,waypoint)
    if first is None:return None
    second=route(waypoint,goal)
    return first+second[1:] if second is not None else None

复杂度

O(RC)两次BFS仍同阶,前驱/队列O(RC)、输出O(L1+L2)。不用枚举所有可能start→goal路径再过滤必经点。

易错点与追问

容易失分的边界

  • 复用第一段visited限制第二段会错误判无解。
  • 忽略简单路径限制,输出重复格却声称满足题面。

继续深挖

  • 多个必须依次经过的点可分段累加;顺序任意时为何出现组合优化?
  • 若路径必须经过w恰好一次,第二段重复w需要禁止,合同与证明怎么调整?
✓已复制微信号!