剑指offer -- 链表中环的入口结点(双指针详解)

题目:
如果一个链表中包含环,如何找出环的入口结点?
在这里插入图片描述

如此图中所示链表,环的入口结点为结点3。

分析:
1)
要找到环的入口结点,我们首先要确定这个链表中是否包含环?我们可以用两个指针从头开始走,一个指针走得快,一个指针走得慢,如果走的快的指针追上了走的慢的指针,那就证明这个链表存在环。

2)
判断了链表中包含环,我们仍然可以用双指针来找到入口,假如环中一共包含n个结点,那么从环入口开始走一圈再次到达环入口一共需要n步,从头开始到达环入口假如为x步,我们令第一个指针从头开始先走n步,那么这个指针就剩x步到达环入口,这时候让第二个指针从头开始走,第一个指针继续向下走,当二者相遇时的结点就为环的入口结点。这种方法就需要我们知道环中一共包含多少个结点,我们在1)中判断了链表是否包含环,两个指针相遇结点一定在环中,可以从相遇的结点出发,一边移动一边计数,当再次回到这个结点的时候,就可以得到环中结点数目。

综上解决这个问题分为3个步骤:
先判断是否存在环(找到环中相遇的结点)->计算出环中结点数目->找到环的入口结点

ListNode *MeetingNode(ListNode*head){
	 if(head == NULL)
		 return NULL;

	 ListNode *pSlow = head->next;
	 if(pSlow == NULL)   //一个结点 不能成环
		 return NULL;
	 ListNode *pFast = pSlow->next;

	 while(pFast != NULL && pSlow != NULL){ //只判断pFast也可以
		 if(pFast == pSlow)
			 return pFast;

		 pFast = pFast->next;
		 pSlow = pSlow->next;

		 if(pFast != NULL)
			 pFast = pFast->next;
	 }

	 return NULL;
 }

 ListNode *detectCycle(ListNode *head){
	 ListNode *meetingNode = MeetingNode(head);

	 if(meetingNode == NULL) return NULL; //不存在环

	 //得到环中结点数目
	 int count = 1;
	 ListNode *p1 = meetingNode;

	 while(p1->next != meetingNode){
		 p1 = p1->next;
		 count++;
	 }

	 p1 = head;
	 for(int i=0;i<count;i++){
		 p1=p1->next;
	 }

	 ListNode *p2 = head;

	 while(p1 != p2){
		 p1 = p1->next;
		 p2 = p2->next;
	 }
	 return p2;
 }
	

除此之外,本题也有多处地方考察了代码的鲁棒性,我们在对链表进行移动的时候一定要时刻注意是否访问了NULL,会存在多处令程序崩溃的风险。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值