求链表中环的入口节点
问题描述:一个链表中包含环,如何找到环的入口节点?
解法一:遍历链表中的节点,将节点放入Set集合中,利用Set集合不允许插入重复数据的特性,可以找到第一个重复的节点,即为环的入口 节点。
解法二:定义连个指针p1和p2,p1和p2都指向链表的头结点,p1移动环的个数个节点,然后p1和p2以相同的速度移动,直到p1和p2相遇,相 遇的节点即为环的入口节点。
package com.wyl.linklist; import java.util.HashSet; import java.util.LinkedList; import java.util.Set; /** * 求链表中环的入口节点 * @author wyl * */ public class CircleStartNode { /** * 定义链表中节点的结构 * @author wyl */ static class Node<T>{ private T data ; //节点的值 private Node<T> next; public Node(T data){ this(data, null); } public Node(T data, Node<T> next) { this.data = data; this.next = next; } public T getData() { return data; } public void setData(T data) { this.data = data; } public Node<T> getNext() { return next; } public void setNext(Node<T> next) { this.next = next; } //节点的后继节点 } public static void main(String[] args) { Node<Integer> n6 = new Node(6); Node<Integer> n5 = new Node(5, n6); Node<Integer> n4 = new Node(4, n5); Node<Integer> n3 = new Node(3, n4); Node<Integer> n2 = new Node(2, n3); Node<Integer> n1 = new Node(1, n2); n6.setNext(n3);
//Node n = circleStartNode(n1); Node n = circleStartNode2(n1); System.out.println(n.getData()); } /** * 查找环的入口节点 * 解法一:使用Set集合 * @param n1 * @return */ public static Node circleStartNode(Node<Integer> n1) { // TODO Auto-generated method stub if(n1 == null){ return null; } Set<Node> set = new HashSet<Node>(); while(n1 != null && set.add(n1)){ //利用set集合不能存储重复数据的特性 n1 = n1.getNext(); } return n1; } /** * 解法二:使用两个指针解决 * 1、首先得到环中节点的个数 * 2、利用两个指针进行查找 * @param n1 * @return */ public static Node circleStartNode2(Node<Integer> n1) { int size = circleSize(n1); //得到环的节点个数 Node p1 = n1; Node p2 = n1; while(size > 0){ p1 = p1.next; size--; } while(p1 != null && p2 != null){ if(p1 == p2){ return p1; } p1 = p1.next; p2 = p2.next; } return null; } /** * 找到链表相遇的节点 * @param n * @return */ public static Node meetingNode(Node n){ if(n == null){ return null; } Node p1 = n; //慢指针,每次移动一个 Node p2 = n; //快指针,每次移动两个 while(true){ p1 = p1.next; p2 = p2.next.next; if(p1 == p2){ //相遇的节点 return p1; } } } public static int circleSize(Node<Integer> n1) { int size = 0; if(n1 == null){ return -1; } //利用快慢指针得到第一次相遇的节点,此节点必然在环中,然后遍历进行计数 Node p = meetingNode(n1); Node p1 = p.next; while(p1 != null){ if(p1 != p){ size++; p1 = p1.next; }else{ size++; break; } } return size; } }