{"id":27593,"date":"2018-04-04T19:35:49","date_gmt":"2018-04-04T14:05:49","guid":{"rendered":"https:\/\/www.wikitechy.com\/technology\/?p=27593"},"modified":"2018-04-04T19:35:49","modified_gmt":"2018-04-04T14:05:49","slug":"the-celebrity-problem","status":"publish","type":"post","link":"https:\/\/www.wikitechy.com\/technology\/the-celebrity-problem\/","title":{"rendered":"The Celebrity Problem"},"content":{"rendered":"<p><em>In a party of N people, only one person is known to everyone. Such a person <strong>may be present<\/strong> in the party, if yes, (s)he doesn\u2019t know anyone in the party.<span id=\"more-19622\"><\/span> We can only ask questions like \u201c<strong>does A know B?<\/strong> \u201c. Find the stranger (celebrity) in minimum number of questions.<\/em><\/p>\n<p>We can describe the problem input as an array of numbers\/characters representing persons in the party. We also have a hypothetical function <em>HaveAcquaintance(A, B)<\/em> which returns <em>true<\/em> if A knows B, <em>false<\/em> otherwise. How can we solve the problem.<\/p>\n<p>We measure the complexity in terms of calls made to <em>HaveAcquaintance().<\/em><\/p>\n<p><center><strong>Method 1 (Graph)<\/strong><\/center>We can model the solution using graphs. Initialize indegree and outdegree of every vertex as 0. If A knows B, draw a directed edge from A to B, increase indegree of B and outdegree of A by 1. Construct all possible edges of the graph for every possible pair [i, j]. We have N<sub>C2<\/sub> pairs. If celebrity is present in the party, we will have one sink node in the graph with outdegree of zero, and indegree of N-1. We can find the sink node in (N) time, but the overall complexity is O(N<sup>2<\/sup>) as we need to construct the graph first.<\/p>\n<p><center><strong>Method 2 (Recursion)<\/strong><\/center>We can decompose the problem into combination of smaller instances. Say, if we know celebrity of N-1 persons, can we extend the solution to N? We have two possibilities, Celebrity(N-1) may know N, or N already knew Celebrity(N-1). In the former case, N will be celebrity if N doesn\u2019t know anyone else. In the later case we need to check that Celebrity(N-1) doesn\u2019t know N.<\/p>\n<p>Solve the problem of smaller instance during divide step. On the way back, we find the celebrity (if present) from the smaller instance. During combine stage, check whether the returned celebrity is known to everyone and he doesn\u2019t know anyone. The recurrence of the recursive decomposition is,<\/p>\n<p>T(N) = T(N-1) + O(N)<\/p>\n<p>T(N) = O(N<sup>2<\/sup>). You may try writing pseudo code to check your recursion skills.<\/p>\n<p><center><strong>Method 3 (Using Stack)<\/strong><\/center><br \/>\nThe graph construction takes O(N<sup>2<\/sup>) time, it is similar to brute force search. In case of recursion, we reduce the problem instance by not more than one, and also combine step may examine M-1 persons (M \u2013 instance size).<\/p>\n<p>We have following observation based on elimination technique (Refer <em>Polya\u2019s How to Solve It<\/em> book).<\/p>\n<ul>\n<li>If A knows B, then A can\u2019t be celebrity. Discard A, and <em>B may be celebrity<\/em>.<\/li>\n<li>If A doesn\u2019t know B, then B can\u2019t be celebrity. Discard B, and <em>A may be celebrity<\/em>.<\/li>\n<li>Repeat above two steps till we left with only one person.<\/li>\n<li>Ensure the remained person is celebrity. (Why do we need this step?)<\/li>\n<\/ul>\n<p>We can use stack to verity celebrity.<\/p>\n<ol>\n<li>Push all the celebrities into a stack.<\/li>\n<li>Pop off top two persons from the stack, discard one person based on return status of <em>HaveAcquaintance<\/em><em>(A, B)<\/em>.<\/li>\n<li>Push the remained person onto stack.<\/li>\n<li>Repeat step 2 and 3 until only one person remains in the stack.<\/li>\n<li>Check the remained person in stack doesn\u2019t have acquaintance with anyone else.<\/li>\n<\/ol>\n<p>We will discard N elements utmost (Why?). If the celebrity is present in the party, we will call <em>HaveAcquaintance<\/em><em>()<\/em> 3(N-1) times. Here is code using stack.<\/p>\n<p><strong>C++ Programming:<\/strong><\/p>\n<div class=\"code-embed-wrapper\"> <div class=\"code-embed-infos\"> <\/div> <pre class=\"language-cpp code-embed-pre line-numbers\"  data-start=\"1\" data-line-offset=\"0\"><code class=\"language-cpp code-embed-code\">\/\/ C++ program to find celebrity<br\/>#include &lt;bits\/stdc++.h&gt;<br\/>#include &lt;list&gt;<br\/>using namespace std;<br\/> <br\/>\/\/ Max # of persons in the party<br\/>#define N 8<br\/> <br\/>\/\/ Person with 2 is celebrity<br\/>bool  MATRIX[N][N] = {{0, 0, 1, 0},<br\/>                      {0, 0, 1, 0},<br\/>                      {0, 0, 0, 0},<br\/>                      {0, 0, 1, 0}};<br\/> <br\/>bool knows(int a, int b)<br\/>{<br\/>    return MATRIX[a][b];<br\/>}<br\/> <br\/>\/\/ Returns -1 if celebrity is not present.<br\/>\/\/ If present, returns id  (value from 0 to n-1).<br\/>int findCelebrity(int n)<br\/>{<br\/>    \/\/ Handle trivial case of size = 2<br\/> <br\/>    stack&lt;int&gt; s;<br\/> <br\/>    int C; \/\/ Celebrity<br\/> <br\/>    \/\/ Push everybody to stack<br\/>    for (int i=0; i&lt;n; i++)<br\/>        s.push(i);<br\/> <br\/>    \/\/ Extract top 2<br\/>    int A = s.top();<br\/>    s.pop();<br\/>    int B = s.top();<br\/>    s.pop();<br\/> <br\/>    \/\/ Find a potential celevrity<br\/>    while (s.size() &gt; 1)<br\/>    {<br\/>        if (knows(A, B))<br\/>        {<br\/>            A = s.top();<br\/>            s.pop();<br\/>        }<br\/>        else<br\/>        {<br\/>            B = s.top();<br\/>            s.pop();<br\/>        }<br\/>    }<br\/> <br\/>    \/\/ Potential candidate?<br\/>    C = s.top();<br\/>    s.pop();<br\/> <br\/>    \/\/ Last candidate was not examined, it leads<br\/>    \/\/ one excess comparison (optimize)<br\/>    if (knows(C, B))<br\/>        C = B;<br\/> <br\/>    if (knows(C, A))<br\/>        C = A;<br\/> <br\/>    \/\/ Check if C is actually a celebrity or not<br\/>    for (int i = 0; i &lt; n; i++)<br\/>    {<br\/>        \/\/ If any person doesn&#039;t know &#039;a&#039; or &#039;a&#039;<br\/>        \/\/ doesn&#039;t know any person, return -1<br\/>        if ( (i != C) &amp;&amp;<br\/>                (knows(C, i) || !knows(i, C)) )<br\/>            return -1;<br\/>    }<br\/> <br\/>    return C;<br\/>}<br\/> <br\/>\/\/ Driver code<br\/>int main()<br\/>{<br\/>    int n = 4;<br\/>    int id = findCelebrity(n);<br\/>    id == -1 ? cout &lt;&lt; &quot;No celebrity&quot; :<br\/>               cout &lt;&lt; &quot;Celebrity ID &quot; &lt;&lt; id;<br\/>    return 0;<br\/>}<\/code><\/pre> <\/div>\n<p><strong>Output :<\/strong><\/p>\n<pre>Celebrity ID 2<\/pre>\n<p>Complexity O(N). Total comparisons 3(N-1). Try the above code for successful MATRIX {{0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}}.<\/p>\n<p><strong>Note:<\/strong> You may think that why do we need a new graph as we already have access to input matrix. Note that the matrix MATRIX used to help the hypothetical function <em>HaveAcquaintance(A, B),<\/em> but never accessed via usual notation MATRIX[i, j]. We have access to the input only through the function <em>HaveAcquiantance(A, B)<\/em>. Matrix is just a way to code the solution. We can assume the cost of hypothetical function as O(1).<\/p>\n<p>If still not clear, assume that the function <em>HaveAcquiantance <\/em>accessing information stored in a set of linked lists arranged in levels. List node will have <em>next<\/em> and <em>nextLevel<\/em> pointers. Every level will have N nodes i.e. an N element list, <em>next<\/em> points to next node in the current level list and the <em>nextLevel<\/em> pointer in last node of every list will point to head of next level list. For example the linked list representation of above matrix looks like,<\/p>\n<pre><strong>L0<\/strong> 0-&gt;0-&gt;1-&gt;0\r\n             |\r\n<strong>L1<\/strong>           0-&gt;0-&gt;1-&gt;0\r\n                       |\r\n<strong>L2<\/strong>                     0-&gt;0-&gt;1-&gt;0\r\n                                 |\r\n<strong>L3<\/strong>                               0-&gt;0-&gt;1-&gt;0<\/pre>\n<p>The function <em>HaveAcquanintance(i, j)<\/em> will search in the list for <em>j-th<\/em> node in the <em>i-th<\/em> level. Out goal is to minimize calls to <em>HaveAcquanintance<\/em> function.<\/p>\n<p><center><strong>Method 4 (Using two Pointers)<\/strong><\/center>The idea is to use two pointers, one from start and one from the end. Assume the start person is A, and the end person is B. If A knows B, then A must not be the celebrity. Else, B must not be the celebrity. We will find a celebrity candidate at the end of the loop. Go through each person again and check whether this is the celebrity. Below is C++ implementation.<\/p>\n<p><strong>C++ Programming:<\/strong><\/p>\n<div class=\"code-embed-wrapper\"> <div class=\"code-embed-infos\"> <\/div> <pre class=\"language-cpp code-embed-pre line-numbers\"  data-start=\"1\" data-line-offset=\"0\"><code class=\"language-cpp code-embed-code\">\/\/ C++ program to find celebrity in O(n) time<br\/>\/\/ and O(1) extra space<br\/>#include &lt;bits\/stdc++.h&gt;<br\/>using namespace std;<br\/> <br\/>\/\/ Max # of persons in the party<br\/>#define N 8<br\/> <br\/>\/\/ Person with 2 is celebrity<br\/>bool  MATRIX[N][N] = {{0, 0, 1, 0},<br\/>    {0, 0, 1, 0},<br\/>    {0, 0, 0, 0},<br\/>    {0, 0, 1, 0}<br\/>};<br\/> <br\/>bool knows(int a, int b)<br\/>{<br\/>    return MATRIX[a][b];<br\/>}<br\/> <br\/>\/\/ Returns id of celebrity<br\/>int findCelebrity(int n)<br\/>{<br\/>    \/\/ Initialize two pointers as two corners<br\/>    int a = 0;<br\/>    int b = n - 1;<br\/> <br\/>    \/\/ Keep moving while the two pointers<br\/>    \/\/ don&#039;t become same. <br\/>    while (a &lt; b)<br\/>    {<br\/>        if (knows(a, b))<br\/>            a++;<br\/>        else<br\/>            b--;<br\/>    }<br\/> <br\/>    \/\/ Check if a is actually a celebrity or not<br\/>    for (int i = 0; i &lt; n; i++)<br\/>    {<br\/>        \/\/ If any person doesn&#039;t know &#039;a&#039; or &#039;a&#039;<br\/>        \/\/ doesn&#039;t know any person, return -1<br\/>        if ( (i != a) &amp;&amp;<br\/>                (knows(a, i) || !knows(i, a)) )<br\/>            return -1;<br\/>    }<br\/> <br\/>    return a;<br\/>}<br\/> <br\/>\/\/ Driver code<br\/>int main()<br\/>{<br\/>    int n = 4;<br\/>    int id = findCelebrity(n);<br\/>    id == -1 ? cout &lt;&lt; &quot;No celebrity&quot; :<br\/>               cout &lt;&lt; &quot;Celebrity ID &quot; &lt;&lt; id;<br\/>    return 0;<br\/>}<\/code><\/pre> <\/div>\n<p><strong>Output :<\/strong><\/p>\n<pre>Celebrity ID 2<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The Celebrity Problem &#8211; Stack &#8211; In a party of N people, only one person is known to everyone. Such a person may be present in the party, if yes<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[73012,79607],"tags":[81849,81846,81847,81843,81841,81848,81842,81845,81844,81850],"class_list":["post-27593","post","type-post","status-publish","format-standard","hentry","category-data-structures","category-stack","tag-celebrity-identification-problem","tag-celebrity-problem-code","tag-celebrity-problem-graph","tag-celebrity-problem-induction","tag-celebrity-problem-leetcode","tag-celebrity-problem-python","tag-celebrity-problem-recursive-algorithm","tag-find-celebrity-leetcode-java","tag-find-the-celebrity-leetcode","tag-find-the-celebrity-python"],"_links":{"self":[{"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/posts\/27593","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/comments?post=27593"}],"version-history":[{"count":0,"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/posts\/27593\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/media?parent=27593"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/categories?post=27593"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wikitechy.com\/technology\/wp-json\/wp\/v2\/tags?post=27593"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}