您的位置:首页 > 理论基础 > 数据结构算法

带环链表得几个问题

2017-01-21 10:06 309 查看

1、判断一个链表是否有环,如果有环,则返回入环的第一个节点,否则返回null

如果一个链表有环,遍历一个链表便永远不会到达null,否则必定会到达null。设置两个指针,刚开始都指向头节点,遍历时,一个指针每次前进一步,我们称之为慢指针,另一个每次前进两步,称之为快指针,这样,如果链表没有环,快指针必然会到达null,如果有环,两个指针必然会相交于一点。

下面再来看看如何找到入环的第一个节点,假设从头节点到入环第一个节点的长度为m,两个指针第一次相遇时的节点距离环入口点的长度为t,环的长度为n,那么此时慢指针走的长度为m+t,快指针走的长度为m+t+kn(k=0,1,2...),kn项表示快指针有可能在环内走了几圈后再与慢指针相遇,这时满足

m+t+kn = 2(m+t)

简化得到

m = (k-1)n + n - t

其中n-t项正表示了慢指针走完当前环还需要走的长度,从这里就可以看出此时如果将快指针放回头节点,然后让它每次只走一步,那么这两个指针必然会相交,并且相交的交点就是入环点。

ListNode *detectCycle(ListNode *head)
{
ListNode *fast = head;
ListNode *slow = head;

while ( fast && fast->next )
{
slow = slow->next;
fast = fast->next->next;
if ( slow == fast ) break;
}

if (fast == NULL || fast->next == NULL)
return NULL;

slow = head;
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}

return slow;
}


2、判断两个链表是否相交,相交则返回第一个交点

如果两个链表相交,则交点后面部分两个链表是相同的,当然长度也就相同,关键在于两个链表不相交的部分,所以可以先求出两个链表的长度len1和len2,如果len1大于len2,则链表1先开始往前走,直到从当前节点开始两个链表的长度相同,然后再同时前进,直到两个节点相同,就是第一个交点。

int getListLength(ListNode *list)
{
ListNode *p = list;
int len = 0;
while (p)
{
len++;
p = p->next;
}

return len;
}

/**
* @param headA: the first list
* @param headB: the second list
* @return: a ListNode
*/
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
{
if (!headA || !headB)
{
return nullptr;
}
int lenA = getListLength(headA);
int lenB = getListLength(headB);

while (lenA > lenB)
{
headA = headA->next;
lenA--;
}

while (lenA < lenB)
{
headB = headB->next;
lenB--;
}

while (headA != headB)
{
headA = headA->next;
headB = headB->next;
}

return headA;
}

3、如何判断两个有环链表是否相交,相交则返回第一个相交点

这个问题可以首先利用问题1分别获得两个链表的环入口点loop1和loop2,此时如果loop1和loop2相等,则表明两个链表在入环前就已经相交,这个时候可以利用问题2的方法获得相交点,只是把loop1当作尾节点即可。
如果loop1和loop2不相等呢,这个时候有两种情况,要么两个链表不相交,要么两个链表在环内相交。这个时候可以从loop1出发走一圈,如果在回到loop1的时候一直没有遇到loop2,那么表明两个链表不相交,否则就相交,此时返回loop1或者loop2都可以。

ListNode* bothLoop(ListNode* head1, ListNode* loop1, ListNode* head2, ListNode* loop2)
{
ListNode* cur1 = nullptr;
ListNode* cur2 = nullptr;

if (loop1 == loop2)
{
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1)
{
n++;
cur1 = cur1->next;
}
while (cur2 != loop2)
{
n--;
cur2 = cur2->next;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = abs(n);
while (n != 0)
{
n--;
cur1 = cur1->next;
}
while (cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
else
{
cur1 = loop1->next;
while (cur1 != loop1)
{
if (cur1 == loop2)
{
return loop1;
}
cur1 = cur1->next;
}
return nullptr;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  链表 数据结构 算法