剑指offer50--链表中环的入口结点


一、题目


题目:一个链表中包含环,如何找出环的入口结点



二、举例



比如链表 1->2->3->4->5->6->3,那么链表中是存在环的,且环的入口是3


三、思想


其实该题目的编程并不难,难的是其数学的计算,首先看下面这张图:


1、总体思想:

一开始设置两个指针都指向表头,其中一个每次(一步)前进一个节点的叫p1,另外那个每次(一步)前进两个节点的

叫p2 。p1和p2同时走,当其中有一个遇到null,就证明链表没有环。如何某个时刻(假设走了n步之后),p1和p2指向的地址相

同,那么链表就是有环的。 在p1和p2重合后,设置一个p3指向表头,然后p1和p3每次同时行走一步,每步前进一个节点,等到p1

和p3重合时,重合的位置就 是环的入口。

2、☆计算公式☆:

(1)Head指的是初始化位置,L1是到链表环入口的长度,L2是整个环的长度,蓝色为重合P1和P2的重合点

(2)入口可重合点处的距离为a,如图所示,p1和p2同时走起,p2比p1块,所以p2在环内可能走了好几圈了

(3)当p1终于走到环里边的时候才能正好重合了

(4)推倒过程如下:

--------------------   L1+a=n                   #1   //n是p1走过的节点数

--------------------   L1+k*L2+a=2*n      #2   //2*n这个是p2走过的节点数,其中的k表示p2可能在环里面走了k圈,k>=1

--------------------   由#2式减去#1式,有:

--------------------   k*L2 = n                   #3

--------------------   同时由#1和#3得到:

--------------------   L1+a = k*L2             #4

--------------------   接着由#4就得到了如下式:

--------------------   L1 = k*L2 - a = (k-1)*L2 + (L-a)

(5)因为(L-a)表示的是交点与环入口的距离(从交点沿着行走方向到环入口),然后(k-1)是>=0的,因为p2在环中至少绕了一

圈,这样我们就发现:L1的长度 = 环长度的整数倍 + 交点与环入口的距离

也就是L1 = L2 - a,所以再让p1或者p2回来往前走L1步就正好重合了



四、程序



package 剑指offer;

public class Test56 {

	public static void main(String args[]){
		
	    // 1->2->3->4->5
	    //    ^        |
	    //    |        |
	    //    +--+-----+
        ListNodeEnter n1 = new ListNodeEnter(1);
        ListNodeEnter n2 = new ListNodeEnter(2);
        ListNodeEnter n3 = new ListNodeEnter(3);
        ListNodeEnter n4 = new ListNodeEnter(4);
        ListNodeEnter n5 = new ListNodeEnter(5);

        n1.next = n2;
        n2.next = n3;
        n3.next = n4;
        n4.next = n5;
        n5.next = n2;

        System.out.println(findEnterOfList(n1));
	}
	
	public static int findEnterOfList(ListNodeEnter head){
		//建立两个节点,p1和p2,p1的速度是p2的两倍
		ListNodeEnter p1 = head;
		ListNodeEnter p2 = head;
		while(p1 !=null && p2.next != null){
			p1 = p1.next.next;
			p2 = p2.next;
			if(p1 == p2){
				break;
			}
		}
		
		if(p1 == null || p2.next == null){
			return -1;
		}
		
		//p1重新回到起点
		p1 = head;
		while(p1 != p2){
			p1 = p1.next;
			p2 = p2.next;
		}
		
		return p1.value;
	}
	
}

class ListNodeEnter{
	int value;
	ListNodeEnter next;
	
	public ListNodeEnter(int value){
		this.value = value;
	}
	
	public String toString(){
		return value+"";
	}
}




--------------output--------------
2





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值