剑指Offer 面试题23:链表中环的入口节点 Java代码实现

原创 2017年11月29日 22:07:16

题目描述

一个链表中包含环,请找出该链表的环的入口结点。

  这题又用到了一快一慢两个指针的方法,快指针一次走两步慢指针一次走一步。可以证明,若存在环路,则这两个指针一定会在环路中某个地方相遇。这也是检测一个链表是否存在环路的方式。

  接下来具体分析一下这两个指针什么时候会相遇。假设从第一个数据节点到环的入口节点需要走k步,那么当慢指针slow走到环的入口节点时,快指针fast已经走了2k步,其中在环内走了k步。k可能会比环路的节点数大会很多,快指针应该距离环的入口节点mod(k,LOOP_SIZE)步,记为K。
也就是说:当slow走到入口节点时,fast在环内走了K步。slow落后于fast,相距K。或者说fast落后slow,相距(LOOP_SIZE-K)步。
每走一次,fast都会靠近slow步。于是两者将在(LOOP_SIZE-K)步之后相遇,这个相遇点就距离环入口 K 步。

  下面说一下怎么找到环路起始处。上面说了,在相遇点,还需走K步到环的入口节点 。
因为K=mod(k,LOOP_SIZE), k=K+M*LOOP_SIZE,所以也可以说从碰撞处,需要走k步到达环的入口节点(就是在环里面多绕几圈)。也就是说,链表第一个数据节点和碰撞节点都需要走k步到达环的入口节点。碰撞后,我们把一个指针指向链表第一个节点,一个指针指向碰撞处,以同样的速度移动,他们会在环的入口处相遇。
实现的Java代码如下(这儿的链表包含一个没有数据域的头结点):
public static ListNode entryNodeOfLoop2(ListNode head){
		if(head==null||head.next==null)
			return null;
		
		ListNode slow=head.next,fast=head.next;
		
		//找到碰撞处 ,处于链表中LOOPSIZE-k步
		while(fast!=null&&fast.next!=null){
			slow=slow.next;
			fast=fast.next.next;
			if(fast==slow)
				break;
		}
		//错误检查 没有环路
		if(fast==null||fast.next==null){
			return null;
		}
		//发生碰撞后,再将slow指向链表第一个数据点,fast流在碰撞处
		//同速度走,相碰的地方就是 环路起始处
		slow=head.next;
		while(slow!=fast){
			slow=slow.next;
			fast=fast.next;
		}
		return fast;
	}
剑指Offer上的实现,有些许不同。上面的的分析比较全面,分析后代码也更简洁。Offer中的方法更好理解,但是代码量稍多一点。各有优点,大家自己斟酌。Offer中的实现思路如下:

1.通过一快一慢两个指针找到碰撞处

2.遍历环,得到环中的节点数N

3.两个指针都初始指向第一个节点,然后第一个指针先走N步(两个指针相距就是环内节点数),然后一起走,第一次相遇的点就是环的入口。
public static ListNode meetingNode(ListNode head){
		if(head==null||head.next==null)
			return null;
		
		ListNode slow=head.next,fast=head.next;
		
		while(fast!=null&&fast.next!=null){
			slow=slow.next;
			fast=fast.next.next;
			if(fast==slow)
				return fast;
		}
		return null;
	}
	
	public static ListNode entryNodeOfLoop(ListNode head){
		ListNode meetingNode=meetingNode(head);
		if(meetingNode==null) return null;
		
		//求环节点数目
		int loopCount=1;
		ListNode pNode=meetingNode;
		while(pNode.next!=meetingNode){
			pNode=pNode.next;
			loopCount++;
		}
		//从第一个数据节点开始移动loopCount次
		pNode=head.next;
		for(int i=0;i<loopCount;i++){
			pNode=pNode.next;
		}
		//同时移动
		ListNode pNode2=head.next;
		while(pNode!=pNode2){
			pNode=pNode.next;
			pNode2=pNode2.next;
		}
		
		return pNode;
	}


版权声明:本文为博主原创文章,未经博主允许不得转载。

剑指Offer 面试题24:反转链表 Java代码实现

题目:定义一函数,输入链表的头结点,反转该链表并输出反转后的链表头结点。 因为在反转一个节点时,需要把该节点的指针域指向其前一节点,这样就无法访问其后续节点。所以,需要有三个指针分别指向当前节点...

剑指Offer 面试题22:链表中倒数第k个节点 Java代码实现

题目 输入一个链表,输出该链表中倒数第k个结点。 这个问题可以用两个链表指针来实现,这个方法在单向链表的问题中经常使用。具体而言,就是一快一慢两个指针,快指针先走(k-1)步,然后两个指针同时走,当...

剑指offer--面试题23:链表中环的入口节点

#include #include #define nullptr NULL struct ListNode { int m_nValue; ListNode...

剑指Offer 面试题18:删除链表节点 Java代码实现

题目:在O(1)时间内删除链表节点。 给定单向链表头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。 这儿采用有头结点的单链表结构,头结点的存在是为了方便操作,针对单链表来说,如果带头...

【剑指offer】面试题23:链表中环的入口节点

题目一个链表中包含环,请找出该链表的环的入口节点。思路 先判断链表中是否包含环 (node1,node2指向头结点,node1每次向前移动1步,node2每次向前移动2步,若出现node1==nod...

剑指Offer 面试题15:二进制中1的个数 Java代码实现

剑指Offer 面试题15:二进制中1的个数 题目:实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如,9的二进制是1001,有两位是1,那么输入9,函数输出2。 看完题目我就想到了J...

剑指offer面试题11 数值的整数次方的Java代码实现

数值的整数次方的Java代码实现 剑指offer这本书不错。以下是我对这道题的Java代码实现 /** * 剑指offer中面试题11:数值的整数次方double power(double b...

剑指Offer 面试题17:打印从1到最大的n位数 Java代码实现

题目:输入数字n,按顺序打印从1到最大的n位的十进制数。比如,输入3,则打印出1、2、3一直到999。 这个题目好像很简单,求出最大的n位数,然后for循环打印就好了。但是Java中int类型的范...

剑指Offer 面试题19:正则表达式匹配 Java代码实现

题目:正则表达式匹配 请实现一个函数用来匹配包含'.'和'*'的正则表达式。字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次) 主要思想就是字符的第...

剑指offer----链表中环的入口节点----java实现

http://blog.csdn.net/snow_7/article/details/52181049 一个链表中包含环,请找出该链表的环的入口结点。 此问题包含两个步骤: (1)判断...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:剑指Offer 面试题23:链表中环的入口节点 Java代码实现
举报原因:
原因补充:

(最多只允许输入30个字)