标签:
2.6Given a circular linked list, implement an algorithm which returns the node at the beginning of the loop.
快指针和慢指针一起在头指针开始移动,快指针每次移动两步,慢指针每次移动一步,直到相遇, 相遇后,把慢指针指向头指针,两个指针一起往后移动一步。直到相遇,相遇的地方就是循环的开始(如果相遇,说明是有循环的节点,这时快指针走的路程是慢指针的两倍,快:开始的k距离,和一圈(或者n圈)循环,和慢指针走过的循环圈的路部分长度这三部分相加。。。
看图:
慢指针走的距离是 开始没进循环的k距离慢指针走过的循环圈的路部分长度 这两部分相加),那么 快指针的长度是:K+慢在循环圈里的距离+ 满圈的长度*n圈; 慢指针的长度是:K+慢在循环圈里的距离,同时,因为快指针每次走两步,慢指针每次走一步,所以 快的长度等于慢长度的2倍:得到:(K+慢在循环圈里的距离+ 满圈的长度*n圈)=2*(K+慢在循环圈里的距离)所以:
上式子可以变成:K+慢在循环圈里的距离+ 满圈的长度*n圈 =K+慢在循环圈里的距离+K+慢在循环圈里的距离。
所以可以得到:满圈的长度*n圈 =K+慢在循环圈里的距离;
如果n是1, 那么k的长度就是等于现在相遇地方到循环开始的地方。就是k到循环开始的地方和相遇地方到循环开始的地方。。
如果 n是2,那么k到循环开始的地方就是,循环一圈加相遇地方到循环开始的地方。
所以,k到循环开始的地方和相遇地方到循环开始的地方。
所以,一个指针在原地,一个指针在开始的地方,都往前走,相遇的那个点就是循环开始的地方。
1 public class Circ6 { 2 static class LinkNode { 3 int val; 4 LinkNode next; 5 6 LinkNode(int x) { 7 val = x; 8 next = null; 9 } 10 } 11 12 public static LinkNode FindBeginning(LinkNode head) { 13 LinkNode slowp = head; 14 LinkNode fastp = head; 15 16 while (fastp != null && fastp.next != null) { 17 fastp = fastp.next.next; 18 slowp = slowp.next; 19 if (fastp == slowp) { 20 break; 21 } 22 } 23 if (fastp == null || fastp.next == null) { 24 return null; 25 } 26 slowp = head; 27 while (slowp != fastp) { 28 slowp = slowp.next; 29 fastp = fastp.next; 30 } 31 return slowp; 32 } 33 }
网上还看到另一个解题方法:
就是用hashSet,存每一个节点,如果set里存在这个节点,就返回这个节点。
public LinkNode firstNodeInCircle1(LinkNode head) { if (head == null || head.next == null) return null; Set<LinkNode> hashSet = new HashSet<LinkNode>(); while (head != null) { if (hashSet.contains(head)) { return head; } else { hashSet.add(head); head = head.next; } } return null; }
http://www.hawstein.com/posts/2.5.html
http://www.jyuan92.com/blog/careercup2_6-first-node-in-circle-linkedlist/
https://github.com/1094401996/CareerCup/blob/master/Chapter02/src/twodot6/Circular.java
标签:
原文地址:http://www.cnblogs.com/hewx/p/4492189.html