前言
本文总结了力扣141.环形链表|以及142.环形链表||这两道有关环形链表的求解方案,去求证链表是否带环已经如何找出入环口的结点。
有关环形链表,在BAT等大厂面试中均有出现,一般是属于中等难度的题,需掌握
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
提示:
好,看完了题目描述,接下去我们来分析一下如何去求解这道题目
【牢记规则:快指针走两步,慢指针走一步】
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* fast, *slow;
fast = slow = head;
while(fast && fast->next) //判断奇数和偶数个结点的情况
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
return true;
}
return false;
}
};
【最后我们可以得出结论:当两个指针的相对速度为1时,一定能相遇;当两个指针的相对速度> 1时,则需要视两个指针之间的距离而定】
ListNode *detectCycle(ListNode *head) {
ListNode* slow, *fast;
fast = slow = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
ListNode* cur1 = fast;
ListNode* cur2 = head;
while(cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
}
return NULL;
}
if(slow == fast)
{
ListNode* meet = slow;
ListNode* otherHead = meet->next; //新的链表头
meet->next = NULL; //meet相当于尾结点,也就是尾结点指向空
ListNode* meetNode = getIntersectionNode(head,otherHead);
return meetNode;
}
因为快指针一定是先进入环内的,然后慢指针才进到环内,然后当慢指针进入下一个入口时,快指针走的一定是慢指针的两倍,所以慢指针在没有进入到下一个入口处时,快指针在中间的某个位置一定和其相遇了
证明如下:
在快指针fast进入环口3时,它已经走了k + n个结点,从图中可以清晰地看出,k为快指针和慢指针之间的距离,n为一个环的距离,而慢指针在进入环内相应地走了(k + n)/2个结点,从图中可以看出k是小于n的,所以(k + n)/2也一样是小于n的,即慢指针在进入环内一圈不到的距离就会和快指针相遇
所以慢指针走动的距离为L + N就够了,其不会再走第二圈
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* fast, *slow;
fast = slow = head;
while(fast && fast->next) //判断奇数和偶数个结点的情况
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
return true;
}
return false;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow, *fast;
fast = slow = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
ListNode* cur1 = fast;
ListNode* cur2 = head;
while(cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
}
return NULL;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
private:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA, *curB = headB; //遍历
int lenA = 0, lenB = 0; //记录两个链表的长度
while(curA->next){
lenA++;
curA = curA->next;
}
while(curB->next){
lenB++;
curB = curB->next;
}
if(curA != curB)
return NULL; //若两个结点的地址不同,则表示不相交,return NULL
ListNode* longer = headA, *shorter = headB; //先假设链表A长于链表B
if(lenB > lenA){ //若是假设错误则交换
longer = headB;
shorter = headA;
}
int gap = abs(lenA - lenB); //求出两个链表的长度差
while(gap--)
longer = longer->next; //先让长的链表走gap步,使得两链表位于同一起跑线
while(longer != shorter) //一同往后走,寻找两链表的交点(此时一定相交)
{
longer = longer->next;
shorter = shorter->next;
}
return longer;
}
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow, *fast;
fast = slow = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
ListNode* meet = slow;
ListNode* otherHead = meet->next; //新的链表头
meet->next = NULL; //meet相当于尾结点,也就是尾结点指向空
ListNode* meetNode = getIntersectionNode(head,otherHead);
return meetNode;
}
}
return NULL;
}
};
以上就是本文所要描述的所有内容,感谢您对本文的观看,如有疑问请于评论区留言或者私信我都可以🍀