LeetCode142.环形链表II【双指针,链表判环,找入环点的两方法】

LeetCode142.环形链表II

1.题目

题目描述

2.思路

两个步骤:
1.判定是否有环——快慢指针法
在这里插入图片描述要注意的是:一定会相遇,因为进环后相当于fast指针每次前移一个追逐slow指针

2.寻找环的入口
a.从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
下面是数学证明:
在这里插入图片描述

n如果大于1的情况,就是fast指针在环形转n圈之后才遇到 slow指针。其实和n为1的时候 效果是一样的,一样可以通过这个方法找到环形的入口节点,只不过,index1 指针在环里 多转了(n-1)圈,然后再遇到index2,相遇点依然是环形的入口节点。

b.断开链表,结合链表相交的问题找起始在这里插入图片描述

3.代码实现

(1)判定是否有环
//1.设置指向表头的快慢指针
		ListNode* fast = head;
		ListNode* slow = head;
//2.fast每次走两步 slow每次走一步
		//下面这样写是不行的!如果fast->next是空,不能访问fast->next->next!
		//while(fast->next != NULL && fast->next->next != NULL)
		while(fast!=NULL && fast->next !=NULL)
		 {
		 	fast = fast->next->next;
			slow = slow->next;
			if(fast == slow) break;//相等就跳出
		 }
//3.用于判定跳出的条件是fast == slow还是fast指空
		 if(fast==NULL || fast->next == NULL)
		 	return NULL;

注意事项

1.下面这样写是不行的!如果fast->next是空,不能访问fast->next->next!
while(fast->next != NULL && fast->next->next != NULL)
2.循环条件不能是while(fast != slow),这样的话无法判别无环条件!

(2)寻找环的入口
a.数学方法 再设两个指针
		 ListNode* p1 = fast;//从相遇节点出发一个指针
		 ListNode* p2 = head;//从头结点出发一个指针
		 while(p1 != p2)
		 {
		 	p1 = p1->next;
		 	p2 = p2->next;
		 }
		 return p1;//相遇节点即为链表入口
b.断开链表,结合链表相交
		//ListNode *x;x->next = fast;x->next = NULL 这样写不对!
		ListNode* p = fast;
		while(p->next != fast)
		p = p->next;
		p->next = NULL;
		
		//变成两个链表,一个以head开头 一个以相遇点fast开头
		ListNode* m = head; ListNode* n = fast;
		//统计两链表的长度
        int len1 = 0;int len2 = 0;
		while(m!= NULL) {m = m->next;len1 ++;}
		while(n != NULL){n = n->next;len2++;}
		
		if(len1 > len2){
			int n = len1 - len2;//求链表差
			while(n--){//长链表的指针先向后走,和短链表的指针对齐
				head = head->next;
			}
			while( head != fast)//同步往后走,直到遇到相等结点为止。
			{
				head = head->next;
				fast = fast->next;
			}
			return head;
		}
		else{
			int n = len2 - len1;
			while(n--){fast = fast->next;
			}
			while( head != fast)
			{
				head = head->next;
				fast = fast->next;
			}
			return head;
		}

注意事项

ListNode *x;x->next = fast;x->next = NULL,千万不能这么写!单链表没办法访问他前面的结点!

完整代码

方法一:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
		ListNode* slow = head;
        while(fast!=NULL && fast->next !=NULL)
		 {
		 	fast = fast->next->next;//一次两步 
			slow = slow->next;		//一次一步
			if(fast == slow) break;
		 }
		 if(fast==NULL || fast->next == NULL)
		 	return NULL;
		 	ListNode* p1 = fast;//从相遇节点出发一个指针
		 ListNode* p2 = head;//从头结点出发一个指针
		 while(p1 != p2)
		 {
		 	p1 = p1->next;
		 	p2 = p2->next;
		 }
		 return p1;//相遇节点即为链表入口
}
};

方法二:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
		ListNode* slow = head;
        while(fast!=NULL && fast->next !=NULL)
		 {
		 	fast = fast->next->next;//一次两步 
			slow = slow->next;		//一次一步
			if(fast == slow) break;
		 }
		 if(fast==NULL || fast->next == NULL)
		 	return NULL;
		
		ListNode* p = fast;//ListNode *x;x->next = fast? 
		while(p->next != fast)
		p = p->next;
		p->next = NULL;
		
		//变成两个链表,一个以head开头 一个以相遇点fast开头
		ListNode* m = head; ListNode* n = fast;
		while(m!= NULL) {m = m->next;len1 ++;}
		while(n != NULL){n = n->next;len2++;}
		
		if(len1 > len2){
			int n = len1 - len2;
			while(n--){
				head = head->next;
			}
			while( head != fast)
			{
				head = head->next;
				fast = fast->next;
			}
			return head;
		}
		else{
			int n = len2 - len1;
			while(n--){fast = fast->next;
			}
			while( head != fast)
			{
				head = head->next;
				fast = fast->next;
			}
			return head;
		} 
		
    }
};

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值