Lesson 55 of 164
Find the Celebrity
At a party of n people, numbered 0 to n - 1, a celebrity is someone who:
- is known by everyone else, and
- knows no one else.
You're given an n × n boolean[][] matrix where knows[a][b] is true if person a knows person b. Return the celebrity's number as an OptionalInt, or OptionalInt.empty() if there isn't one. There can be at most one celebrity: if two people were both celebrities, each would have to know the other, which contradicts "knows no one".
LeetCode: 277. Find the Celebrity
Example 1
0 1 2 3
0 [ 0, 1, 1, 0 ]
1 [ 1, 0, 1, 1 ]
2 [ 0, 0, 0, 0 ]
3 [ 0, 1, 1, 0 ]
Output: 2graph LR
0 --> 1
0 --> 2
1 --> 0
1 --> 2
1 --> 3
3 --> 1
3 --> 2
style 2 stroke-width:3pxAn arrow a → b means a knows b. Every other person has an arrow into 2, and 2 has no arrows out.
Example 2
knows: 0 -> 1, 1 -> 2, 2 -> 0
Output: empty (everyone knows someone)Brute force: test every person
For each candidate c, check every other person p: p must know c, and c must not know p. OptionalInt is a container that holds either one int or nothing, so the method can report "no celebrity" without returning null.
import java.util.OptionalInt;
public class Main {
static boolean isCelebrity(boolean[][] knows, int c) {
for (int p = 0; p < knows.length; p++) {
if (p != c && !(knows[p][c] && !knows[c][p])) return false;
}
return true;
}
static OptionalInt findCelebrity(boolean[][] knows) {
for (int c = 0; c < knows.length; c++) {
if (isCelebrity(knows, c)) return OptionalInt.of(c);
}
return OptionalInt.empty();
}
static boolean[][] matrix(int[][] rows) {
boolean[][] m = new boolean[rows.length][];
for (int i = 0; i < rows.length; i++) {
m[i] = new boolean[rows[i].length];
for (int j = 0; j < rows[i].length; j++) m[i][j] = rows[i][j] == 1;
}
return m;
}
public static void main(String[] args) {
boolean[][] party = matrix(new int[][] {{0, 1, 1, 0}, {1, 0, 1, 1}, {0, 0, 0, 0}, {0, 1, 1, 0}});
boolean[][] noCelebrity = matrix(new int[][] {{0, 1, 0}, {0, 0, 1}, {1, 0, 0}});
System.out.println(findCelebrity(party) + " " + findCelebrity(noCelebrity));
}
}OptionalInt[2] OptionalInt.emptyTime: O(n²) questions ("does a know b?"). Space: O(1).
Optimal: eliminate one person per question
A single question always rules someone out:
- If
aknowsb, thenaisn't the celebrity (a celebrity knows no one). - If
adoesn't knowb, thenbisn't the celebrity (everyone knows the celebrity).
Push everyone onto a stack. While there are at least two people, pop two, ask one question, and push back the one who could still be the celebrity. After n - 1 questions, one candidate is left. That candidate is the only possible celebrity, but not necessarily a real one, so verify them with isCelebrity.
Walkthrough with example 1. The stack (an ArrayDeque, the standard Java stack) starts as [0, 1, 2, 3]:
| pop a | pop b | knows[a][b]? | eliminated | push back | stack after |
|---|---|---|---|---|---|
| 3 | 2 | yes | 3 | 2 | [0, 1, 2] |
| 2 | 1 | no | 1 | 2 | [0, 2] |
| 2 | 0 | no | 0 | 2 | [2] |
Candidate 2 passes the check, so the answer is 2.
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.OptionalInt;
public class Main {
static boolean isCelebrity(boolean[][] knows, int c) {
for (int p = 0; p < knows.length; p++) {
if (p != c && !(knows[p][c] && !knows[c][p])) return false;
}
return true;
}
static OptionalInt findCelebrity(boolean[][] knows) {
if (knows.length == 0) return OptionalInt.empty();
Deque<Integer> stack = new ArrayDeque<>();
for (int p = 0; p < knows.length; p++) stack.push(p);
while (stack.size() > 1) {
int a = stack.pop();
int b = stack.pop();
stack.push(knows[a][b] ? b : a);
}
int candidate = stack.pop();
return isCelebrity(knows, candidate) ? OptionalInt.of(candidate) : OptionalInt.empty();
}
static boolean[][] matrix(int[][] rows) {
boolean[][] m = new boolean[rows.length][];
for (int i = 0; i < rows.length; i++) {
m[i] = new boolean[rows[i].length];
for (int j = 0; j < rows[i].length; j++) m[i][j] = rows[i][j] == 1;
}
return m;
}
public static void main(String[] args) {
boolean[][] party = matrix(new int[][] {{0, 1, 1, 0}, {1, 0, 1, 1}, {0, 0, 0, 0}, {0, 1, 1, 0}});
boolean[][] noCelebrity = matrix(new int[][] {{0, 1, 0}, {0, 0, 1}, {1, 0, 0}});
System.out.println(findCelebrity(party) + " " + findCelebrity(noCelebrity));
}
}OptionalInt[2] OptionalInt.emptyTime: O(n): n - 1 elimination questions, plus 2(n - 1) to verify. Space: O(n) for the stack.
Same idea with O(1) space
The stack isn't really needed: keep one candidate and compare it with each person in turn. If the candidate knows p, the candidate is eliminated and p becomes the new candidate.
import java.util.OptionalInt;
public class Main {
static boolean isCelebrity(boolean[][] knows, int c) {
for (int p = 0; p < knows.length; p++) {
if (p != c && !(knows[p][c] && !knows[c][p])) return false;
}
return true;
}
static OptionalInt findCelebrity(boolean[][] knows) {
if (knows.length == 0) return OptionalInt.empty();
int candidate = 0;
for (int p = 1; p < knows.length; p++) {
if (knows[candidate][p]) candidate = p;
}
return isCelebrity(knows, candidate) ? OptionalInt.of(candidate) : OptionalInt.empty();
}
static boolean[][] matrix(int[][] rows) {
boolean[][] m = new boolean[rows.length][];
for (int i = 0; i < rows.length; i++) {
m[i] = new boolean[rows[i].length];
for (int j = 0; j < rows[i].length; j++) m[i][j] = rows[i][j] == 1;
}
return m;
}
public static void main(String[] args) {
boolean[][] party = matrix(new int[][] {{0, 1, 1, 0}, {1, 0, 1, 1}, {0, 0, 0, 0}, {0, 1, 1, 0}});
System.out.println(findCelebrity(party));
}
}OptionalInt[2]Time: O(n). Space: O(1).
Edge cases
- Empty party:
OptionalInt.empty(). - One person: they're trivially the celebrity (there's no one else to check).
- No celebrity: the elimination still leaves a candidate, and the verification rejects them.
