在
n
人中,“名人”被定义为某人
大家都认识但谁也不认识的人。这
问题是通过询问名人来识别名人(如果存在的话)
仅提出以下形式的问题:“请问,您认识这个人吗?”
在那里?”(假设所有答案都是正确的,
连那个名人也会回答。)
目标是尽量减少问题数量。
这里是否存在阶数小于明显
O(n^2)
的解?
使用名人问题的分析这里
蛮力解决方案。 该图最多有
条边,我们可以通过对每个潜在边提出问题来计算它。在此 点,我们可以通过计算一个顶点来检查它是否是一个汇点 入度及其出度。这个蛮力解决方案要求n(n-1)
问题。接下来我们展示如何最多使用n(n-1)
来做到这一点 问题和线性位置。3(n-1)
一个优雅的解决方案。我们的算法由两个阶段组成:在淘汰阶段,我们淘汰除了一个人之外的所有人。 名人;在验证阶段我们检查这个是否 剩下的人确实是名人。消除阶段 维护一个可能的名人列表。最初它包含所有
人们。在每次迭代中,我们从列表中删除一个人。我们 利用以下关键观察:如果人n
认识人1
, 那么2
这个人就不是名人;如果人1
不认识人1
, 那么2
这个人就不是名人。因此,通过询问人2
是否知道 person1
,我们可以从列表中删除 person2
或 person1
可能的名人。我们可以反复使用这个想法来消除 除了一个人之外的所有人,说人2
。我们现在通过暴力验证p
是否是名人:对于每个其他人p
,我们都会询问人i
他是否认识人p
,我们询问人i
是否认识 人i
。如果某人p
总是回答“否”,而其他人总是回答“否” 回答是,我们宣布人p
为名人。否则,我们 断定这个群体中没有名人。p
将所有人分成两两。
对于每一对(A,B),询问 A 是否认识 B。
现在只剩下一半人了。
从 1 开始重复,直到只剩下一个人。
成本O(N)。
这是O(N)时间的算法
这个问题可以使用图(入度和出度概念)以O(N^2)时间复杂度来解决。
我们还可以使用简单的两指针概念在 O(N) 时间和 O(1) 空间中解决这个问题。 我们将同时比较两个人,一个从头开始,另一个从最后开始,我们会将那个人从不可能是名人的考虑中删除。例如,如果有两个人 X 和 Y,并且 X 可以识别 Y 人,那么 X 肯定不可能是名人,因为它认识该聚会中的某个人。另一种情况是,X 不认识 Y,在这种情况下,Y 不可能是名人,因为聚会中至少有一个人不认识他/她。使用这种直觉两指针概念可以用来找到聚会中的名人。
我在 Youtube 上发现了 algods 制作的一个很好的解释视频。
您可以参考此视频以获得更好的解释。
视频链接:
这是我的解决方案。
#include<iostream>
using namespace std;
int main(){
int n;
//number of celebrities
cin>>n;
int a[n][n];
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
cin>>a[i][j];
}
}
int count = 0;
for(int i = 0;i < n;i++){
int pos = 0;
for(int j = 0;j < n;j++){
if(a[i][j] == 0){
count = count + 1;
}
else{
count = 0;
break;
}
}
if(count == n){
pos = i;
cout<<pos;
break;
}
}
return 0;
}
我就是这么做的:)
问题 - 名人的定义是其他人都知道但不认识任何人的人。给定 N 个人(索引为 0...(N-1)),并且定义了一个 KnowOf 函数 如下所示:knowsOf(int person0, int person1) = true 如果人 0 认识人 1,否则为 false 如果有的话,找出 N 个给定的人中的名人。
// 如果没有名人则返回-1,否则返回人物索引/编号。
public int celeb(int n) {
int probaleCeleb = 0;
for(int i =1 ; i < n; i++) {
if(knowsOf(probaleCeleb , i)) { // true /false
probaleCeleb = i;
}
}
for(int i =0 ; i < n; i++) {
if( i != probaleCeleb &&
(!knowsOf( i , probaleCeleb) || (knowsOf( probaleCeleb , i)) ) {
probaleCeleb = -1;
break;
}
}
return probaleCeleb;
}
}
public class Solution {
public int findCelebrity(int n) {
if (n <= 1) {
return -1;
}
int left = 0;
int right = n - 1;
// First find the right candidate known by everyone, but doesn't know anyone.
while (left < right) {
if (knows(left, right)) {
left++;
} else {
right--;
}
}
// Validate if the candidate knows none and everyone knows him.
int candidate = right;
for (int i = 0; i < n; i++) {
if (i != candidate && (!knows(i, candidate) || knows(candidate, i))) {
return -1;
}
}
return candidate;
}
}
int findCelebrity(int n) {
int i=0;
for(int j=1;j<n;j++){
if(knows(i,j)){
i=j;
}
}
for(int j=0;j<n;j++){
if(j!=i && (knows(i,j)|| !knows(j,i))){
return -1;
}
}
return i;
}
int celebrity(vector<vector<int>>& mat) {
int n = mat.size();
int p1 = 0;
int p2 = n - 1;
while (p1 < p2) {
if (mat[p1][p2] == 1) {
p1++;
} else {
p2--;
}
}
int celebrity = p1;
for (int i = 0; i < n; i++) {
if (i != celebrity) {
if (mat[i][celebrity] == 0 || mat[celebrity][i] == 1) {
return -1;
}
}
}
return celebrity;
}