链表中环的入口节点--java

本文介绍了一种高效检测链表中是否存在环的方法,即快慢指针法,并详细解析了如何通过该方法进一步定位环的入口节点。通过数学推导,证明了在链表有环的情况下,快慢指针相遇后,从头节点出发的指针与从相遇点出发的指针将以相同的速度在环的入口节点相遇。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 判断是否有环的思路--快慢指针 


首先创建两个指针1和2(在java里就是两个对象引用),同时指向这个链表的头节点。然后开始一个大循环,在循环体中,让指针1每次向下移动一个节点,让指针2每次向下移动两个节点,然后比较两个指针指向的节点是否相同。如果相同,则判断出链表有环,如果不同,则继续下一次循环。

例如链表A->B->C->D->B->C->D,两个指针最初都指向节点A,进入第一轮循环,指针1移动到了节点B,指针2移动到了C。第二轮循环,指针1移动到了节点C,指针2移动到了节点B。第三轮循环,指针1移动到了节点D,指针2移动到了节点D,此时两指针指向同一节点,判断出链表有环。

此方法也可以用一个更生动的例子来形容:在一个环形跑道上,两个运动员在同一地点起跑,一个运动员速度快,一个运动员速度慢。当两人跑了一段时间,速度快的运动员必然会从速度慢的运动员身后再次追上并超过,原因很简单,因为跑道是环形的。
 

二 找出环的入口节点(环的连接点)的思路

这里先证明一个定理:碰撞点到连接点的距离=头指针到连接点的距离

假设单链表的总长度为L,头结点到环入口的距离为a,环入口到快慢指针相遇的结点距离为x,环的长度为r,慢指针总共走了s步,则快指针走了2s步。另外,快指针要追上慢指针的话快指针至少要在环里面转了一圈多(假设转了n圈加x的距离),得到以下关系:
    s = a + x
    2s = a + nr + x
    =>a + x = nr
    =>a = nr - x

由上式可知:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点。

代码如下:

 public ListNode EntryNodeOfLoop(ListNode pHead)
    {
		ListNode slow = pHead;
        ListNode fast = pHead;
        boolean isLoop = false;    //判断是否有环
        while (fast != null && fast.next != null) {
		 	slow = slow.next;
			fast = fast.next.next;
			if (slow == fast) {
				isLoop = true;
				break;
			}
		}
        
        if (isLoop) {
			slow = pHead;
			while (slow != fast) {
				slow = slow.next;
				fast = fast.next;
			}
			  return slow;
		}
        return null;
    }
  public ListNode EntryNodeOfLoop(ListNode pHead)
    {
     	if (pHead==null||pHead.next==null) {
			return null;
		}
     	ListNode slow = pHead;
     	ListNode fast = pHead;
     	while (fast!=null&&fast.next!=null) {
			slow = slow.next;
			fast = fast.next.next;
			if (slow==fast) {
				slow = pHead;
				while (slow!=fast) {
					slow = slow.next;
					fast = fast.next;
				}
				return slow;
			}
		}
     	return null;
    }
package 秋招刷题.剑指offer_链表;
/*https://www.nowcoder.com/discuss/198840?type=0&order=0&pos=65&page=2
使用双指针,一个指针 fast 每次移动两个节点,一个指针 slow 每次移动一个节点。
因为存在环,所以两个指针必定相遇在环中的某个节点上。假设相遇点在下图的 z1 位置,
此时 fast 移动的节点数为 x+2y+z,slow 为 x+y,由于 fast 速度比 slow 快一倍,
因此 x+2y+z=2(x+y),得到 x=z。

在相遇点,slow 要到环的入口点还需要移动 z 个节点,
如果让 fast 重新从头开始移动,并且速度变为每次移动一个节点
,那么它到环入口点还需要移动 x 个节点。在上面已经推导出 x=z,
因此 fast 和 slow 将在环入口点相遇。
        */
public class 链表中环的入口节点 {
    public static void main(String[] args) {

    }
    public static ListNode EntryNodeOfLoop(ListNode pHead)
    {     if (pHead == null || pHead.next == null)
                return null;
         ListNode fast = pHead, slow = pHead;
          do {
              fast = fast.next.next;
              slow = slow.next;
              }while (slow != fast);      //找到相遇点
                fast = pHead;
              while (fast != slow) {
                  slow = slow.next;
                  fast = fast.next;
              }
         return slow;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值