http://hi.baidu.com/gmfoqlmthriprur/item/fb96f7c8ca4db72fef46657f
相交的话,一定是Y型或者V型的。所以只需要判断两个链表最后一个节点就可以了。
问题描述:
给定两个单向列表的头指针,比如h1、h2,判断这两个列表是否相关。
注,这里只讨论这两个列表均不带环的情况。
解法一:直观的想法
估计有些人一看到这个题目,便不管三七二十一,从第一个链表开始遍历,判断它的每一个节点是否在第二个链表中。这是最简单的方法,但是时间复杂度却是O(length(h1)*length(h2)),非常耗时间。
解法二:
由于两个列表都没有环,那么我们可以把第二条链表接到第一条链表后面,如果得到的链表有环,则说明这两条链表有相交,如果没有环,则说明这两条链表没相交。判断一个链表是否有环,也不是一件简单的事,但是这里我们可以发现,假如有环,则第二条链表的表头一定在环上,因此我们只需要从第二条链表开始遍历,看是否会回到起始点就可以判断出来,当然了,最后不要忘了恢复原来的状态,去掉第一个链表到第二个链表表头的指向。
解法三:
上面的解法二的解法比起解法一来说明显高效了很多,但是要把两条链表拼起来,最后还要恢复它的状态,不免太麻烦了一点,那么有没有更好的办法呢?我们知道假如两条链表相交于某节点上,那么从该节点开始,两条链表共用同一个结点,也就是说最后一个节点肯定是共用的,这样我们便可以通过判断最后一个结点是否为两条链表共用来判断两条链表是否相交。
首先先遍历第一条链表,记住最后一个节点,接着遍历第二条链表,到最后一个节点时与第一条链表的最后一个节点相比较,如果两个节点相同,则两条链表相交,否则为不相交。该算法的时间复杂度为O(length(h1)+length(h2)),而且只用了一个额外的指针来保存最后一个节点,无疑地,这个方法比解法二更优。
扩展问题 如果两个链表相交,找出相交的第一个节点?
在判断相交的过程中要分别遍历两个链表,同时记下各自的长度。然后再遍历一次:长链表节点先从头节点出发前进(lengthMax-lenghMin)步,之后两个链表同时前进,每次一步,相遇的第一个节点即为两个链表相交的第一个节点。程序描述如下:
Node *intersection(Node *head1, Node *head2)
if(!head1 || !head2)
return NULL;
int len1 = 1;
int len2 = 1;
bool result = false;
//判断两个链表是否相交,同时记下各个链表的长度
Node *p = head1;
while(p->next)
pLen++; p=p->next
q=head2
while(q->next)
len2++; q=q->next
result=(p==q)
if(result)
int steps = abs(len1 – len2)
Node *head = len1 > len2 ? head1 : head2;
while(steps)
head = head->next
steps –-
len1 > len2 ? p = head,q=head2 ? q = head,p=head1
while(p!=q)
p=p->next
q=q->next
return p
return NULL

2s = s + nr
s= nr
设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
{
int isLoop=0;
LinkList *fast,*slow;
fast=list;
slow=list;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;//fast每次两步,slow每次一步
if(fast==slow) //当两指针相等时,判断链表中有环
{
isLoop=1;
break;
}
}
if(isLoop==1)//链表中有环时
{
slow=list;
while(slow!=fast)//一个头指针,一个相遇点指针,两个第一次相等时为环入口点
{
slow=slow->next;
fast=fast->next;
}
return slow;
}
else
{
cout<<"链表中没有环";
return NULL;
}
}