问题描述:给定一个链表,检测该链表中是否存在闭环。要求时间和空间复杂度。
问题分析:如果存在环,那么我们在遍历链表的时候最终会进入一条无限循环中。我们可以把这视为2个人在操作运动,速度快的最终一定会赶上并且遇上速度慢的,也就是速度快的会比速度慢的多跑n整圈。
假设a和b俩个物体运动,速度分别为va,vb,要使得运动相差闭环的整圈。需要满足几个条件:
a. 首先速度需要有快慢我们让vb>=va
b. 速度慢的物体a要进入环区域才可能有机会。所以有a的移动距离sa>闭环之前的直线距离sl
c. 在这里我们是通过遍历的方式,所以vb是va的整数倍。这里的移动速度本质上还是遍历,时间复杂度方面,我们这里让vb=2va即可,则有b的运动距离sb = 2sa。b比a多移动的距离sba = sb - sa = sa。
d. 由以可知sa >= sl,另环的周长为sr,sa是sr的整数倍,这里我们取a的移动距离sa为>= sl的sr的最小整数倍的a和b相遇。那么有sba = sr,sa=sr,sb=2sr(sr >sl)。
e. 举例,如果sl=2,sr=5,那么sa = 5;如果sl = 10,sr=9,那么sa=18的时候b赶上a。
f. 时间复杂度为sa。代码逻辑
function HasLoop(list,out pmeet)
{
pmeet =null
var head = list.head, p1 = head, p2= head
var hasLoop = false
while(true)
{
if(null == p2.next || null == p2.next.next)
break;
p1 = p1.next
p2 = p2.next.next
if(p1 == p2)
{
pmeet = p1
hasLoop = true
break
}
}
return hasLoop
}
. 扩展:求一个闭环链表中的入环点
a. 我们假设在b赶上a的时候a在环内移动距离是s,那么运动起点到环起点距离是sa - s
b. 沿着当前运动方向到环起点的距离是sr - s = sa - s,与以上相同。
function GetLoopNode(list)
{
var pmeet
if(!HasLoop(pmeet)) return null
var p1= list.head,p2 = pmeet
while(p1!= p2)
{
p1= p1.next
p2 = p2.next
}
return p
}
扩展:检测两条链表相交汇合
- 将该2链表头尾拼接成一条:当然不一定需要真正意义的拼接,只是采用一定方式使得可以 遍历完全2个链表就可以了。
- 然后就采用以上的检测是否闭环和求入环点的方式进行处理。