面试题23:链表中环的入口节点

本文介绍了一种高效算法,用于在链表中检测是否存在环,并精确找出环的入口节点。通过使用快慢指针策略,首先判断链表是否包含环,接着计算环内节点数量,最后利用双指针法精确定位环的入口节点。
题目:如果一个链表中包含环,如何找出环的入口节点?例如,在如图3.8所示的链表中,环的入口节点3.

標題

解题思路:

一 . 解决这个问题的第一步是如何确定一个链表中包含环。 

定义一快和一慢两个指针,开始时慢指针指向第一个节点,快指针指向第二个节点;然后慢指针一次走一步,快指针一次走两步。如果走的快的指针追上了走的慢的指针,那么链表就包含环。如果走的快的指针走到了链表的末尾都没有追上第一个指针,那么链表就不包含环。

二 . 第二步是判断环中有几个节点。

两个指针相遇的节点肯定是在环中。可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时,就可以得到环中节点数了。

三  . 第三步就是如何找到环的入口。(本题环中有四个节点)

我们还是用两个指针来解决这个问题。先定义两个指针P1(快指针)和P2(慢指针)指向链表的头节点。如果链表中的环有n个节点,则指针P1先在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第一个指针指向环的入口节点时,第一个指针已经围绕着环走了一圈,又回到了入口节点。

標題

package leetcode;

class ListNode {
	int val;
	ListNode next;

	ListNode(int x) {
		val = x;
		next = null;
	}
}
public class Class_EntryNodeOfLoop {
	public static ListNode createList() {
		ListNode[] list = new ListNode[5];
		for (int i = 0; i < 5; i++) {
			list[i] = new ListNode(i + 1);
		}
		for (int i = 0; i < 4; i++) {
			list[i].next = list[i + 1];
		}
		list[4].next = list[2];
		return list[0];
	}
	public static ListNode isCycle(ListNode pHead) {
		if (pHead == null) {
			return null;
		}
		ListNode pSlow = pHead;
		ListNode pFast = pHead.next;
		while (pSlow != null && pFast != null) {
			if (pSlow == pFast) {
				return pSlow;
			}
			pSlow = pSlow.next;
			pFast = pFast.next;
			if (pFast != null) {
				pFast = pFast.next;
			}

		}
		return null;
	}
	public static ListNode detectCycle(ListNode pHead) {
		ListNode meetListNode = isCycle(pHead);
		if (meetListNode == null) {
			return null;
		}
		// 确定环中有几个节点
		int num = 1;
		ListNode p = meetListNode;
		while (p.next != meetListNode) {
			p = p.next;
			num++;
		}
		/*
		 * 用一快一慢两个指针 找到环的入口节点 快指针先走num步,之后快慢指针每次都走一步,快慢指针相遇时 即为入口节点
		 */
		ListNode pSlow = pHead;
		ListNode pFast = pHead;
		while (num > 0) {
			pFast = pFast.next;
			num--;
		}
		while (pSlow != pFast) {
			pSlow = pSlow.next;
			pFast = pFast.next;
		}
		return pSlow;
	}
	public static void main(String[] args) {
		ListNode pHead = createList();
		ListNode res = detectCycle(pHead);
		System.out.println(res.val);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值