剑指offer-面试题56-链表中环的入口结点

链表节点结构定义:

package case56_EntryNodeOfLoop;

/**
 * 单链表的节点结构定义
 * 
 * @author WangSai
 *
 */
public class ListNode {

	int data;
	ListNode next;

	public ListNode() {
	}

	public ListNode(int data) {
		this.data = data;
	}

}


链表中环的入口结点代码实现:

package case56_EntryNodeOfLoop;

/**
 * 题目:一个链表中包含环,如何找出环的入口节点?例如在下图的链表中,环的入口节点是节点3。
 * 
 * N1 ——>N2 ——>N3 ——>N4 ——>N5 ——>N6 ——>N7 ——>N8 ——>N9 ——>N10 ——>N11 ——>N12
 * ............^—————————————<—————————————<—————————————<—————————————v
 * 
 * 思路:
 * 
 * 1,首先判断链表中是否有环。方法:定义两个指针,fast和slow指向head,fast走的快,slow走的慢。若有环则fast会追上slow,
 * 并且相遇的节点就是环中的节点。
 * 
 * 2,若有环,则从相遇的节点开始统计环中的节点数n
 * 
 * 3,再定义两个指针p1,p2从链表的头开始,p1先走n步,然后,p2和p1一起向前走,当第一次相遇时,便是环形链表的入口节点。
 * 
 * @author WangSai
 *
 */
public class EntryNodeOfLoop {

	/**
	 * 判断链表中是否存在环?定义两个指针一个走的 快fast,一个走的慢slow,如果快的fast和慢的slow相遇了,说明存在环,并且返回相遇的点。
	 * 若不存在则返回null。
	 * 
	 * @param head,链表的头结点
	 * @return 环中相遇的节点,若不存在环则返回null
	 */
	private static ListNode meetingNode(ListNode head) {
		// 异常检测
		if (head == null)
			return null;
		// 定义两个指针,一个走的快,一个走的慢
		ListNode fast = head;
		ListNode slow = head;
		while (fast != null) {
			fast = fast.next;
			if (fast == null)
				return null;
			fast = fast.next;

			slow = slow.next;
			if (fast == slow) {
				return slow;
			}
		}
		return null;
	}

	/**
	 * 找到相遇的点后,计算环中有多少个点
	 * 
	 * @param node,环中任意的一个节点
	 * @return 环中有多少个节点
	 */
	private static int numOfNodeInLoop(ListNode node) {
		if (node == null)
			return 0;
		int count = 1;
		ListNode temp = node;
		temp = temp.next;
		while (node != temp) {
			count++;
			temp = temp.next;
		}
		return count;
	}

	/**
	 * 寻找环的入口节点。定义两个指针p1,p2。p1先走n步,然后,p1 p2一起向前走,当他们相遇时,就是环形链表的入口。
	 * 
	 * @param head,链表的头结点
	 * @param num,链表中环形链表中的节点数量
	 * @return 链表的环形入口
	 */

	private static ListNode myEntryNode(ListNode head, int num) {
		// num为0,说明没有环
		if (num == 0)
			return null;
		// fast先走num步,然后,slow和fast一起向前走。当fast和slow相遇时,就是入口的点。
		ListNode fast = head;
		ListNode slow = head;
		while (num > 0) {
			fast = fast.next;
			num--;
		}
		while (fast != slow) {
			fast = fast.next;
			slow = slow.next;
		}
		return slow;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// 链表有环
		test1();
		// 单链表,没有环
		test2();
		// 空链表
		test3();
		// 环形链表,链表尾节点指向头结点
		test4();
	}

	/**
	 * 链表有环
	 */
	public static void test1() {
		// TODO Auto-generated method stub
		ListNode head = 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);
		ListNode n7 = new ListNode(7);
		ListNode n8 = new ListNode(8);
		ListNode n9 = new ListNode(9);
		head.next = n2;
		n2.next = n3;
		n3.next = n4;
		n4.next = n5;
		n5.next = n6;
		n6.next = n7;
		n7.next = n8;
		n8.next = n9;
		n9.next = n8;

		ListNode entryNode3 = myEntryNodeInLoop(head);
		System.out.println(entryNode3.data);
	}

	/*
	 * 单链表,没有环
	 */
	public static void test2() {
		// TODO Auto-generated method stub
		ListNode head = 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);
		ListNode n7 = new ListNode(7);
		ListNode n8 = new ListNode(8);
		ListNode n9 = new ListNode(9);
		head.next = n2;
		n2.next = n3;
		n3.next = n4;
		n4.next = n5;
		n5.next = n6;
		n6.next = n7;
		n7.next = n8;
		n8.next = n9;

		ListNode entryNode3 = myEntryNodeInLoop(head);
		System.out.println(entryNode3);
	}

	/*
	 * 空链表
	 */
	public static void test3() {

		ListNode entryNode1 = myEntryNodeInLoop(null);
		System.out.println(entryNode1);
	}

	/*
	 * 链表尾节点指向头节点
	 */
	public static void test4() {
		// TODO Auto-generated method stub
		ListNode head = 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);
		ListNode n7 = new ListNode(7);
		ListNode n8 = new ListNode(8);
		ListNode n9 = new ListNode(9);
		head.next = n2;
		n2.next = n3;
		n3.next = n4;
		n4.next = n5;
		n5.next = n6;
		n6.next = n7;
		n7.next = n8;
		n8.next = n9;
		n9.next = head;

		ListNode entryNode3 = myEntryNodeInLoop(head);
		System.out.println(entryNode3.data);
	}

	private static ListNode myEntryNodeInLoop(ListNode head) {
		// 是否有环,若有环则返回环中的任意结点;若没有则返回null
		ListNode nodeInloop = meetingNode(head);
		// 统计环中有多少个节点
		int numInLoop = numOfNodeInLoop(nodeInloop);
		System.out.println("环中有多少个节点:" + numInLoop);
		// 返回环的入口节点
		ListNode entryNode = myEntryNode(head, numInLoop);
		return entryNode;
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值