LeetCode 第277题:寻找名人
📖 文章摘要
本文详细解析LeetCode第277题"寻找名人",这是一道经典的图论和逻辑推理问题。文章提供了双指针和图论两种解题思路,包含C#、Python、C++三种语言实现,配有详细的分析表格和性能对比。适合学习图论和逻辑推理算法的读者。
核心知识点: 图论、双指针、逻辑推理
难度等级: 中等
推荐人群: 具备基础算法知识,想要提升逻辑思维能力的开发者
题目描述
假设你是一个专业的狗仔,参加了一个 n
人派对,其中每个人被从 0
到 n - 1
标号。在这个派对中,只有一个 “名人”。所谓 “名人” 的定义是:
- 所有其他人都认识他/她
- 他/她不认识任何其他人
现在你想要确认这个 “名人” 是谁,或者确定这个 “名人” 不存在。而你只能问诸如 “A 你好呀,请问你认识 B 吗?” 的问题。你需要尽可能少的问题来确定这个 “名人” 是谁(或者确定这个 “名人” 不存在)。
在本题中,你可以使用辅助函数 bool Knows(int a, int b)
获取到 A 是否认识 B。请你来实现一个函数 int FindCelebrity(int n)
。
派对最多只会有一个 “名人” 参加。若 “名人” 存在,请返回他/她的编号;若 “名人” 不存在,请返回 -1
。
示例
示例 1:
输入:graph = [[1,1,0],[0,1,0],[1,1,1]]
输出:1
解释:2号人认识所有人,但1号人不认识2号人,所以2号人不是名人。
1号人不认识2号人,但其他人都认识1号人,所以1号人是名人。
0号人认识1号人,所以0号人不是名人。
因此,1号人是名人。
示例 2:
输入:graph = [[1,0,1],[1,1,0],[0,1,1]]
输出:-1
解释:没有名人。
提示
n == graph.length == graph[i].length
2 <= n <= 100
graph[i][j]
是0
或1
graph[i][i] == 1
解题思路
本题可以使用双指针方法来解决,主要思路如下:
- 首先假设0号是名人候选人
- 遍历所有人,如果当前候选人认识某人,那么候选人一定不是名人,将认识的那个人设为新的候选人
- 最后需要验证候选人是否真的是名人:
- 确保所有其他人都认识候选人
- 确保候选人不认识任何其他人
图解思路
候选人筛选过程分析表
当前位置 | 候选人 | 比较对象 | Knows(候选人,比较对象) | 新候选人 | 说明 |
---|---|---|---|---|---|
0 | 0 | 1 | true | 1 | 0认识1,0不是名人 |
1 | 1 | 2 | false | 1 | 1不认识2,1可能是名人 |
2 | 1 | - | - | 1 | 遍历结束,1是候选人 |
名人验证分析表
验证步骤 | 检查内容 | 条件 | 结果 | 说明 |
---|---|---|---|---|
第一步 | 候选人不认识任何人 | Knows(候选人,i)==false | 通过 | 遍历检查候选人是否认识其他人 |
第二步 | 所有人都认识候选人 | Knows(i,候选人)==true | 通过 | 遍历检查其他人是否都认识候选人 |
结论 | 候选人是名人 | 两个条件都满足 | 是名人 | 返回候选人编号 |
代码实现
C# 实现
public class Solution : Relation {
public int FindCelebrity(int n) {
// 找到候选人
int candidate = 0;
for (int i = 1; i < n; i++) {
if (Knows(candidate, i)) {
candidate = i;
}
}
// 验证候选人是否是名人
for (int i = 0; i < n; i++) {
if (i != candidate) {
// 如果候选人认识其他人,或其他人不认识候选人
if (Knows(candidate, i) || !Knows(i, candidate)) {
return -1;
}
}
}
return candidate;
}
}
Python 实现
class Solution(object):
def findCelebrity(self, n):
"""
:type n: int
:rtype: int
"""
# 找到候选人
candidate = 0
for i in range(1, n):
if knows(candidate, i):
candidate = i
# 验证候选人
for i in range(n):
if i != candidate:
if knows(candidate, i) or not knows(i, candidate):
return -1
return candidate
C++ 实现
class Solution : public Relation {
public:
int findCelebrity(int n) {
// 找到候选人
int candidate = 0;
for (int i = 1; i < n; i++) {
if (knows(candidate, i)) {
candidate = i;
}
}
// 验证候选人
for (int i = 0; i < n; i++) {
if (i != candidate) {
if (knows(candidate, i) || !knows(i, candidate)) {
return -1;
}
}
}
return candidate;
}
};
执行结果
C# 实现
- 执行用时:92 ms
- 内存消耗:39.8 MB
Python 实现
- 执行用时:112 ms
- 内存消耗:14.2 MB
C++ 实现
- 执行用时:76 ms
- 内存消耗:9.5 MB
性能对比
语言 | 执行用时 | 内存消耗 | 特点 |
---|---|---|---|
C# | 92 ms | 39.8 MB | 代码结构清晰,性能适中 |
Python | 112 ms | 14.2 MB | 代码最简洁,但运行较慢 |
C++ | 76 ms | 9.5 MB | 性能最优,内存占用最小 |
代码亮点
- 🎯 使用双指针优化时间复杂度为O(n)
- 💡 巧妙利用逻辑推理减少API调用次数
- 🔍 分两步验证确保结果正确性
- 🎨 代码结构清晰,逻辑分明
常见错误分析
- 🚫 忘记验证候选人是否真的是名人
- 🚫 验证过程中遗漏某些情况的检查
- 🚫 未考虑没有名人的情况
- 🚫 API调用次数过多导致性能下降
解法对比
解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
---|---|---|---|---|
暴力解法 | O(n^2) | O(1) | 思路简单直观 | API调用次数多 |
双指针法 | O(n) | O(1) | API调用次数少 | 代码略复杂 |
图论解法 | O(n^2) | O(n^2) | 易于理解 | 空间复杂度高 |
相关题目
📖 系列导航
🔥 算法专题合集 - 查看完整合集
📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新第277题。
💬 互动交流
感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。
如果这篇文章对你有帮助,请:
- 👍 点个赞,让更多人看到这篇文章
- 📁 收藏文章,方便后续查阅复习
- 🔔 关注作者,获取更多高质量算法题解
- 💭 评论区留言,分享你的解题思路或提出疑问
你的支持是我持续分享的动力!
💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!