文章目录
费曼算法
1.写下这个问题
2.真正地努力思考
3.写下解决办法
——物理学家Murray Gell-Mann,1992年
面试官问这个问题的目的是什么
面试造航母,工作拧螺丝,这句话放在程序员招聘中再合适不过了。但是,无论是人力面还是技术面,面试官的时间都是很宝贵的。面试官需要在短短一个小时的时间内,尽可能多的全面了解一个人的技术能力,就绝对不会随便问问题,总得为公司负责,也一定要为被招聘者负责。那么,面试官很多面试官纠结于算法问题的原因是什么呢?很多原因,举几个例子,
- 数据结构和算法对软件创作来说确实必不可少,这往往成为程序效率提升的瓶颈
- 或许在某些程序岗位,算法没那么重要,或者换句话说,要求并不高。但是,能关注算法至少说明应聘者是一个爱学习,爱钻研的人
- 没有人是全能的,就算是很厉害的人,对于不了解的算法也是很难给出令人满意的回答,毕竟那些精彩的算法,都是牛人们心血的结晶,指望面试的几分钟应急出来,可能么?所以,某些问题答不出来并没有关系,技术面很少因为这个刷人,这时候面试官会观察应聘者的抗压能力,和在压力下的思考问题的能力。要给处一个解决问题的方案。
- 僧多粥少,总要有个评判标准
- 其他
快慢指针的工作原理
问题描述:给定一个单向链表,如何判断其是否有环
答案:快慢指针,使用两个指针A,B,同时从起点出发,A每次移动步长为1,B每次移动步长为2,如果A和B能够“相遇”,那么证明链表有环。
我们通过下边的图先直观的看一下,环是如何发现的,后面再来看数学表达。可以看出,通过5步,快指针追上了慢指针,确定有环。
下面是数学模型,我们从图三开始看,此时慢指针刚刚入环。那么此时,整个场景可以用以下模型表示,
- 快指针比慢指针超前d个节点
- 环的长度为n
- n > 1 n>1 n>1
- d < n d<n d<n
步数 | 慢指针移动距离 | 快指针移动距离 | 两者距离 |
---|---|---|---|
1 | 1 | 2 | d+1 |
2 | 2 | 4 | d+2 |
3 | 3 | 6 | d+3 |
… | … | … | … |
k | k | 2k | d+k |
当 d + k = n d+k=n d+k=n时,快指针追上慢指针,于是确定有环。
快慢指针究竟几步可以定位环
在上边我们得到结论,对于快慢指针(一步一节点和一步两节点)来说,定位环时必然满足下边得等式。
d
+
k
=
n
d+k=n
d+k=n
因为
d
<
n
d<n
d<n,所以
k
=
n
−
d
k=n-d
k=n−d有解。
我们用上边得公式验证一下本文中得第一个例子,
n
=
5
,
d
=
3
n=5,d=3
n=5,d=3,因此我们需要
n
−
d
=
2
n-d=2
n−d=2,表明我们只需要两步就可以定位环,与前边例子里得步骤4和5对应。
总共得步数则需要加入入环时已经走过的距离,因为快指针是慢指针的两倍,所以当入环时,如果快指针没有在环里转了几圈的情况下,这个距离也等于d,此时我们需要的步数为
d
+
(
n
−
d
)
=
n
d+(n-d)=n
d+(n−d)=n.
可以看出,这种情况下何时能定位环仅取决于环的长度,上边的例子中环的长度为5,所以我们仅用5步便定位了环。
那么,如果环的长度比入环前的距离小又是什么情况呢?我们不难推导一个更加普适的公式,
此时的步骤数目
k
=
(
n
−
m
o
d
(
d
,
n
)
)
+
d
k=(n-mod(d,n))+d
k=(n−mod(d,n))+d,
m
o
n
(
d
,
n
)
mon(d,n)
mon(d,n)表示求余,当
d
<
n
d<n
d<n时,
m
o
d
(
d
,
n
)
=
d
mod(d,n)=d
mod(d,n)=d
从上边的公式可以看出,
k
=
n
+
d
−
m
o
d
(
d
,
n
)
k=n+d-mod(d,n)
k=n+d−mod(d,n),当
d
>
n
d>n
d>n时,
k
>
n
k>n
k>n
快指针的速度只能是双倍速么
现在我们再来思考一个问题,双指针方法的移动步长只能时1和2么?如果快指针跑的更快是否可以更快找到环呢?亦或时快指针总是跳过慢指针永远找不到环呢?我们先来实际走一下。
步数 | 慢指针移动距离 | 快指针移动距离 | 两者距离 |
---|---|---|---|
1 | 1 | p | d+p-1 |
2 | 2 | 2p | d+2p-2 |
3 | 3 | 3p | d+3p-3 |
… | … | … | … |
k | k | kp | d+kp-k |
还是同样的条件定位环,即,
n
=
d
+
k
p
−
k
=
d
+
k
(
p
−
1
)
n=d+kp-k=d+k(p-1)
n=d+kp−k=d+k(p−1),可以看出上边步长为1和2时(即p=2),是此公式的特例。
那么我们来求一下几步可以定位环,
k
=
(
n
−
d
)
/
(
p
−
1
)
k=(n-d)/(p-1)
k=(n−d)/(p−1)
当
n
−
d
n-d
n−d可以被
p
−
1
p-1
p−1整除时,k有解,此时可以定位环。那么,否则呢?实际上,我们多转几圈也是可以的。结果应该是,
l
/
(
p
−
1
)
l/(p-1)
l/(p−1),
l
l
l为
n
−
d
n-d
n−d和
p
−
1
p-1
p−1的最大公约数。
其他判定单向链表环路的方法
快慢指针是单向链表找环的最快方法,时间复杂度为
O
(
n
)
O(n)
O(n),空间复杂度为
O
(
1
)
O(1)
O(1).
这个方法很巧妙,如果我们不知道,第一反应可能是两个遍历环的方法,此时我们的时间复杂度为
O
(
n
2
)
O(n^2)
O(n2),空间复杂度为
O
(
1
)
O(1)
O(1).
那么,既然有了一个方法,我们就应该意识到
O
(
n
2
)
O(n^2)
O(n2)是一个不和实际的方法,这个算法时间增长太快。通常我们有更好的方法,我们可以考虑是不是可以用空间换时间呢?
于是我们,有了哈希法。
从下图可以看出,我们通过空间换来了时间,时间复杂度为
O
(
n
)
O(n)
O(n),空间复杂度为
O
(
n
)
O(n)
O(n).
不过可以看出,哈希法的时间是稳定的,总共需要n步来定位环,而快慢指针则是线性时间,一定是快于哈希法的。
小结
关于双指针法还有什么问题呢?有问题/有指正的请留言。