力扣:环形链表Ⅱ(快慢双指针思路+代码实现+剖析难点+数学推导)

题目

在这里插入图片描述在这里插入图片描述

①本题思路

快慢双指针工作方式:

slow和fast从同一起点出发。(注意:同一起点就是链表头结点出发!)

fast每次右移两个单位长度
slow每次右移一个单位长度

1.判断是否有环

成环:slow和fast相遇
不成环:fast最终指向NULL

2.寻找入环点(难)

难点是由于需要进行一些数学推导,找出等量关系。

简略的数学推导一下:

Ⅰ:展示原始环形链表

在这里插入图片描述

Ⅱ:两点把环形链表分成了三个区域设出x,y,z

在这里插入图片描述

Ⅲ:明确推导目标

在这里插入图片描述

Ⅳ:列出等量关系(三条),并整合得出x的等式

①:2slow = fast。

(fast、slow在此都表示走过的长度) 

②:X + n(y+z) + y= fast。

描述fast走过的距离为:x + n(y+z) + y
 n表示转的圈数,取值范围 [1,INF),
 理解圈数:x很大很长,环形很小(y+z值很小),相遇之前fast必然在圈内循环!(即slow指针到达x前)
 而必须是循环一圈,才能够使得fast和slow相遇,所以n取值范围最小值是1

③:slow = x+y

描述slow指针走过的举例为x+y

最终整合三个等式得到:x = (n-1)(y+z)+z

整合方式:②③式代入①式

Ⅴ:最终表达式(找到入口点x)

x = (n-1)(y+z)+z

这条表达式如同:

有两个指针分别从:O点,B点以相同的速度出发,最终将在A相遇。
(z可能比x长,当出现这种情况就会在环形内循环,直到总路程一样总能在x处相遇)
在这里插入图片描述

②代码实现

其实结论很简单,知道结论做题犹如知道答案考试,几下就能写完代码的,时间主要都是花在公式推导,以及初次接触很难想到!

第一种代码:(因为经常使用while,所以给了while版本)

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
    	if(head==NULL||head->next==NULL)return NULL;
    	
        ListNode *fast = head;
        ListNode *slow = head;
        
        //可以变成dowhile语句———— (第二种版本)
        if(fast==NULL||fast->next==NULL)return NULL;
        fast=fast->next->next;
        
		slow=slow->next;
		//可以变成dowhile语句———— (第二种版本)
        
        
        while(fast!=slow){//因为一开始fast和slow指向同一个位置,所以上面要先移动一次//适合do...while语句其实! 
        	if(fast==NULL||fast->next==NULL)return NULL;//不成环(fast是右移两次,所以判空方式不同)
			
			fast=fast->next->next;//
			slow=slow->next;
		}
        
        //代码到这里,slow和fast就相遇了!
		
		//接下来就是根据表达式,两个变量从相遇点出发,相遇的时候就是出口点
		ListNode *first = head;
		ListNode *second = fast;//使用slow复制也行,因为一样! 
		
		while(first!=second){
			first=first->next;
			second=second->next;
		}
		
        return first;//返回second也行 
        
    }
    
};

第二种版本:do…while语句

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
    	if(head==NULL||head->next==NULL)return NULL;
    	
        ListNode *fast = head;
        ListNode *slow = head;
        
        do{//因为一开始fast和slow指向同一个位置,所以上面要先移动一次//适合do...while语句其实! 
        	if(fast==NULL||fast->next==NULL)return NULL;//不成环(fast是右移两次,所以判空方式不同)
			
			fast=fast->next->next;//
			slow=slow->next;
		}while(fast!=slow);
        
        //代码到这里,slow和fast就相遇了!
		
		//接下来就是根据表达式,两个变量从相遇点出发,相遇的时候就是出口点
		ListNode *first = head;
		ListNode *second = fast;//使用slow复制也行,因为一样! 
		
		while(first!=second){
			first=first->next;
			second=second->next;
		}
		
        return first;//返回second也行 
        
    }
    
};
  • 44
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值