最近看到關於環的算法題以爲頗有意思,因而思考了一會,如今分幾步把解法展現出來.java
問題1:如何檢測一個單鏈表有環.算法
設兩個指針,p=head,q=head,從頭結點開始,每次p = p.next , q= q.next.next ,若是能找到一點p==q就說明這個有環.
this
問題2:一個有環的單鏈表找出環的入口.指針
如圖所示,設置3個變量,根據第一次相遇時,q走的距離是p的兩倍,能夠列出一個方程等式, 2*(a+b) =a+2b+c,最後能夠簡化成 a = c.那麼從第一次相遇的焦點到圓環的起始點和從head到圓環的起始點實際上結點數同樣多,這樣就可能夠經過循環判斷來完成.p=head , q=第一次相遇點. while(p!= q) {p=p.next ; q=q.next} 最終找到圓環的起點.code
附上代碼:get
public class FindFrstCircleNode { public static void main(String[] args) { Node<Integer> head = new Node<Integer>(1); Node<Integer> n1 = new Node<Integer>(2); Node<Integer> n2 = new Node<Integer>(3); Node<Integer> n3 = new Node<Integer>(4); Node<Integer> n4 = new Node<Integer>(5); Node<Integer> n5 = new Node<Integer>(6); Node<Integer> n6 = new Node<Integer>(7); Node<Integer> n7 = new Node<Integer>(8); Node<Integer> n8 = new Node<Integer>(9); Node<Integer> n9 = new Node<Integer>(10); head.next = n1; n1.next = n2; n2.next = n3; n3.next = n4; n4.next = n5; n5.next = n6; n6.next = n7; n7.next = n8; n8.next = n9; n9.next = n5; FindFrstCircleNode ffcn = new FindFrstCircleNode(); Node<Integer> p = ffcn.getFirstCircleNode(head); System.out.println(p.data); } public Node<Integer> getFirstCircleNode(Node<Integer> head) { Node<Integer> p = head; Node<Integer> q = head; int count = 0; while (count == 0 || p != q) { p = p.next; q = q.next.next; count++; } p = head; while (p != q) { p = p.next; q = q.next; } return p; } static class Node<T> { T data; Node<T> next; public Node() { super(); } public Node(T data) { super(); this.data = data; } } }
問題3:兩個無環單鏈表有一個結點相交,找出這個交點.class
最爛的解法:變量
循環H1的結點,H1的每一個結點與H2的全部結點對比,時間複雜度是O(n*m)循環
最簡單的解法:遍歷
找到H1的長度m,找到H2的長度n.較長的結點先移動m-n的長度,而後遍歷循環兩個鏈表,結束的條件是p.next=q.next 時間複雜度是O().
最方便的解法:
把H1鏈表結點依次放到HashSet中,而後再把H2鏈表結點依次放入HashSet中,直到沒法放入的時候就找到這個相交的節點了.
最優雅的解法:
把H1最後的結點指向H1的頭部.而後就把問題轉換成問題2了.