环形链表1
运用快慢指针的方法,fast ,slow从头节点出发,快指针走两步,慢指针走一步,若有环,快指针先进环,后续如果慢指针和快指针相遇,则链表带环。转换成了追击问题。
struct ListNode {
int val;
struct ListNode *next;
};
typedef struct ListNode LN;
bool hasCycle(struct ListNode *head) {
LN*slow,*fast;
slow=fast=head;
while(fast && fast->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
return true;
}
return false;
}
思考:为什么一定会相遇,会不会错过,永远追不上?若快指针走三步,四步呢?
证明:假设链表就是有环,slow(1步)进环时,fast(两步)与slow的距离为N,追击过程中,每走一次,N都会-1,最后到0。本题的思想证明,距离为0就是追上了。
若fast走三步,同样假设slow进环时,fast与slow相差N,
fast追击slow过程中,距离变化一直-2,但是最后结果要注意,N为偶数时,最后变为0,N为奇数时,最后为-1.而当距离为-1时,两指针会错过,进行新一轮追击。这时假设环的长度为C。新的距离就变成C-1了,这是又要将C分为奇数,偶数进行讨论。
那么是否存在N是奇数且C是偶数的情况呢,
假设从出发位置到进环的位置相差L,slow进环时,fast已经走了x圈,且fast与slow相差N:
进环时:slow走的距离->L
fast走的距离->L+x*C+C-N
fast的距离应该为slow的三倍:3*L=L+x*C+C-N
化简为:2*L=(x+1)*C-N 若要满足该等式,若C是偶数,N必须是偶数。若N是奇数,如果C是偶数,则(x+1)*偶数一定是偶数,偶数-奇数!=偶数。
所以上述条件不成立,故永远追不上的条件不成立。
结论:一定能追上。
N是偶数第一轮追上。N是奇数第一轮追不上,C是奇数,第二轮追上。
其他走四步等的条件证明过程类似。
环形链表2
本题相较于第一个环形链表题,多了返回节点位置的步骤,所以最初思路也是通过快慢指针,快慢指针相遇,则证明有环存在,然后将两指针相遇点记为meet,再继续走,此时头节点也开始移动,meet与head相遇点就是环的最初节点。
证明过程如下:
struct ListNode {
int val;
struct ListNode *next;
};
typedef struct ListNode LN;
struct ListNode *detectCycle(struct ListNode *head) {
LN*slow,*fast,*meet;
slow=fast=head;
while(fast && fast->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
meet=slow;
while(meet!=head){
meet=meet->next;
head=head->next;
}
return meet;
}
}
return NULL;
}
这种方法不容易想到,还有另外一种方法,将快慢指针相遇点newhead=meet->next,meet->next=NULL,此时从newhead开始,与原链表head通过相交链表的思路求解。
struct ListNode {
int val;
struct ListNode *next;
};
typedef struct ListNode LN;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
LN*cur1=headA,*cur2=headB;
int lenA=1,lenB=1;
while(cur1){
cur1=cur1->next;
lenA++;
}
while(cur2){
cur2=cur2->next;
lenB++;
}
//尾节点不相同就没有相交
if(cur1!=cur2){
return NULL;
}
//假设法
int gap=abs(lenA-lenB);
LN* longlist = headA;
LN* shortlist = headB;
if(lenA<lenB){
longlist=headB;
shortlist=headA;
}
while(gap--){
longlist=longlist->next;
}
while(longlist!=shortlist){
longlist=longlist->next;
shortlist=shortlist->next;
}
return longlist;
}
struct ListNode *detectCycle(struct ListNode *head) {
LN*slow,*fast,*meet;
slow=fast=head;
while(fast && fast->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
meet=slow;
LN* newhead=meet->next;
meet->next=NULL;
return getIntersectionNode(head,newhead);
}
}
return NULL;
}
本节内容到此结束,感谢各位友友对小编的支持!!!
觉得本文章有用的话留下三连和评论吧!!!
咱们下期再见!!!