1、给定单链表,检测是否有环。
使用两个指针p1,p2从链表头开始遍历,p1每次前进一步,p2每次前进两步。如果p2到达链表尾部,说明无环,否则p1、p2必然会在某个时刻相遇(p1==p2),从而检测到链表中有环。


2、如果单链表有环,找到环节点。

第一步,先按照上一题让p1和p2相遇,则相遇的点必然在环里。

假设链表起点到环节点距离为l,环节点到p1,p2相遇点的距离为a,

则p1前进距离为:l+a

p2前进距离为:2(l+a)

2(l+a)-(l+a)= nc // p2比p1多跑的距离为n圈c为环的周长

则 l+a = nc

第二步,p1再从链表开始跑,p2从相遇点开始跑,当跑了l距离以后。

p1所在位置则是环节点。

p2所在位置是2(l+a)+l = 2nc + l,p2必然也在环节点了,

所以当p1,p2 再次相遇,就是环节点的位置。


3、 给定两个单链表(head1, head2),检测两个链表是否有交点,如果有返回第一个交点。

如果head1==head2,那么显然相交,直接返回head1。

否则,分别从head1,head2开始遍历两个链表获得其长度len1与len2。假设len1>=len2,那么指针p1由head1开始向后移动len1-len2步。指针p2=head2,下面p1、p2每次向后前进一步并比较p1p2是否相等,如果相等即返回该结点,否则说明两个链表没有交点。


4、给定单链表头结点,删除链表中倒数第k个结点。
使用两个节点p1,p2,p1初始化指向头结点,p2一直指向p1后第k个节点,两个结点平行向后移动直到p2到达链表尾部(NULL),然后根据p1删除对应结点。


5、​找出链表的中间元素

单链表的一个比较大的特点用一句广告语来说就是“不走回头路”,不能实现随机存取(random access)。如果我们想要找一个数组a的中间元素,直接a[len/2]就可以了,但是链表不行,因为只有a[len/2 - 1] 知道a[len/2]在哪儿,其他人不知道。因此,如果按照数组的做法依样画葫芦,要找到链表的中点,我们需要做两步(1)知道链表有多长(2)从头结点开始顺序遍历到链表长度的一半的位置。这就需要1.5n(n为链表的长度)的时间复杂度了。有没有更好的办法呢?有的。想法很简单:两个人赛跑,如果A的速度是B的两倍的话,当A到终点的时候,B应该刚到中点。这只需要遍历一遍链表就行了,还不用计算链表的长度