《剑指Offer》23:链表中环的入口节点

题目

若一个链表中包含环,如何找出的入口结点?如下图链表中,环的入口节点的节点3。

分析

  1. 一快(移两节点)一慢(移一节点)两指针判断链表是否存在环。
  2. 算出环有几个节点(上一步的两指针可知是在环中,让慢指针停止遍历,让快指针改为一节点一节点然后两指针一动一静的计算出环有多少个节点)。
  3. 重置两指针指向链头,一指针移动2. 步骤得出n,然后两指针一起移动。当两指针相遇,此时它们指向的环的入口结点

放码

import com.lun.util.SinglyLinkedList.ListNode;

public class FindEntryNodeOfLoop {

	public ListNode find(ListNode head) {
		
		//1.判断是否存在环
		ListNode meetNode = meetNode(head);
		
		if(meetNode == null) {
			return null;
		}
		
		int nodesInLoop = 1;
		
		ListNode node1 = meetNode;
		
		//2.计算环内节点
		while(node1.next != meetNode) {
			nodesInLoop++;
			node1 = node1.next;
		}
		
		//3.先移动node1, 次数为环中节点的数目
		node1 = head;
		for(int i = 0; i < nodesInLoop; i++)
			node1 = node1.next;
		
		ListNode node2 = head;
		while(node1 != node2) {
			node1 = node1.next;
			node2 = node2.next;
		}
		
		return node1;
	}

	
	public ListNode meetNode(ListNode head) {
		
		if(head == null)
			return null;
		
		ListNode slow = head.next;
		
		if(slow == null) {//链表只有一个节点
			return null;
		}
			
		ListNode fast = slow.next;
		
		while(fast != null && slow != null) {//可能循环几次才能碰上
		
			if(fast == slow) {
				return fast;
			}
			
			slow = slow.next;
			fast = fast.next;
			
			if(fast != null) {
				fast = fast.next;
			}
		}
		
		return null;
	}
	
}

测试

import static org.junit.Assert.*;

import org.junit.Test;

import com.lun.util.SinglyLinkedList;
import com.lun.util.SinglyLinkedList.ListNode;

public class FindEntryNodeOfLoopTest {

	@Test
	public void test() {	
		FindEntryNodeOfLoop fl = new FindEntryNodeOfLoop();
		
		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;//n3为入口节点
		
		assertEquals(3, fl.find(n1).val);
		
		//没有环的链表
		assertNull(fl.find(SinglyLinkedList.intArray2List(new int[] {1, 2, 3, 4, 5, 6})));
		
	}
	
	@Test
	public void test2() {
		FindEntryNodeOfLoop fl = new FindEntryNodeOfLoop();		
		assertNull(fl.meetNode(SinglyLinkedList.intArray2List(new int[] {1, 2, 3, 4, 5, 6})));
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值