circular linked list
1. Topic
Link: 141. Circular linked list I
2. Ideas
3. Code
bool hasCycle(struct ListNode *head) {
struct ListNode*slow = head;//慢指针
struct ListNode*fast = head;//快指针
while(fast&&fast->next)//快指针所指向的节点和快指针的下一个节点都不为空的时候才向后执行
{
slow = slow->next;//慢指针一次走一步
fast = fast->next->next;//快指针一次走两步
if(slow==fast)//当慢指针追上快指针时停下,说明是带环链表
return true;
}
return false;//慢指针没有追上快指针式
}
4. Expand the question
Extended Question 1
1. Slow takes one step at a time and fast takes 2 steps at a time. Can you catch up? Please prove.
Must be able to catch up.
Extended Question 2
2. Slow takes 1 step at a time and fast takes 3 steps at a time. Can you catch up? fast how about 4 steps at a time? What about n steps? Please prove.
Not necessarily, it may never catch up in special scenarios!
Other reasoning about taking 4 steps and n steps at a time is similar to the above.
Let's discuss the situation when fast takes 4 steps at a time.
Extended Question 3
3. Request the entry point of the linked list ring. Returns NULL if the linked list has no loops.
This question is actually the 142nd question of leetcode. Let's take a look at it!
topic
Link: 142. Circular Linked List II
ideas
Two methods:
Idea 1
1. Formula Proof
Code:
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode*slow = head;
struct ListNode*fast = head;
while(fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow==fast)
{
struct ListNode*meet = slow;//记录下相遇的节点
while(meet!=head)//meet节点与head节点同时开始走,相遇点
{
meet = meet->next;
head = head->next;
}
return meet;
}
}
return NULL;
}
Idea 2
2. Open the linked list for conversion
Through the above method, the problem is transformed into the problem of finding the intersecting nodes of the intersecting linked list.
Note: In the following code, headB is meet->next, and headA is head. It is worth noting that after assigning meet->next to headB ,Don't forget to assign meet->next to a null pointer.
Code:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {//复用的是找相加节点的代码
struct ListNode*tailA = headA;//记录链表A的尾节点
struct ListNode*tailB = headB;//记录链表B的尾节点
int lenA = 1;//记录链表A的长度
int lenB = 1;//记录链表B的长度
while(tailA->next!=NULL)
{
tailA = tailA->next;
lenA++;
}
while(tailB->next!=NULL)
{
tailB = tailB->next;
lenB++;
}
if(tailA!=tailB)//尾节点不等,所以直接返回NULL
{
return NULL;
}
//相交,求节点,长的先走差距步,再同时走找交点
struct ListNode*shortList = headA,*longList = headB;//默认A是较长节点的链表,B是较短的
if(lenA>lenB)
{
longList = headA;
shortList = headB;
}
int gap = abs(lenA - lenB);//gap存储的是节点数的差值
while(gap--)
{
longList = longList->next;//节点数多的先走gap步
}
while(longList!=shortList)//两者同时开始进行遍历,在交点处停下
{
longList = longList->next;
shortList = shortList->next;
}
return longList;//随便返回一个就行,因为两个都是交点
}
struct ListNode *detectCycle(struct ListNode *head)
{
struct ListNode*slow = head;
struct ListNode*fast = head;
while(fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow==fast)
{
struct ListNode*meet = slow;//记录下相遇的节点
struct ListNode*headB = meet->next;
struct ListNode*headA = head;
meet->next = NULL;
struct ListNode*ret = getIntersectionNode(headA,headB);//返回的节点存储在ret中
return ret;
}
}
return NULL;
}