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

42 篇文章 0 订阅
34 篇文章 0 订阅
题目:链表中环的入口节点
        一个链表中包含环,如何找出环的入口节点?例如,下图中的入口节点是3.
                1->2->3->4->5->6
                               ^                   |
                                |                   |
                            —————                                
算法分析:
          可以用两个指针来解决这个问题。先定义两个指针P1和P2指向链表的头结点。如果链表中环有n个结点,指针P1在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向环的入口结点时,第一个指针已经围绕着环走了一圈又回到了入口结点。
  剩下的问题就是如何得到环中结点的数目。我们在面试题15的第二个相关题目时用到了一快一慢的两个指针。如果两个指针相遇,表明链表中存在环。两个指针相遇的结点一定是在环中。可以从这个结点出发,一边继续向前移动一边计数,当再次回到这个结点时就可以得到环中结点数了。

算法实现源程序:
/**************************************************************      
* Copyright (c) 2016, 
* All rights reserved.                   
* 版 本 号:v1.0                   
* 题目描述:链表中环的入口节点
*   	        一个链表中包含环,如何找出环的入口节点?例如,下图中的入口节点是3.
*   		1->2->3->4->5->6
*   			  ^  	   |
*   			  | 	   |
*   			  ----------	   
*   
* 输入描述:无
* 程序输出:环中节点数是: 4
*			链表中环的入口节点是:3
* 问题分析: 无
* 算法描述:可以用两个指针来解决这个问题。先定义两个指针P1和P2指向链表的头结点。如果链表中环有n个结点,
* 			指针P1在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向环的入口结点时,
* 			第一个指针已经围绕着环走了一圈又回到了入口结点。
*		  剩下的问题就是如何得到环中结点的数目。我们在面试题15的第二个相关题目时用到了一快一慢的两个指针。
*			如果两个指针相遇,表明链表中存在环。两个指针相遇的结点一定是在环中。可以从这个结点出发,
*			一边继续向前移动一边计数,当再次回到这个结点时就可以得到环中结点数了。

* 完成日期:2016-10-13
***************************************************************/ 

package org.marsguo.offerproject56;
	/*
	定义一个节点
	*/
class ListNode{
	int val;
	ListNode next;
	public ListNode(){
		
	}
	public ListNode(int val){
		this.val = val;
	}
	public String toString(){
		return val + "";
	}
}

class SolutionMethod1{
	/*
	找到带环链表的入口节点函数
	@param head:头节点
	*/
	public ListNode EntryFunction(ListNode head){
		if(head == null){
			return null;
		}
		
		ListNode p1 = head;				//设置两个指针,使其期初都指向头节点
		ListNode p2 = head;				//设置两个指针,使其期初都指向头节点
		
		/*
		circleNode1和circleNode2都指向环中任意一个节点,通过while循环,
		计算出环中所包含的节点数
		circleNode1先固定指向环中一个节点不变,circleNode2依次向后移动,直到
		circleNode1和circleNode2再次相遇,此时circleNode2所走过的节点数即为环中包含的节点数
		*/
		ListNode circleNode1 = CircleNodeFunction(head);			
		ListNode circleNode2 = CircleNodeFunction(head).next;
		int count = 1;				//用于计算环中节点数,从1开始计数
		
		while(circleNode1 != circleNode2){
			count++;
			circleNode2 = circleNode2.next;
		}
		System.out.println("环中节点数是: " + count);				//输出环中的节点数
		/*
		使用 for循环让p2先走count步,然后再使p1和p2以相同的速度在链表上向前移动
		直到他们相遇,则相遇的节点即为环的入口节点
		*/
		for(int i = 0; i < count;i++){
			if(p2.next != null){
				p2 = p2.next;
			}
		}
		
		while(p1 != p2){
			p1 = p1.next;
			p2 = p2.next;
		}
		
		return p1;			//返回环的入口节点
	}
	/*
	判断环中节点数目,可用于判断链表中是否存在环
	设置两个指针,一个走的快,一个走的慢,如果两个指针能够相遇,则说明链表中存在环,
	并且相遇的节点即为环中的一个节点。
	*/
	public ListNode CircleNodeFunction(ListNode head){			//定义ListNode型函数
		if(head == null){
			return null;
		}
		ListNode pFast = head.next.next;
		ListNode pSlow = head.next;
		
		if(pSlow == null){
			return null;
		}
		
		while(pFast != null && pSlow != null){
			if(pFast == pSlow){
				return pFast;
			}
			pSlow = pSlow.next;
			pFast = pFast.next;
			
			if(pFast != null){
				pFast = pFast.next;		//使pFast走的速度比pSlow快,这样两个节点便会相遇
			}
		}
		return null;
	}
	
}

public class EntryNodeOfLoop {
	public static void main(String[] args){
		ListNode n1 = new ListNode(1);
		ListNode n2 = new ListNode(2);
		ListNode n3 = new ListNode(3);
		ListNode n4 = new ListNode(4);
		ListNode n5 = new ListNode(5);
		ListNode n6 = new ListNode(6);
		
		n1.next = n2;
		n2.next = n3;
		n3.next = n4;
		n4.next = n5;
		n5.next = n6;
		n6.next = n3;
		 
		SolutionMethod1 solution1 = new SolutionMethod1();
		System.out.println("链表中环的入口节点是:" + solution1.EntryFunction(n1));
		
		System.out.println();
	}
}

程序运行结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值