【问题标题】:Optimal solution for the "celebrity" algorithm“名人”算法的最优解
【发布时间】:2015-07-01 02:33:51
【问题描述】:

n 人中,“名人”被定义为某人 谁都知道,但不认识任何人。这 问题是通过询问名人来识别名人(如果存在) 只问形式,“对不起,你认识这个人吗? 那边?”(假设所有答案都是正确的, 甚至那个名人也会回答。) 目标是尽量减少问题的数量。

这里有没有明显小于O(n^2)的顺序的解决方案?

【问题讨论】:

  • 我投票决定将此问题作为离题结束,因为在当前形式下它不是编程问题。
  • 除非您要进行任何假设或任何概率导数,否则我认为您已经为解决方案提供了足够的约束,使其成为 n^2
  • 是的。谢谢@therealprashant
  • 检查birthday problem,我认为这与通过将“与你生日相同”更改为“你认识这个人”以相反的形式提出最佳问题数量有关

标签: algorithm data-structures time-complexity complexity-theory graph-algorithm


【解决方案1】:
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;
}

【讨论】:

  • 知道从何而来?它有什么作用?此外,您的代码中的一些上下文对这个线程的未来读者是有益的。
  • knows(int i, int j) 是一个布尔函数,如果我知道 j 则返回 true,否则返回 false。这是来自问题的已知信息。在第一个 for 循环中,如果 know(i,j) 为真,'i' 肯定不是名人,所以,让 i=j else 继续。在第一个 for 循环之后,“i”等于可能成为潜在名人的人。在第二个 for 循环中,我们只是确定 'i' 是否是真正的名人。所以,我们总共要问 2N-1 个问题。
【解决方案2】:

这个问题可以用 O(N^2) 时间复杂度的图表(入度和出度概念)来解决。

我们也可以使用简单的两指针概念在O(N)时间和O(1)空间解决这个问题。 我们将一次比较两个人,一个从开始,另一个从结束,我们将把那个不能成为名人的人排除在外。例如,如果有两个人 X 和 Y,并且 X 可以识别人 Y,那么 X 肯定不能是名人,因为它认识这个党内的一个人。另一种情况是 X 不认识 Y,在这种情况下,Y 不可能是名人,因为聚会中至少有一个人不认识他/她。使用这种直觉的两点概念可以用来找到这个聚会中的名人。

我在 Youtube 上找到了 algods 的一个很好的解释视频。

您可以参考此视频以获得更好的解释。

视频链接:

https://youtu.be/aENYremq77I

【讨论】:

    【解决方案3】:
    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;
        }
    }
    

    【讨论】:

    • 欢迎来到 SO,请为您的代码提供一些解释,以使其更易于理解。
    【解决方案4】:

    我就是这样做的:)

    问题 - 名人的定义是其他人都知道但不认识任何人的人。给定 N 个人(索引为 0...(N-1)),并且定义了一个函数 knowOf 如下:knowOf(int person0, int person1) = 如果人 0 认识人 1,则为 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;
      }
     }
    

    【讨论】:

      【解决方案5】:

      这是我的解决方案。

       #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;
      }
      

      【讨论】:

        【解决方案6】:

        这里是O(N)时间算法

        1. 将所有元素推入堆栈。
        2. 删除前两个元素(比如 A 和 B),如果 B 知道 A 而 A 不知道 B,则保留 A。
        3. 删除 A、B 两者是相互认识或相互不认识

        【讨论】:

          【解决方案7】:
          1. 将所有人分成两组。

          2. 对于每一对 (A, B),询问 A 是否知道 B。

            • 如果答案是肯定的,A不可能是名人,丢弃他。
            • 如果答案是否定的,B 不可能是名人,丢弃他。

            现在,只剩下一半人了。

          3. 从 1 开始重复,直到只剩下一个人。

          成本 O(N)。

          【讨论】:

          • @NikosM:是的,但是由于每次迭代中要处理的项目数量减半,总成本不是O(NlogN),而是O(N)
          • 很好的解决方案!是的,它是 O(N)
          【解决方案8】:

          利用名人问题here分析

          蛮力解决方案。 该图最多有n(n-1) 边,我们可以通过对每个潜在边提出问题来计算它。在这 点,我们可以通过计算它来检查一个顶点是否是一个接收器 入度及其出度。这个蛮力解决方案要求n(n-1) 问题。接下来我们将展示如何使用最多3(n-1) 来做到这一点 问题和线性位置。

          一个优雅的解决方案。我们的算法由两个阶段组成:在淘汰阶段,我们将除一个人之外的所有人排除在 名人;在验证阶段我们检查这个是否 剩下的人确实是名人。淘汰阶段 维护一个可能的名人列表。最初它包含所有n 人们。在每次迭代中,我们从列表中删除一个人。我们 利用以下关键观察:如果人 1 认识人 2, 那么人1不是名人;如果人1不认识人2, 那么人2 不是名人。因此,通过询问人 1 他是否知道 人2,我们可以从列表中删除人1或人2 可能的名人。我们可以反复使用这个想法来消除 除了一个人以外的所有人,比如说p。我们现在通过蛮力验证 p是否是名人:对于每个其他人i,我们问人p 他是否认识i,我们询问i是否认识 人p。如果p 的人总是回答“否”,而其他人总是 回答是的,我们宣布人 p 为名人。否则,我们 断定该组中没有名人。

          【讨论】:

            猜你喜欢
            • 2013-10-17
            • 2019-04-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-12
            • 2011-05-19
            • 2021-10-15
            • 1970-01-01
            相关资源
            最近更新 更多