大家好,今天我对环形链表进行了一个学习,下面是我的学习内容
1.给定一个链表,判断链表中是否有环。141. 环形链表 - 力扣(LeetCode)https://leetcode.cn/problems/linked-list-cycle/description/
对于这一题 首先我们要明白 如果成环 代表着链表是循环的 如图
可以把他的循环想象成走了一段距离 然后 形成一个圆的循环
对此 我的思路是快慢指针 快的指针走 慢的指针在快的指针走了一遍或者x遍循环之后
如果两个指针相遇 也就意味着循环成环
下面是解题过程
为什么一定会相遇呢?我认为一定会相遇 证明
在快慢指针的过程中 我们需要判断快的指针要走多少步
如果快指针一次走两步的话 假设slow进环时 与fast的距离为N(偶数) 接着每进行下一次行动 距离变成N-1 N-2……2 1 相遇。
如果走三步呢 假设slow进环时 与fast的距离为N(奇数) 接着每进行下一次行动 距离变成N-2 N-4 ……3 1 -1 这时候就要分情况总结了
距离为-1的话 进行下一次环的循环 此时环的距离为C-1
分两种情况C-1为偶数 C-1为奇数
偶数的循环因为fast每次和slow相差的距离为2 后面的距离 4 2 0相遇;为奇数 继续开启下一次的追击 C-2 ……
因此 总结一下 如果 N为偶数的话 第一次循环就相遇 如果 N为奇数的话 第一轮的追击错过
开启新的一轮(C-1),如果C-1为偶 相遇 C-1 为奇数 继续追击……
fast走4 5 ……情况类似
所以 如果N为奇数C为偶数的话 相遇不到一起
如果用公式来计算的话
假设fast走3步 slow进环时 fast已经走了x圈 slow走了L距离 fast走了L+C*x+C-N
3L = L+C*x + C -N;
2L = (x+1)C -N;
偶数 =(x+1)偶数 -奇数
显然不相等
反正N为奇数且C为偶数条件不能同时存在 ,永远追不上的条件不成立
结论:一定能追上
追上的话就是1.N为奇数 第一轮追击C-1
a.C-1为偶数的话 追上
b.C-1为奇数的话 永远追不上
2.N为偶数 C为偶数
第一轮就追上
下面是代码
bool hasCycle(struct ListNode *head) {
struct ListNode* slow = head,*fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
return true;
}
return false;
}
2.环形链表IIhttps://leetcode.cn/problems/linked-list-cycle-ii/description/
返回到成环的入口点
也是快慢指针的方法
下面是我的思考过程
要算出成环的节点 首先判断走的路程
fast 走的是slow的2倍
2(L+N)= x*C + L + N
L+N = x*C
L = x*C -N
所以slow走的路程就是相遇后 从相遇点走到起始成环的地点
代码如下
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow = head,*fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
//相遇
if(slow == fast)
{
struct ListNode *meet = slow;
while(meet != head)
{
meet = meet->next;
head = head->next;
}
return meet;
}
}
return NULL;
}
换一种方法
新建一个指针链表
快指针先走 判断插值
在同时走 第一个相等是就是交点 最后返回值就是起始点(这里用到了相交链表的内容)https://leetcode.cn/problems/intersection-of-two-linked-lists/description/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* newA = headA,*newB = headB;
int lenA = 0,lenB = 0;
while(newA)
{
newA = newA->next;
++lenA;
}
while(newB)
{
newB = newB->next;
++lenB;
}
//尾节点不相等就是不相交
if(newA != newB)
return NULL;
//长的先走差值 再同时走 第一个相等的就是交点;
int gap = abs(lenA-lenB);
struct ListNode* longList = headA,* shortList = headB;
if(lenB > lenA)
{
longList = headB;
shortList = headA;
}
while(gap--)
{
longList = longList->next;
}
while(longList !=shortList)
{
longList = longList->next;
shortList = shortList->next;
}
return shortList;
}
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow = head,*fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
//相遇
if(slow == fast)
{
struct ListNode *meet = slow;
struct ListNode *newhead = meet->next;
meet->next = NULL;
return getIntersectionNode(head,newhead);
}
}
return NULL;
}
今天的内容就结束了