赞
踩
Mar 2, 2016
首先声明一下节点的定义。
struct Node
{
int val;
Node* next;
public:
Node(int v) :val(v), next(NULL)
{}
};
本文的符号图示如下:
1、判断链表是否带环
判断链表是否带环,可以在头结点设两个指针,一个叫fast,一个叫slow,fast一下走两步,而slow一下走一步。如果链表中存在环的话,那么fast和slow必定会在环中相遇。若链表中没有环的话,那么fast必定先于slow指针先到达链表的尾节点。
建立数学模型证明如下:
令环长度为k,环节点编号为0,1,2,…,k-1。首先来看两节点初始都在节点0的时候的情况,时间t的时候两个指针的位置节点分别为
t
%
k
t\%k
t%k和
2
t
%
k
2t\%k
2t%k,节点相遇的时候有
t
%
k
=
2
t
%
k
(1)
t\%k=2t\%k \tag{1}
t%k=2t%k(1)
这个模型肯定有解,比如t等于k的整数倍这个时候正好相遇在起点。现在主要讨论除此之外还会在别的点相遇吗?这时的问题转化为等式2有解吗?
t
%
k
=
2
t
%
k
(2.1)
t\%k=2t\%k \tag{2.1}
t%k=2t%k(2.1)
0
<
t
%
k
<
k
(2.2)
0<t\%k<k \tag{2.2}
0<t%k<k(2.2)
将(2_1)转化为
t
%
k
=
(
t
%
k
+
t
%
k
)
%
k
t\%k=(t\%k+t\%k)\%k
t%k=(t%k+t%k)%k可见,等式右边不等于等式左边的,只有在两边都是零的时候才成立。
现在看看两个指针在刚开始的时候不是同时进入环的情况,因此将模型修改为
t
%
k
=
(
2
t
%
k
+
b
)
%
k
(3)
t\%k=(2t\%k+b)\%k \tag{3}
t%k=(2t%k+b)%k(3)
其中
0
≤
b
<
k
0\leq b<k
0≤b<k,表示慢指针进入环的时候快指针所在的位置,这里假设环的入口节点编号为0。对等式3求解可得
(
t
+
b
)
%
k
=
0
(t+b)\%k=0
(t+b)%k=0。综上可知若存在环,两个指针必定相遇,并且在慢指针到达节点k-b的时候相遇。
代码如下:
class Solution { public: bool HasCirclaInList(Node * pHead) { Node* pFast = pHead, *pSlow = pHead; while (true) { if (pFast->next != NULL && pFast->next->next != NULL) pFast = pFast->next->next; else return false; pSlow = pSlow->next; if (pFast == pSlow) return true; } return NULL; } };
2、求环长
当知道两个指针在环内的交点后,找一个指针在环内转一圈所走的步数即是这个环的长度。
这里有一个问题:可否用第一次相遇以前快指针走的步数减去满指针走的步数呢?答案是否定的,因为满指针进入的时候快指针可能已经转了不止一圈了,并且如果第一次相遇点编号大于k/2的时候,快指针在满指针进入环以后要在第二次赶上满指针的时候才能相遇。
class Solution { public: int LengthOfCircleInList(Node* pHead) { Node* pFast = pHead, *pSlow = pHead; bool flag = false; while (true) { if (pFast->next != NULL && pFast->next->next != NULL) pFast = pFast->next->next; else break; pSlow = pSlow->next; if (pFast == pSlow) { flag = true; break; } } if (flag) { int length = 1; Node* pNode = pSlow; while (pSlow->next != pNode) { pSlow = pSlow->next; length++; } return length; } else return 0; } };
3、求环的入口点
求解思路,找到第一次相遇点以后,将pSlow重新指向pHead,同时将pFast速度降为1,等到再次相遇的节点就是环的入口节点。
数学证明如下:
假设相遇点节点编号为c,有
t=a+c
2t=a+c+Nk
所以(a+c)%k=0,即证。
class Solution { public: Node* EntranceOfCircleInList(Node* pHead) { Node* pFast = pHead, *pSlow = pHead; bool flag = false; while (true) { if (pFast->next != NULL && pFast->next->next != NULL) pFast = pFast->next->next; else break; pSlow = pSlow->next; if (pFast == pSlow) { flag = true; break; } } if (flag) { pSlow = pHead; while (pSlow != pFast) { pSlow = pSlow->next; pFast = pFast->next; } return pSlow; } else return NULL; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。