知乎上“有哪些令人拍案叫绝的算法?”部分问题整理+思路整理_1.26

转自知乎https://www.zhihu.com/question/27547892
一.多项式系数算法

有一个黑匣子,黑匣子里有一个关于 x 的多项式 p(x) 。我们不知道它有多少项,但已知所有的系数都是正整数。每一次,你可以给黑匣子输入一个整数,黑匣子将返回把这个整数代入多项式后的值。那么,最少需要多少次, 我们可以得到这个多项式每项的系数呢?并给出相应方案

二.交易员薪水问题(避免产生公共知识)

有n>2个交易员,他们想知道他们平均的薪水,但是又不想任何人知道自己的薪水,求方案?(交易员数量已知,且为公共知识)

三.色盲证明问题

Alice是色盲,她有两个球,外观完全一样,Bob告诉她这两个球颜色不同,问Bob怎么向Alice证明这俩球颜色不同。求方案?

四.特殊元素查找-过半元素

有个list,已知存在majority element,就是出现次数多余一半的元素,怎么把它找出来。比如 abaacbbacaa 中的a。如果不知道list里面是不是有majority element,且已知元素总数量。如果有就把它找出来,没有的话return none呢?
要求时间复杂度O(n),空间复杂度O(1)

五.摔杯子问题(查找问题)(个人认为最有价值的题目)

有一种玻璃杯质量确定但未知,需要检测。
有一栋100层的大楼,该种玻璃杯从某一层楼扔下,刚好会碎。
现给你两个杯子,问怎样检测出这个杯子的质量,即找到在哪一层楼刚好会碎?
要求你的方案尽可能减少最坏结果下的测试次数

六.折返问题

一些蚂蚁在树枝上向其中一端爬,爬到末端就掉下去,如果相遇则向反方向爬,蚂蚁速度相同,给定位置和方向,求所有蚂蚁从树枝上落下来的时间

思路及答案如下

一.

笔者思考
多项式公式为F(x) = i0+i1*x+i2*x2+i3*x3+…+ik*xk
n进制转十进制的公式为:F(n)=i0+i1*n+i2*n2+i3*n3+…+iknk
只要将合理的n代入多项式中,将得到的十进制数值转化为n进制的数值,n进制的数每倒数k位就对应着一个ik-1
那么,如何使这个n“合理”呢?
先举一个随意取n的错误例子
比如我令n=10,得到答案100,但是答案是10
x还是x2呢?
问题在哪里?
如果n小于其中一个ik,就会产生上面那个例子的问题
(原理不详,求能解释清楚的大佬)
那如何找到大于任何ik的呢?
取n=1,得到的数值+1(加多少正整数都行)就一定大于i、任一ik

答案如下:
1.取n=1,得到A
2.取n=A+1,得到B
3.将B进行A+1进制转化,n进制的数每倒数k位就对应着一个ik-1
收获:对进制计算有了船新的理解

二.

笔者思考
这个问题有两个要求
1.所有人都知道平均薪水
2.所有人都不知道任意一个其他人的薪水

其实要完成第一个要求,不一定要所有人都具备计算平均薪水的“能力”,只要让一个人具备这个“能力”就好了。

这样思考的话,问题将被分解为解决以下要求
1.让有且仅有一个人具备计算能力
2.该人不能得知其他任意一人的薪水
3.其他人不能得知任意一人的薪水
4.得到平均薪水的信息后也不能获得任意一人薪水的信息(n>2的话满足123就做不到,pass)

(编不下去了,直接贴答案吧233)

答案如下
先让第一个人将自己的薪水i1+一个只有自己知道的值k告诉第二个人,让第二个人把自己的薪水i1加上这个值(k+i1)得到(k+i1+i2)传递给第三人,以此类推。最后一个人加完后把结果(k+i1+i2+…+in)告诉第一个人,第一个人将结果减去k得到总值,再把总值/n就得到平均值啦

收获:设计算法一定要可数字化!不然思路完全是一团糟。。。

三.

答案如下

A将某个球“标记”(A知道B不知道且无法的标记,比如A用脑子记住哪个是哪个球233)后打乱顺序,让B猜出哪个是标记了的球。n次猜中能将“A是色盲B不是色盲”事件的概率变成【1-(1/2)^n】。比如n取100000,这个概率就是99.999…%

收获
算法证明在计算机大量计算的条件下可以逼近100%正确,反正不追求数学的严谨证明

四.

笔者思考
时间复杂度为O(n)的话当然是遍历啦,空间复杂度。。。请看答案!

答案如下
建立一个数据结构,类似于a:0。然后列表从第一位向最后一位遍历。分三种情况改变数据。
1.当数字为0时,将字母改变成指向的字母,并且数字部分+1
2.当字母和指向的字母相同,数字部分+1
3.当字母和指向的字母不同,且数字>0,数字部分-1
后面就不用说了吧

收获
一些空间复杂度O(1)的算法的特点:建立一个或若干个“值”,查找时只改变上述的“值”,而不把查找的对象存储下来

笔者思考
假设只有一个杯子,为了保证得到正确答案,那就不得不从1楼一直摔到100楼
但此时有两个杯子,我们就可以“分区间式”地摔杯子啦,第一个杯子从下往上摔就好了
这样做的目的是,将第二个杯子的测试范围缩小(比如你用第一个杯子在35楼没碎,50楼碎了,那第二个杯子只要从36-49层测试就可以啦)。
那如何设计才能尽可能减少测试次数呢?
要知道,第一个杯子在“摔”的时候也是算在测试次数里面的;换而言之第一个杯子的区间大小应该随着测试的次数逐渐变小,通过第一个杯子测试次数增加时减少第二个杯子的测试次数,达到一种微妙的最小平衡
但是如何求得这种平衡呢?
其实只要第一个杯子每摔一次,下一个区间大小减小1就好了
假设从第x层楼开始摔,求x+(x-1)+(x-2)+…+2>=100即可
解得x最小为14
这种方法的最坏情况需测试14次

答案如下
第一个杯子:
x+(x-1)+(x-2)+…+2>=100
解得x最小为14
故第一个杯子在14,27,39,50,60,69,77,84,90,95,99层摔,直到摔碎即可得到第二个杯子的区间
第二个杯子不解释

收获
n分法的又一次船新体验

备注
共有五种算法,详见:https://wenku.baidu.com/view/7c9de809581b6bd97f19ea72.html

答案如下
将每个蚂蚁的路径作为单独的路径(假设蚂蚁们本来不会相撞),计算每个蚂蚁掉下去的时间,取其中的最大值
(其实类似于冒泡排序的思路,做一个等效替换。)
(其实我觉得这就是一个脑筋急转弯。。。可惜我还真没想出来)

收获
get到了一种等效替换的思路。

你可能感兴趣的:(知乎上“有哪些令人拍案叫绝的算法?”部分问题整理+思路整理_1.26)