[Leetcode] 277. Find the Celebrity 解题报告

本文介绍了一种高效算法,用于从n个人中找出唯一的名人,该名人被所有人所知但本人却不认识任何人。通过两阶段策略,即候选者确定与验证,实现了O(n)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them.

Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do is to ask questions like: "Hi, A. Do you know B?" to get information of whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense).

You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a function int findCelebrity(n), your function should minimize the number of calls to knows.

Note: There will be exactly one celebrity if he/she is in the party. Return the celebrity's label if there is a celebrity in the party. If there is no celebrity, return -1.

思路

1、暴力法:最先想到的就是暴力法,依次验证每一个人,一旦发现该人认识其他人或者有其他人不认识该人,就表明验证失败,开始进入下一个人的验证。虽然大多数情况下可以提前结束第二重循环,但是理论上的时间复杂度还是O(n^2)。但这倒是可以通过所有的测试数据。

2、验证法:题目说明最多有一个celebrity。利用这个信息,我们可以将算法的时间复杂度降低到O(n):我们首先假定k号是celebrity,然后依次判断i号是否认识k,一旦发现不认识,则说明k号不可能是candidate,而i号则有可能是candidate。我们下面证明一个重要结论,就是如果题目中有一个celebrity,则我们的算法必然可以正确地找出该celebrity:

1)假设这个celebrity是0号,那么由于knows(i, 0) (i > 0)永远会返回true,所以k在整个循环中会保持不变,所以循环结束后k == 0,celebrity被作为candidate找出;

2)假设这个celebrity是m号,并且0 < m < n,那么当i == m的时候,knows(m, k)会返回false,此时k会被赋值为m,而此后knows(i, m) (i > m)都会返回true,所以k的值会保持为m直到循环结束,celebrity依然会被作为candidate正确找出。

由此可见,一旦有一个celebrity,我们在第一次循环的时候就会把它找出来,而第二次循环的时候就会验证通过,所以整个算法就会返回该celebrity。

如果给定的集合中没有celebrity,那么第一次循环返回的candidate在第二次循环的时候就会验证失败,所以整个算法就会返回-1。因此,我们的算法是正确的。

代码

1、暴力法:

// Forward declaration of the knows API.
bool knows(int a, int b);

class Solution {
public:
    int findCelebrity(int n) {
        for (int i = 0; i < n; ++i) {
            int j = 0;
            for (; j < n; ++j) {
                if (j == i) {
                    continue;
                }
                if (knows(i, j) || !knows(j, i)) {
                    break;
                }
            }
            if (j == n) {
                return i;
            }
        }
        return -1;
    }
};

2、验证法:

// Forward declaration of the knows API.
bool knows(int a, int b);

class Solution {
public:
    int findCelebrity(int n) {
        int k = 0;
        for (int i = 1; i < n; ++i) {   // find the only possible candidate
            k = knows(i, k) ? k : i;
        }
        for (int i = 0; i < n; ++i) {   // verfiy whether the candiate is the celebrity
            if (i != k && (knows(k, i) || !knows(i, k))) {
                return -1;
            }
        }
        return k;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值