SWE · Coding

TikTok 朋友分组:能否分成两组组内互不认识的人?

把每条朋友边转为异色约束,用二分图染色检查奇环,并处理不连通图、非对称列表与自环。

题目重点:把每条朋友边转为异色约束,用二分图染色检查奇环,并处理不连通图、非对称列表与自环。

题意与假设

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

  • 朋友视为无向关系,某一侧列出也约束双方;重复关系合并。
  • 仅要求组内无朋友边,不要求两组人数相等,也不要求每组互相连通。
  • 训练允许空组,输出可行两组或None;若正式只要求布尔结果,保留染色判断即可。

解题路线

  1. 每条边(u,v)要求 color[u]≠color[v],颜色只有0/1。沿边给未染色邻居相反颜色;若已经同色,当前约束不可满足。
  2. 不能仅检查每个人的朋友人数。三个人互相认识,每人只有两条边,却构成奇环,需要三种颜色;任何两组分法都会留下组内朋友。
  3. 对每个未染色节点重新启动BFS,覆盖不连通分量与孤立点。各分量可整体反转颜色,互不影响可行性,因此无需为了染色把所有人连成一个图。
  4. 正确性:BFS赋色等于到起点路径长度奇偶。若有同色边,树路径加这条边形成奇环;奇环无法交替两色闭合。若所有边异色,返回分组直接满足每条朋友约束。
  5. 训练先把非对称adjacency对称化。若关系实际上有向且“陌生”含义不同,需要先定义哪种关系禁止同组;把有向边端点不同色仍是当前冲突约束,不等于检查有向图是否有环。
  6. 自环要求一个人与自己异色,直接不可行。若要求两组人数相等,二分图可行只完成第一步,还需对各连通分量的两侧大小做选择组合,当前算法不保证平衡。

手动走一遍

朋友链0—1—2可分[0,2]和[1],0与2没有朋友边。添加2—0形成三角形就不可行。两个独立边与一个孤立点仍可行,孤立点放哪组都不违反边约束。

Python 参考实现

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

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

"""Undirected friendship constraints, even if only one adjacency lists an edge.
Return two groups or None if impossible; an empty group is permitted.
"""
from collections import deque


def stranger_groups(friends):
    n = len(friends)
    graph = [set() for _ in range(n)]
    for u, neighbors in enumerate(friends):
        for v in neighbors:
            if not isinstance(v, int) or isinstance(v, bool) or not 0 <= v < n:
                raise ValueError("invalid person ID")
            graph[u].add(v)
            graph[v].add(u)
    color = [-1] * n
    for start in range(n):
        if color[start] != -1:
            continue
        color[start] = 0
        queue = deque([start])
        while queue:
            u = queue.popleft()
            for v in graph[u]:
                if color[v] == -1:
                    color[v] = 1 - color[u]
                    queue.append(v)
                elif color[v] == color[u]:
                    return None
    return [[u for u in range(n) if color[u] == c] for c in (0, 1)]

复杂度

对称建图、BFS O(V+E) 时间,图/颜色/队列 O(V+E) 空间。若只返回布尔值仍需颜色;返回奇环证据可以额外保留父节点和深度。

易错点与追问

容易失分的边界

  • 只从节点0开始漏其他分量。
  • 自环被去重时错误丢掉。
  • 混淆朋友传递闭包和直接朋友关系。
  • 默认两组人数必须相等。

继续深挖

  • 怎样返回一条不可行奇环?
  • 若必须均分人数还需要什么状态?
  • 不断新增朋友边怎样在线检查?
  • 输入百万节点如何控制邻接内存?
✓已复制微信号!