1. 程式人生 > >名人問題 演算法解析與Python 實現 O(n) 複雜度 (以Leetcode 277. Find the Celebrity為例)

名人問題 演算法解析與Python 實現 O(n) 複雜度 (以Leetcode 277. Find the Celebrity為例)

1. 題目描述 Problem Description

Leetcode 277. Find the Celebrity

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

.

 

2. 題目解析(參考了Prof. Sarrafzadeh 180講的內容)

首先題目定義了:如果一個人A是名人,那麼其他的n-1個人都認識A,而且A不認識其他的n-1個人。這題的目標是要從n個人中找出其中的名人,如果沒有,則告知其中沒有名人。我們可以呼叫knows(a,b)函式來詢問a是否認識b,而我們要儘量少呼叫這個函式。

這題的關鍵是理解題意,題意其實比較容易理解錯,所以有幾個小問題可以幫大家理解:

(1)n個人中最多可以有幾個名人?

答案:是1個。如果這n個人中有2個名人分別為A和B,那麼按照定義,如果一個人A是名人,那麼其他的n-1個人都認識A,而且A不認識其他的n-1個人,這也就是說A不認識B。但與此同時我們又定義瞭如果一個人B是名人,那麼其他的n-1個人都認識B,那麼A也應該認識B。這就產生了 contradiction了。因此其中不可以有2個或2個以上的名人。

  (2) 如果其他n-1個人都認識A,但是A認識了n-1個人中其中一個人,那麼A還是名人嗎?

答案:不是的。 

  (3) 如果A不認識其他的n-1個人,但是n-1個人中有人不認識A,那麼A還是名人嗎?

答案:不是的。

-

這題最直接的想法應該是暴力,但是暴力的複雜度是多少呢?對於每個人我們需要詢問:

(1) 他是否認識剩下的n-1個人: 最壞的情況需要呼叫knows(a,b)函式n-1次

(2) 剩下的n-1個人是否認識他:最壞的情況需要呼叫knows(a,b)函式n-1次

有的可能會重複,但是總體來說需要詢問的次數是$\frac{n(n-1)}{2}$。即時間複雜度為 O($n^2$)

-

有沒有辦法優化演算法?

如果我們從n個人中任意挑兩個人a,b出來,詢問啊是否認識b,那麼只有兩種情況:

(1)a認識b:那麼a肯定不是名人。

(2)b認識a:那麼b肯定不是名人。

所以任何一種情況,我們都可以排除掉2個人中的1一個人。如果我們不斷地重複的這個過程,直到只剩下一個人,那麼我們會做n-1次對比。而剩下這個人是唯一可能成為名人的人,那麼我們需要詢問剩下的n-1個人是否認識他,也需要詢問他是否認識剩下的n-1個人。

因此我們一共需要詢問3(n-1)次——時間複雜度為O($n$)。

 

3. Python 實現

 1 # The knows API is already defined for you.
 2 # @param a, person a
 3 # @param b, person b
 4 # @return a boolean, whether a knows b
 5 # def knows(a, b):
 6 
 7 class Solution(object):
 8     def findCelebrity(self, n):
 9         """
10         :type n: int
11         :rtype: int
12         """
13         if n == 0:
14             return -1
15         curr_stay = 0
16         for i in range(1, n):
17             if knows(curr_stay, i):
18                 curr_stay = i
19         for i in range(0, n):
20             if i == curr_stay:
21                 continue
22             if knows(curr_stay, i):
23                 return -1
24             if not knows(i, curr_stay):
25                 return -1
26         return curr_stay
27