-
Notifications
You must be signed in to change notification settings - Fork 43
/
find-the-celebrity.py
206 lines (170 loc) · 7.03 KB
/
find-the-celebrity.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
"""
277. Find the Celebrity
Medium
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 the celebrity, but the celebrity 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 ask questions like: "Hi, A. Do you know B?" to get information about 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) that tells you whether A knows B. Implement a function int findCelebrity(n). There will be exactly one celebrity if they are at the party.
Return the celebrity's label if there is a celebrity at the party. If there is no celebrity, return -1.
Example 1:
Input: graph = [[1,1,0],[0,1,0],[1,1,1]]
Output: 1
Explanation: There are three persons labeled with 0, 1 and 2. graph[i][j] = 1 means person i knows person j, otherwise graph[i][j] = 0 means person i does not know person j. The celebrity is the person labeled as 1 because both 0 and 2 know him but 1 does not know anybody.
Example 2:
Input: graph = [[1,0,1],[1,1,0],[0,1,1]]
Output: -1
Explanation: There is no celebrity.
Constraints:
n == graph.length
n == graph[i].length
2 <= n <= 100
graph[i][j] is 0 or 1.
graph[i][i] == 1
Follow up: If the maximum number of allowed calls to the API knows is 3 * n, could you find a solution without exceeding the maximum number of calls?
"""
# V0
class Solution:
def findCelebrity(self, n):
self.n = n
for i in range(n):
# NOTE : we return the celebrity directly (if found)
if self.is_celebrity(i):
return i
return -1
# func check if i if celebrity
def is_celebrity(self, i):
for j in range(self.n):
if i == j:
continue # Don't ask if they know themselves.
"""
NOTE : here we check
knows(i, j) or not knows(j, i)
"""
if knows(i, j) or not knows(j, i):
return False
return True
# V0'
class Solution:
# @param {int} n a party with n people
# @return {int} the celebrity's label or -1
def findCelebrity(self, n):
celeb = 0
for i in range(1, n):
if Celebrity.knows(celeb, i): # if celeb knows i, then the given celeb must not a celebrity, so we move to the next possible celeb
celeb = i # move from celeb to i
# Check if the final candicate is the celebrity
for i in range(n):
if celeb != i and Celebrity.knows(celeb, i): # to check if the Celebrity really knows no one
return -1
if celeb != i and not Celebrity.knows(i, celeb): # to check if everyone (except Celebrity) really knows the Celebrity
return -1
return celeb
# V1
# IDEA : BRUTE FORCE
# https://leetcode.com/problems/find-the-celebrity/solution/
class Solution:
def findCelebrity(self, n: int) -> int:
self.n = n
for i in range(n):
if self.is_celebrity(i):
return i
return -1
def is_celebrity(self, i):
for j in range(self.n):
if i == j: continue # Don't ask if they know themselves.
if knows(i, j) or not knows(j, i):
return False
return True
# V1
# IDEA : Logical Deduction
# https://leetcode.com/problems/find-the-celebrity/solution/
class Solution:
def findCelebrity(self, n: int) -> int:
self.n = n
celebrity_candidate = 0
for i in range(1, n):
if knows(celebrity_candidate, i):
celebrity_candidate = i
if self.is_celebrity(celebrity_candidate):
return celebrity_candidate
return -1
def is_celebrity(self, i):
for j in range(self.n):
if i == j: continue
if knows(i, j) or not knows(j, i):
return False
return True
# V1
# IDEA : Logical Deduction with Caching
# https://leetcode.com/problems/find-the-celebrity/solution/
from functools import lru_cache
class Solution:
@lru_cache(maxsize=None)
def cachedKnows(self, a, b):
return knows(a, b)
def findCelebrity(self, n: int) -> int:
self.n = n
celebrity_candidate = 0
for i in range(1, n):
if self.cachedKnows(celebrity_candidate, i):
celebrity_candidate = i
if self.is_celebrity(celebrity_candidate):
return celebrity_candidate
return -1
def is_celebrity(self, i):
for j in range(self.n):
if i == j: continue
if self.cachedKnows(i, j) or not self.cachedKnows(j, i):
return False
return True
# V1
# https://www.jiuzhang.com/solution/find-the-celebrity/#tag-highlight-lang-python
# IDEA :
# AS A CELEBRITY, HE/SHE MOST KNOW NO ONE IN THE GROUP
# AND REST OF PEOPLE (EXCEPT CELEBRITY) MOST ALL KNOW THE CELEBRITY
# SO WE CAN USE THE FACT 1) : AS A CELEBRITY, HE/SHE MOST KNOW NO ONE IN THE GROUP
# -> GO THROUGH ALL PEOPLE IN THE GROUP TO FIND ONE WHO KNOW NO ONE, THEN HE/SHE MAY BE THE CELEBRITY POSSIBILY
# -> THEN GO THROUGH REST OF THE PEOPLE AGAIN TO VALIDATE IF HE/SHE IS THE TRUE CELEBRITY
"""
The knows API is already defined for you.
@param a, person a
@param b, person b
@return a boolean, whether a knows b
you can call Celebrity.knows(a, b)
"""
class Solution:
# @param {int} n a party with n people
# @return {int} the celebrity's label or -1
def findCelebrity(self, n):
celeb = 0
for i in range(1, n):
if Celebrity.knows(celeb, i): # if celeb knows i, then the given celeb must not a celebrity, so we move to the next possible celeb
celeb = i # move from celeb to i
# Check if the final candicate is the celebrity
for i in range(n):
if celeb != i and Celebrity.knows(celeb, i): # to check if the Celebrity really knows no one
return -1
if celeb != i and not Celebrity.knows(i, celeb): # to check if everyone (except Celebrity) really knows the Celebrity
return -1
return celeb
# V2
# Time: O(n)
# Space: O(1)
class Solution(object):
def findCelebrity(self, n):
"""
:type n: int
:rtype: int
"""
candidate = 0
# Find the candidate.
for i in range(1, n):
if knows(candidate, i): # noqa
candidate = i # All candidates < i are not celebrity candidates.
# Verify the candidate.
for i in range(n):
candidate_knows_i = knows(candidate, i) # noqa
i_knows_candidate = knows(i, candidate) # noqa
if i != candidate and (candidate_knows_i or
not i_knows_candidate):
return -1
return candidate