問題描述:java
有一個單鏈表,其中可能有一個環,也就是某個節點的next指向的是鏈表中在它以前的節點,這樣在鏈表的尾部造成一環。 oop
如何判斷一個鏈表是否是這類鏈表? spa
問題擴展: 指針
若是鏈表可能有環呢?code
若是須要求出兩個鏈表相交的第一個節點呢? orm
問題分析:
it
在無環的狀況下,若是兩個鏈表有結點相同,那麼它們下一結點也相同,如此可推出尾結點也相同。 ast
那麼只要判斷兩鏈表的尾結點是否相同。(O(len1+len2))class
//if there is no cycle boolean isJoinedSimple(Node n1, Node n2){ while(n1 != null) n1 = n1.next; while(n2 != null) n2 = n2.next; return n1 == n2; }
擴展1:擴展
須要先判斷有環無環,能夠這樣作,定義兩個指針,指向頭結點,一個每次移動一個結點,另外一個每次移動兩個結點,若是慢的能追上快的(也就是兩個指針重逢),就說明有環。
boolean hasLoop(Node n){ Node nFast = n; Node nSlow = n; while(nFast != null && nSlow != null){ nFast = nFast.next.next; nSlow = nSlow.next; if(nFast == nSlow) return true; } return false; }
利用以下方法分別找到兩個鏈表的環入口。首先設置一個快慢指針p_fast和p_slow,找到兩個指針相交的點,p_inter。而後p從鏈表開頭,p_slow從p_inter開始走,每次都走1步,則兩個指針相交的地方,就是鏈表的入口。
(a) 分別求得A和B兩個鏈表的入口,若是同樣。則兩個鏈表相交的第一個節點方法同1,只是將環當成NULL便可。
(b) 若是兩個鏈表的環入口不同,則沒有第一個相交節點。
擴展2:
如何找到入口點:
當fast若與slow相遇時,slow確定沒有走遍歷完鏈表,而fast已經在環內循環了n圈(1<=n)。假設slow走了s步,則fast走了2s步(fast步數還等於s 加上在環上多轉的n圈),設環長爲r,則:
2s = s + nr
s= nr
設整個鏈表長L,入口環與相遇點距離爲x,起點到環入口點的距離爲a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)
(L – a – x)爲相遇點到環入口點的距離,由此可知,從鏈表頭到環入口點等於(n-1)循環內環+相遇點到環入口點,因而咱們從鏈表頭、與相遇點分別設一個指針,每次各走一步,兩個指針一定相遇,且相遇第一點爲環入口點。程序描述以下:
Node findLoopPort(LinkedList lst){ Node nFast = lst.head; Node nSlow = lst.head; while(nFast != null && nFast.next!= null){ nFast = nFast.next.next; nSlow = nSlow.next; if(nFast == nSlow) break; } if(nFast == null || nSlow == null) return null; nSlow = head; while(nSlow != nFast){ nSlow = nSlow.next; nFast = nFast.next; } return nSlow; }