剑指offer - 链表中环的入口节点

题目描述
输入一个包含环的链表,如何找到环的入口节点?
思路:
1, 先确定链表中是否包含环(用快慢指针的方法)
一个指针 slow每次走一步,另一个指针 fast每次走两步。
如果fast指针追上了slow指针,也就是两个指针指向了同一个节点,则说明链表包含环。
2, 找到环的入口
2.1 先得到环的大小,通过第一步已经找到了环,只要让一个指针在原地,另一个指针绕一圈来和它重逢,则绕圈圈的大小k就是环的大小。
2.2 之后,让一个指针指向链表开头,第二个指针指向链表的第k个节点。两个指针同时向后移动,当他们重逢时,相遇的那个节点就是环的入口节点。

以上思路的代码

	// 找到环的入口
	public static ListNode EntryNodeOfLoop(ListNode head){
		ListNode hasLOOP = FindLoop(head);
		if(hasLOOP == null){
			return null;
		}
		// 找出环的大小
		ListNode node1 = hasLOOP;
		ListNode node2 = hasLOOP.next;
		System.out.println("环:"+hasLOOP);
		int loopCount = 1;
		while(node1 != node2){
			node2 = node2.next;
			loopCount ++;
		}
		System.out.println("环大小:"+loopCount);
		// 一个指针指向第k个
		node2 = head;
		for(int i=0;i<loopCount;i++){
			node2 = node2.next;
		}
		node1 = head;
		while(node2 != node1){
			node1 = node1.next;
			node2 = node2.next;
		}
		return node1;
	}
	
	// 判断是否有环
	public static ListNode FindLoop(ListNode head){
		ListNode fastNode = null;
		ListNode slowNode = null;
		if(head == null){
			return null;
		}
		slowNode = head;
		fastNode = head.next;
		while(slowNode!=null && fastNode!=null){
			if(fastNode == slowNode){
				return fastNode;
			}
			slowNode = slowNode.next;
			fastNode = fastNode.next;
			if(fastNode != null){
				fastNode = fastNode.next;
			}
		}
		return null;
	}

一个简洁版,参考leetcode对代码进行了一些优化

public class Solution {
  public ListNode detectCycle(ListNode head) {
        if(head==null || head.next==null) return null;
        ListNode fist = head;
        ListNode second = head.next;
        boolean isLoop = false;
        while(second!=null && fist!= null){
            if(fist == second){
                isLoop = true;break;
            }
            else{
                if(second.next==null) break;
                fist=fist.next;
                second=second.next.next;
            }
        }
        if(isLoop){
            second = head;
            fist = fist.next;
            while(fist != second){
                second = second.next;fist = fist.next;
            }
             return second;
        }
        return null;
    }
}

链表结构

public class ListNode {
	   public int val;
       public ListNode node = null;
       public ListNode next = null;
       public ListNode(int val) {
            this.val = val;
       }
       int n= 0;
       public String toString(){
        	ListNode re = this;
        	String s = "";
            while(re != null){
            	n++;
            	s += re.val+" -> ";
            	re = re.next;
            	if(n==5){
            		break;
            	}
            }
        	return s;
        }
    }

测试结果:
在这里插入图片描述

备注:感觉这篇博客总结得不错,加个链接吧查看

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值