首页 > 代码库 > 单链表的环相关问题

单链表的环相关问题

给定一个单链表,只给出头指针h:

1、 如何判断是否存在环?

证明:


 slow首次在A点进入环路时,fast一定在环中的B点某处。设此时slow距head长为x,B点距A点长度为y,环周长为s。因为fast和slow的步差为1,所以slow前行距离为y的时候,恰好会被fast在M点追上。因为y<s,所以slow尚未完成一次遍历。

//判断单链表是否有环
	public static boolean hasCycle(ListNode head) {
		if(head == null || head.next == null){
			return false;
		}
		ListNode slow = head;
		ListNode fast = head;
		while(fast.next != null && fast.next.next != null){
			fast = fast.next.next;
			slow = slow.next;
			if(fast == slow){
				return true;
			}
		}
		return false;
    }

2、 如何知道环的长度?

证明:(有公式所以截图了)


//返回环的长度
	public static int cycleLength(ListNode head) {
		if(head == null || head.next == null){
			return 0;
		}
		ListNode slow = head;
		ListNode fast = head;
		while(fast.next != null && fast.next.next != null){
			fast = fast.next.next;
			slow = slow.next;
			if(fast == slow){
				fast = fast.next.next;
				int length = 2;
				while(fast != slow){
					fast = fast.next.next;
					length = length + 2;
				}
				return length;
			}
		}
		return 0;
}

3、 如何找出环的连接点在哪里?

证明:在fast和slow第一次相遇的时候,假定slow走了n步骤,环路的入口是在x步的时候经过的,那么有

slow走的路径: x+y = n;   y为fast和slow相交点M距离环路入口的距离

fast走的路径: x+y+k*s = 2*n;   s为环路的周长,k是整数

所以得出 n = k*s;

显然,如果从x+y点开始,slow再走n步的话,还可以回到x+y这个点(绕了k圈)

同时另一个指针temp从头开始走的话,经过n步,也会达到x+y这点

两者都减去y步,可知两者走x步必然会在环路的入口点处相遇

//找出环的起始点在哪里
		public static ListNode getCycleStartNode(ListNode head) {
			if(head == null || head.next == null){
				return null;
			}
			ListNode slow = head;
			ListNode fast = head;
			while(fast.next != null && fast.next.next != null){
				fast = fast.next.next;
				slow = slow.next;
				if(fast == slow){
					fast = head;
					while(fast != slow){
						fast = fast.next;
						slow = slow.next;
					}
					return slow;
				}
			}
			return null;
	    }

4、带环链表的长度是多少?

证明:总长度 = s + x;

//带环链表总长度,0表示没环
		public static int getListLength(ListNode head) {
			if(head == null || head.next == null){
				return 0;
			}
			ListNode slow = head;
			ListNode fast = head;
			while(fast.next != null && fast.next.next != null){
				fast = fast.next.next;
				slow = slow.next;
				if(fast == slow){
					ListNode p = slow;//标记相遇的地方
					fast = head;
					int lengthX = 0;
					int lengthS = 0;
					while(fast != slow){
						fast = fast.next;
						slow = slow.next;
						lengthX++;
					}
					lengthS = lengthX;
					while(slow != p){
						slow = slow.next;
						lengthS++;
					}
					return lengthX+lengthS;
				}
			}
			return 0;
	    }