带环链表得几个问题
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; } }
相关文章推荐
- day04之链表不带环相交+带环相交问题+fork函数输出几个短线
- 带环链表的几个问题
- 解题笔记(13)——几个链表的问题
- 7.微软亚院之编程判断俩个链表是否相交(为了简化问题,我们假设俩个链表均不带环)
- 单链表带环问题
- 《C语言实现链表相交、带环问题》
- 链表——带环问题
- 链表的几个经典问题
- 【每日一题-3】链表带环问题
- 链表带环问题求解?是否带环,环的入口点,环长度
- 链表面试题之带环问题
- 链表带环问题/设计一个类不能被继承/设计一个类只能在堆(栈)上创建对象
- C语言数据结构之单向链表(已经调试可以实现相应的功能了,可是还是有几个问题现在还是不大理解,希望大家能够一起探讨)
- C语言强化(七)链表相交问题_3 判断链表是否带环
- C语言强化(七)链表相交问题_3 判断链表是否带环
- 链表中的带环相交问题
- 链表的几个经典问题
- 65. 链表是否带环、环入口、环长度、链表相交问题分析与总结
- 解题笔记(13)——几个链表的问题
- 带环单链表及链表相交问题的分析及代码实现