SWE · Coding

无向树能否选成二叉树:度数与同层颜色约束

根最多两孩子,其余点扣掉父亲后最多两孩子,再检查每层同色。

题目重点:根最多两孩子,其余点扣掉父亲后最多两孩子,再检查每层同色。

题意与假设

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

  • 输入是非空无向树,n−1条无重复边且连通;非树输入拒绝,不把森林当一种根。
  • 二叉只指孩子数≤2,不要求有序BST或满二叉。颜色follow-up训练为任意标签、同层全相同。

解题路线

  1. 任意非根点children=degree−1,因此所有degree≤3是必要条件;候选root degree≤2。若满足,这些候选对纯二叉约束全部可行。
  2. 加颜色后对每个候选root BFS,按depth保存该层第一个颜色,发现另一颜色则拒绝;不得用只检查邻居颜色代替整层比较。
  3. 输出所有合法root便于明确唯一性;若只要任一个可提前终止。基础颜色重算最坏二次,不能因原图是树就声称所有root检查线性。

手动走一遍

4节点星中心deg3:中心不能作为二叉根,但任一叶可以,中心成为非根后只有两孩子。颜色星形两叶白一叶黑、中心白:选择某叶作根后剩两叶若色不同则该候选失败,具体看层而非边。

Python 参考实现

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

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

from collections import deque


def valid_roots(n,edges,colors=None):
    if n<=0 or len(edges)!=n-1:raise ValueError("nonempty undirected tree required")
    graph=[set() for _ in range(n)]
    for u,v in edges:
        if not 0<=u<n or not 0<=v<n or u==v or v in graph[u]:raise ValueError("invalid edge")
        graph[u].add(v);graph[v].add(u)
    seen={0};todo=[0]
    for u in todo:
        for v in graph[u]:
            if v not in seen:seen.add(v);todo.append(v)
    if len(seen)!=n:raise ValueError("disconnected")
    if colors is not None and len(colors)!=n:raise ValueError("one color per node required")
    if any(len(ns)>3 for ns in graph):return []
    result=[]
    for root in range(n):
        if len(graph[root])>2:continue
        if colors is not None:
            q=deque([(root,-1,0)]);level={};ok=True
            while q:
                u,parent,depth=q.popleft()
                if depth in level and level[depth]!=colors[u]:ok=False;break
                level[depth]=colors[u]
                for v in graph[u]:
                    if v!=parent:q.append((v,u,depth+1))
            if not ok:continue
        result.append(root)
    return result

复杂度

纯度数条件O(n),带颜色基线O(n²)时间/O(n)空间。输出候选O(n);树校验同样O(n)。

易错点与追问

容易失分的边界

  • degree3不代表一定非法,只有当其作为root才有3孩子。
  • 每层同色不要求相邻层不同色,不能误写成二分染色。

继续深挖

  • 多次颜色更新如何复用树距离结构?
  • 限定完整/满二叉树时哪些额外条件需要检查?
✓已复制微信号!