找出星型图的中心节点 图解题解
这道题到底在问什么
- 输入
- edges=[[1,2],[2,3],[4,2]]
- 输出
- 2
- 输入
- edges=[[1,2],[5,1],[1,3],[1,4]]
- 输出
- 1
最优解:一步一步想明白
- 3记牢这条主线:中心出现在每一条边里,叶子只出现在一条边里。所以中心必然同时躺在前两条边里,取这两条边的公共节点即可。下面先用最朴素的数度数法把这个直觉验一遍,再落到只看两条边的写法。
- 4先用笨办法:数每个节点连了几条边(度数)舞台上是 5 个节点,编号 1 到 5,中间的连线就是边。先亮个谜底:这张图的中心是节点 1,等会儿一步步验。第一种最朴素的想法是数度数,也就是每个节点连了几条边。开始时所有度数都是 0,接下来扫每条边,给它的两个端点各加 1。
- 5这条边连着节点 1 和 2,准备给两头各加 1看第 1 条边 [1, 2]。高亮的就是眼下这条边,它连着节点 1 和节点 2。数度数很机械,一条边给它的两个端点各记一笔。
- 6节点 1:1,节点 2:1两头各加 1:节点 1 的度数变成 1,节点 2 的度数变成 1。你会注意到节点 1 每条边几乎都掺一脚,度数涨得最快,这正是中心的特征。
- 7这条边连着节点 5 和 1,准备给两头各加 1看第 2 条边 [5, 1]。高亮的就是眼下这条边,它连着节点 5 和节点 1。数度数很机械,一条边给它的两个端点各记一笔。
- 8节点 5:1,节点 1:2两头各加 1:节点 5 的度数变成 1,节点 1 的度数变成 2。你会注意到节点 1 每条边几乎都掺一脚,度数涨得最快,这正是中心的特征。
- 9这条边连着节点 1 和 3,准备给两头各加 1看第 3 条边 [1, 3]。高亮的就是眼下这条边,它连着节点 1 和节点 3。数度数很机械,一条边给它的两个端点各记一笔。
- 10节点 1:3,节点 3:1两头各加 1:节点 1 的度数变成 3,节点 3 的度数变成 1。你会注意到节点 1 每条边几乎都掺一脚,度数涨得最快,这正是中心的特征。
- 11这条边连着节点 1 和 4,准备给两头各加 1看第 4 条边 [1, 4]。高亮的就是眼下这条边,它连着节点 1 和节点 4。数度数很机械,一条边给它的两个端点各记一笔。
- 12节点 1:4,节点 4:1两头各加 1:节点 1 的度数变成 4,节点 4 的度数变成 1。你会注意到节点 1 每条边几乎都掺一脚,度数涨得最快,这正是中心的特征。
- 13节点 1 度数 4,其余节点度数都是 14 条边全数完了。节点 1 的度数是 4,正好等于 n-1,也就是 5 减 1;其余 4 个节点度数都是 1。度数最高、达到 n-1 的那个就是中心。数度数这条路走得通,但它把每条边都扫了一遍,做了 O(边数) 的功。
- 14叶子只连中心这一条边,中心连着所有叶子停下来品一下这个结构:每个叶子节点只连着中心一条边,所以度数都是 1,只在一条边里露过面;而中心连着全部 4 个叶子,出现在每一条边里。这个「中心出现在每条边、叶子只在一条边」的差别,就是下面把复杂度砍到 O(1) 的钥匙。
- 15中心出现在每条边里 → 它一定在前两条边里既然中心出现在每一条边里,那它必然同时出现在最前面的两条边里。反过来,任何叶子只出现在一条边里,不可能既在第一条边又在第二条边。所以第一条边和第二条边的公共节点,只可能是中心。我们连后面的边都不用看了,只盯前两条。
- 16中心必在这条边里:要么 1,要么 2拿出第一条边 edges[0] = [1, 2]。中心既然出现在每条边里,当然也在这条边里,所以中心只可能是 1 或者 2 这两个候选之一。现在还不知道是哪个,得靠第二条边来裁决。
- 17中心也必在这条边里:要么 5,要么 1再看第二条边 edges[1] = [5, 1]。中心同样出现在这条边里,所以它也得是 5 或者 1。把两条边一对照,能同时出现在两条边里的,只有节点 1。这就是我们要找的公共节点。
- 18比较:1 是不是 edges[1] 的端点具体怎么落到代码:取第一条边的第一个节点 edges[0][0] = 1,去第二条边 [5, 1] 里看它在不在。先跟第二条边的第一个端点 5 比,1 不等于 5,先不下结论,再看另一个端点。
- 191 等于 edges[1] 的第二个端点,公共节点确定为 1再拿 1 跟第二条边的第二个端点比,1 正好等于 1,命中。这说明节点 1 同时出现在前两条边里,它就是那个公共节点,也就是中心。答案锁定为 1,跟开头亮的谜底对上了。
- 20那答案就是 edges[0][1],另一个端点顺手想想反面情况。如果 edges[0][0] 没在第二条边里出现,说明它只在第一条边露过面,是个叶子,那中心就只能是第一条边的另一个端点 edges[0][1]。代码里就是一个三目:在就取第一个,不在就取第二个。
- 21节点 2 只出现在第一条边里,是叶子看节点 2,它只在第一条边 [1, 2] 里出现过,第二条边里根本没有它。中心得连着 n-1 条边、出现在每一条边里,而 2 只连着一条边,度数是 1,注定是叶子,不可能当中心。这就从反面印证了公共节点法为什么可靠。
- 22中心出现次数 = n-1 ≥ 2,叶子出现次数 = 1把道理收成一句:因为 n ≥ 3,星型图至少有 2 条边,中心出现在每一条边里,所以它一定同时在 edges[0] 和 edges[1] 里;而叶子只出现在一条边里,不可能横跨前两条边。于是前两条边唯一的公共节点必然是中心,看这两条边就足够了。
- 23数度数法与两条边法,都指向节点 1两条路对照一下:数度数法扫完 4 条边,找出度数 4 的节点 1;两条边法只看前两条边,取公共点也是 1。结论完全一致,但后者只碰了两条边,做的是常数次比较,这就是我们最终要交的解法。
- 24最终答案:中心节点 = 1整道题回放一遍:星型图的中心连着每个节点,出现在每一条边里。我们只取前两条边 [1, 2] 和 [5, 1],找它们的公共节点,得到 1,直接返回。一次比较搞定,这就是找星型图中心最省事的办法。
⚠️ 容易写错的地方
✗ 错:老老实实建邻接表数每个点度数再找最大
✓ 对:只看前两条边取公共节点
中心出现在每条边,前两条边的公共点必是中心,建表数度数是 O(n) 的多余功,常数法一步到位
✗ 错:只比 edges[0][0] 和 edges[1][0]
✓ 对:要跟第二条边的两个端点都比
边内两个端点顺序任意,中心可能是第二条边的第一个或第二个端点,只比一个端点会漏判
✗ 错:担心 edges 只有一条边时越界
✓ 对:n ≥ 3 保证至少 2 条边
题目约束 n ≥ 3,星型图有 n-1 条边,所以 edges[1] 一定存在,取前两条边不会越界
✗ 错:以为要先验证输入真是星型图
✓ 对:题目已保证是合法星型图
题面承诺输入就是星型图,不必再判合法性,直接用中心必在前两条边的性质求解即可
完整代码(Python / C++ / Java)
Python
from __future__ import annotations
from typing import *
from collections import *
from functools import *
from itertools import *
from math import *
from heapq import *
from bisect import *
class Solution:
def findCenter(self, edges: List[List[int]]) -> int:
return edges[0][0] if edges[0][0] in edges[1] else edges[0][1]C++
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cmath>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
class Solution {
public:
int findCenter(vector<vector<int>>& edges) {
int a = edges[0][0], b = edges[0][1];
int c = edges[1][0], d = edges[1][1];
return a == c || a == d ? a : b;
}
};Java
import java.util.*;
class Solution {
public int findCenter(int[][] edges) {
int a = edges[0][0], b = edges[0][1];
int c = edges[1][0], d = edges[1][1];
return a == c || a == d ? a : b;
}
}复杂度
时间
O(1)
参考代码只读 edges[0] 和 edges[1] 这两条边,做常数次比较就能定中心,和边数、节点数都没关系。演示里先讲的数度数法要扫全部边,是 O(n) 那一档,用来建立直觉;真正提交的两条边法是常数时间
空间
O(1)
按峰值算。只用了几个变量存两条边的端点,没有开额外数组或哈希,空间是常数。Python 的 in 也只是在长度为 2 的列表里查,不额外分配
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 找出星型图的中心节点 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么中心节点一定出现在每一条边里?+
因为这是星型图的定义:一个中心节点,恰好有 n-1 条边把它和其它每个节点分别连起来。也就是说图里每一条边都有一个端点是中心,另一个端点是某个叶子。既然每条边都带着中心,那中心当然出现在每一条边里,出现次数正好是 n-1。反过来,每个叶子只跟中心连一条边,所以只出现在一条边里。这一多一少的对比,就是「看前两条边取公共点」这个解法的全部依据。
如果不用这个性质,还能怎么做,复杂度分别是多少?+
最直接的替代是数度数:建一个计数数组,扫一遍所有边,给每条边的两个端点各加一,最后度数等于 n-1 的那个节点就是中心,这是 O(n) 时间、O(n) 空间。也可以用哈希集合记录出现过的节点,第一个重复出现的节点就是中心。但这些都要扫较多边。利用中心在每条边这个性质,只看前两条边取公共点,是 O(1) 时间、O(1) 空间,最优。面试时先说朴素的数度数思路,再点出常数解法,层次就很清楚。
边的两个端点顺序不固定,判公共点时要注意什么?+
要注意中心可能出现在第二条边的任意一个位置,所以拿第一条边的一个端点去第二条边找时,必须和第二条边的两个端点都比,不能只比第一个。参考代码里 Python 用 in 一次就把第二条边两个位置都覆盖了,C plus plus 和 Java 则显式写成 a 等于 c 或者 a 等于 d。另外如果第一条边的第一个端点没命中,答案直接是第一条边的第二个端点,不需要再去查第二条边,因为中心必在第一条边里,二选一。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 找出星型图的中心节点 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。