1 基本的原理是,调用knows函数的时候,如果a认识b,则a不是名人,因为名人不认识任何其他人;如果a不认识b,则b不是名人,因为如果b是名人,所有人都会认识他。
2 因此每调用一次knows函数,就可以淘汰掉一个人,因此在O(n)时间内,我们可以淘汰掉n-1个人(为什么不是n?因为总共只有n个人,有一个是名人啊,笨!)
3 最后还要确认,是否所有其他人都知道这个人,而这个人不知道其他所有人
4 以上是第一种方法
5 第二种方法是,找到一个候选人,看其他人是否认识他
6 第三种是directed graph的方法:利用好两个重要条件,1是名人不认识所有人,2是所有人认识这个名人;而且还有个关键的是只有一个名人。所以我们可以建立一个有向图
7 名人不知道任何人表现在图里就是,他没有到任何其余点的路径
8 我们从一个点出发,顺着路走,只走没有走过的路,比如从0到1,但我们不会走1到0,即使1到0有路,然后走2,3,4。最终我们会停在一个点,这个点没有out edge。然后我们重新遍历,看看是否所有其他点都能走到他,而他不能走到其他人
9 还有一种流行的方法是,假定候选人candidate是0,那我们先遍历一遍,加入遍历到i的时候,candidate认识i,则将candidate置成i,等遍历完后,我们再来判定这个candidate是否是名人,如果不是,则返回-1,如果是,则返回candidate。这里的原理是,因为每次调用knows函数,我们都能淘汰掉一个人,所以当遍历完一遍后,我们只剩一个candidate
10 if any(knows(x, i)for i in xrange(x)): return -1代表只要有一个是True,就返回-1,也就是只要有一个case,x认识其他人
11 if any(not knows(i, x) for i inxrange(n)): return -1只要有一个人不知道这个candidate,也返回-1
12 为什么遍历一遍得到candidate后,还要测试一下呢?因为前面只是一个一个淘汰的,并不能保证其他所有的人都认识这个candidate
13 在下图中,范围为什么是到candi呢?因为from i+1到n,已经在前面验证过了