SDE / Applied Scientist · Coding / ML Knowledge

Amazon Coding:有向图插入一条边,怎样验证不会产生环?

新边source→target前检查target可达source,解释输入DAG前提与原子更新。

题目重点:新边source→target前检查target可达source,解释输入DAG前提与原子更新。

题意与假设

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

  • 描述键入items edge、validate嵌入、directional graph和不形成Infinite loop;本文将核心规范为DAG插入边防环,原节点schema/判题接口未知。
  • 输入图已是DAG,插入source→target;合法重复边幂等成功,新节点可创建,自环拒绝;正式政策未公开,均为训练合同。
  • 单线程可变邻接字典;并发与事务另外讨论,代码不自称具备数据库线程安全。

解题路线

  1. 已有DAG加一条边若产生环,环一定包含新边;因此必须已有target→…→source路径。反之若该路径存在,加source→target闭合成环。先从target做可达搜索即可,没必要每次求所有拓扑排列。
  2. 先查重复边:已存在且输入DAG,则不改变任何东西,返回true。自环source==target会在初始栈target就命中source并拒绝;未知节点不存在返回路径时可成功插入。
  3. 搜索以visited防重复;所有检查完成后再改变graph。不能先加边后忘记失败时rollback,否则下一次查询基于污染状态。缺target仅作为无出边节点查,不在检查阶段偷偷插入空节点。
  4. “没有Infinite loop”不是只保证自己的BFS结束:visited能让任意含环输入搜索结束,但并不证明图本来无环。若原输入未保证DAG,需先全图校验或维护可信不变量。
  5. 并发两个插入可能各自看到旧快照都通过,合并后成环。需要同一锁/串行事务,或图版本CAS失败重试;数据库事务隔离级别应覆盖跨边依赖,简单atomic counter不能证明DAG完整性。
  6. 很多插入可维护拓扑编号,顺序方向正确时快速通过,逆序才在受影响区搜索/重排;不能不重排就永久用旧编号拒绝所有逆序合法边。附代码为正确基线,独立参考枚举节点排列判是否存在完整拓扑序。

手动走一遍

已有a→b,b→c,插c→a时从a可达c,拒绝且图不变;插a→c合法。已有a→b和c→d时插d→a合法,没有a→d路径。并发原空图中a→b与b→a各自读取旧图都通过,说明检查+更新必须有一致性合同。

Python 参考实现

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

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

def insert_if_acyclic(graph, source, target):
    """Input graph is already a DAG; graph maps nodes to sets of out-neighbors."""
    if target in graph.get(source, ()):
        return True
    stack = [target]
    seen = set()
    while stack:
        node = stack.pop()
        if node == source:
            return False
        if node not in seen:
            seen.add(node)
            stack.extend(graph.get(node, ()))
    # Change state only after the reachability check succeeds.
    graph.setdefault(source, set()).add(target)
    graph.setdefault(target, set())
    return True

复杂度

单次搜索O(V+E)最坏、O(V)visited;若重复边O(1)期望检查。M次基线O(M(V+E)),维护动态图拓扑的代价依受影响范围/实现,不许以BFS为由宣称常量插入。

易错点与追问

容易失分的边界

  • 搜索source→target方向反了。
  • 先修改后失败不回滚。
  • 输入含环仍声称验证新图DAG。
  • visited保证结束当防环证明。
  • 并发只保护插入那一行。

继续深挖

  • 原图不保证DAG怎样先验证?
  • 怎样返回造成环的见证路径?
  • 拓扑顺序维护怎样减少搜索?
  • 数据库事务怎样避免write skew?
✓已复制微信号!