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

问题:一个链表中包含环,请找出该链表的环的入口结点?

从两个大的角度思考这个问题

1.记录遇到的每一个链表元素

在一次遍历过程中的,使用一种数据结构(数组、Hash表、基数树)记录遇到的每一个链表元素并判断是否已经遇到过,其中使用基数树可以获得O(n)O(n)的时间复杂度,但是可会有比较高的空间复杂度。

2.利用链表的性质

想法一:时间复杂度为O(n),两个指针,一个在前面,另一个紧邻着这个指针,在后面。两个指针同时向前移动,每移动一次,前面的指针的next指向NULL。也就是说:访问过的节点都断开,最后到达的那个节点一定是尾节点的下一个,也就是循环的第一个。这时候已经是第二次访问循环的第一节点了,第一次访问的时候我们已经让它指向了NULL,所以到这结束。这样做的话过题目是可以了,但是会破坏掉原来的链表,所以并不是一个特别完美的解决办法。如果可以在链表元素中加入一个记录“逻辑断开”的元素,也就是说在遍历的过程中,不真正的断开元素之间的连接,而是使用一个记录值,记录下“逻辑上的断开”

想法二:

给定一个链表,只给出头指针hh 
1.如何判断是否存在环?

使用追赶的方法,设定两个指针slowfastslow、fast,均从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fastfast遇到NULLNULL退出。其中主要的思想就是“环形相遇追及问题”,理解上应该不复杂。

2.如何知道环的长度?

记录下问题1的相遇点,slowfastslow、fast从该点开始,再次相遇时slowslow所经过的节点数就是环的长度。从环上的任意一点开始,slowfastslow、fast再次相遇时slowslow经过的节点数就是环的长度,因为此时slowfastslow、fast起始距离为环长,速度差为11。选择问题1的相遇点为起始点是为了确保起始点为环上的一点。

3.如何找出环的连接点在哪里?

设问题1中的相遇点为m1,赋值p=m1,q=h,其中h为链表头结点,然后p,q每次1步向前运动,p,q再次相遇所在的位置就是环的入口节点(环的连接点)。

Java的实现

想法一:

public ListNode EntryNodeOfLoop(ListNode pHead)
{
	if(pHead.next == null)
	{
		return null;
	}
	ListNode front = pHead;
	ListNode fallow = pHead;
	while(front.next != null)
	{
		front = front.next;
		fallow.next = null;
		fallow = front;
	}
    return front;
}

想法二:

public ListNode EntryNodeOfLoop(ListNode pHead)
{
	ListNode fast = pHead;
	ListNode slow = pHead;
	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;
	fast = pHead;
	while(fast!=slow)
	{
		fast = fast.next;
		slow = slow.next;
	}
	return fast;
}

文字内容转载自: http://blog.csdn.net/u011373710/article/details/54024366


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值