这里是否有小于明显的 O(n^2) 解决方案呢?
使用名人问题的分析 这里
如果人员暴力解法。 图中最多有
n(n-1)
条边,我们可以通过询问每条潜在的边来计算它。此时,我们可以通过计算一个顶点的入度和出度来检查它是否是汇点。这种暴力解决方案需要n(n-1)
次询问。接下来,我们将展示如何用最多3(n-1)
次询问和线性空间来完成此操作。优雅的解决方案。 我们的算法包括两个阶段:在消除阶段,我们消除所有不可能成为名人的人;在验证阶段,我们检查这个剩下的唯一的人是否真的是名人。消除阶段维护一个可能成为名人的列表。最初,它包含所有的
n
个人。在每次迭代中,我们从列表中删除一个人。我们利用以下关键观察结果:如果人1
认识人2
,那么人1
不是名人;如果人1
不认识人2
,那么人2
不是名人。因此,通过问人1
他是否认识人2
,我们可以将可能成为名人的列表中的人缩减到要么是人1
,要么是人2
中的一个。我们可以反复使用这个想法来消除除了一个人,例如人p
之外的所有人。现在,我们通过暴力方法验证是否有一个名人:对于每个其他的人i
,我们询问人p
是否认识人i
,并且我们询问人们i
是否认识人p
。
p
总是回答“否”,而其他人总是回答“是”,则我们宣布人员 p
为名人。否则,我们得出结论:此组中没有名人。把所有人分成一对一对的。
对于每一对(A, B),问A是否认识B。
现在,只剩下一半的人了。
重复第1步,直到只剩下一个人。
时间复杂度为O(N)。
O(NlogN)
,而只是O(N)
。 - salva这里是 O(N) 时间复杂度算法
这个问题可以使用图形(入度和出度概念)在O(N^2)时间复杂度内解决。
我们还可以使用简单的双指针概念在O(N)时间复杂度和O(1)空间内解决这个问题。我们将一次比较两个人,一个从开头开始,另一个从结尾开始,并且会删除不能成为名人的那个人,例如,如果有两个人X和Y,X可以识别人Y,那么X肯定不是名人,因为它认识这个派对中的一个人。另一种情况是X不认识Y,在这种情况下,Y不能成为名人,因为至少有一个人在这个派对中不认识他/她。使用这种直觉,可以应用双指针概念来查找此派对中的名人。
我在algods的Youtube上找到了一段很好的解释视频。
您可以参考此视频以获得更好的解释。
视频链接:
这是我做的方式 :)
问题 - 名人被定义为每个人都知道,但却不认识任何人的人。给定N个人(索引为0...(N-1)),以及一个名为knowsOf的函数,其定义如下:如果person0认识person1,则knowsOf(int person0, int person1) = true,否则为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;
}
}
这是我的解决方案。
#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;
}
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;
}
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;
}
}