轉載於:http://blog.csdn.net/insistgogo/article/details/7584240
一、單鏈表結點的刪除
0、刪除單鏈表p指向的那個元素,(時間和空間複雜度儘量小)
二、單鏈表的存取
1、找出單鏈表的倒數第K個元素,(僅允許遍歷一遍鏈表)
2、找出單鏈表的中間元素,(僅允許遍歷一遍鏈表)
三、單鏈表與環的問題
3、判斷單鏈表是否有環(6形狀)?
4、如何找到環的入口?
5、如何知道環的長度?
6、帶環鏈表的長度是多少?
四、單鏈表與相交、環的問題
7、如何知道兩個單鏈表(無環)是否相交
8、如果兩個單鏈表(無環)相交,如何知道它們相交的第一個節點是什麼
9、如何知道兩個單鏈表(有環)是否相交
10、如果兩個單鏈表(有環)相交,如何知道它們相交的第一個節點是什麼
~~~~~~~~~~~華麗的分割線~~~~~~~~~~~~~~
一、單鏈表結點的刪除
0、刪除單鏈表p指向的那個元素,(時間和空間複雜度儘量小)
思路:把q指向結點的值 賦給 p指向的結點,再把q指向結點刪除
二、單鏈表的存取
1、找出單鏈表的倒數第K個元素,(僅允許遍歷一遍鏈表)
思路:使用指針追趕的方法。定義兩個指針fast和slow,fast先走K步,然後從這時開始,fast和slow同時繼續走,即fast和slow相差K個元素。當fast到頭時,slow指向倒數第K個。注意要考慮鏈表長度應該大於K。2、找出單鏈表的中間元素,(僅允許遍歷一遍鏈表)
思路:使用指針追趕的方法。使用兩個指針fast和slow,只是fast每次走一步,slow每次走兩步。當fast到頭時,slow指向鏈表的中間元素
三、單鏈表與環的問題
3、判斷單鏈表是否有環(6形狀)?
思路:使用指針追趕的方法,設定兩個指針fast、slow,從頭指針開始,每次分別前進1步、2步。如存在環,則兩者相遇;如不存在環,fast遇到NULL退出。
- while(直到步長2的跑到結尾)
- {
- 檢查兩個指針是否相等,直到找到爲止。
- }
4、如何找到環的入口?
圖說明:如上圖,h是鏈表起始點,s是環入口,p是兩個指針碰撞點。r = x + y
可以證明, a = y + mr (頭指針 到 環入口的距離 = 碰撞點p 到 環入口的距離 + 循環多次環 )
附錄處有證明
思路:令兩個指針分別從第一個結點、碰撞點開始走,每一次走一步,直到兩指針相遇,此時相遇的那個點就是環入口
5、如何知道環的長度?
思路:記錄下問題4的碰撞點p(或者找在環中任意一結點都可以),讓slow從碰撞點開始,繞着環走一圈,再次到碰撞點的位置時,所走過的結點數就是環的長度s。(一個指針從起始點出發走一圈,再次到起始點,就是走了環一圈)
6、帶環鏈表的長度是多少?
思路:帶環鏈表長度 = a + x + y = 鏈表起始點h 到 環起始點s的距離 + 環的長度 。在第4題中可以找到a的值,在第5題可以找到 環的長度(x+y)的值四、單鏈表與相交、環的問題
7、如何知道兩個單鏈表(無環)是否相交
思路:
1、判斷兩鏈表最後一個節點是否相同,如果相交,則尾節點肯定是同一節點。
時間複雜度O((length(A)+ length(B))、空間複雜度 = O(1)(存儲最後結點的地址)
2、人爲構環,如上圖。將鏈表A的尾節點指向鏈表B,如果B鏈表有環,則兩個鏈表相交,此時從鏈表B的頭指針往下遍歷,如果能夠回到B,則說明相交
時間複雜度O((length(A)+ length(B)),沒有額外的空間消耗
8、如果兩個單鏈表(無環)相交,如何知道它們相交的第一個節點是什麼
思路:
1、先取得兩個鏈表A和B的長度len(A)和len(B)
2、沿着A和B鏈表中較長的鏈表遍歷,使用指針追趕的方法。
設定兩個指針fast、slow。fast先出發前進(lengthMax-lengthMin)步(即是二者的長度之差)使fast和slow指針到相交點的距離相等,之後兩個鏈表同時前進,每次一步,相遇的第一點即爲兩個鏈表相交的第一個點。
9、如何知道兩個單鏈表(可能有環)是否相交
思路:根據兩個鏈表是否有環來分別處理
1、如果兩個鏈表都沒有環。可用 問題7 來判斷
2、一個有環,一個沒環。肯定不相交
3、兩個都有環。(注,兩個有環鏈表相交是指這個環屬於兩個鏈表共有)
具體方法:如果兩個都有環,則求出A的環入口,判斷其是否在B鏈表上,如果在,則相交。
或者,在A鏈表上,使用指針追趕的方法,找到兩個指針碰撞點,之後判斷碰撞點是否在B鏈表上。如果在,則相交 。
10、如果兩個單鏈表(有環)相交,如何知道它們相交的第一個節點是什麼
(注,兩個有環鏈表相交是指這個環屬於兩個鏈表共有)
情況1:相交的點,在環外
思路:使用指針追趕的方法。
1、求兩個鏈表A和B的長度Length(A)和Length(B)
2、如果Length(A)> Length(B),則鏈表A指針先走 Length(A)- Length(B),鏈表B指針再開始走,則兩個指針相遇的位置就是相交的第一個節點。
如果 Length(B)> Length(A),則鏈表B指針先走 Length(B)- Length(A),鏈表A指針再開始走,則兩個指針相遇的位置就是相交的第一個節點。
情況2(圖2)、相交的點,在環內,還不能處理
分析:當交點在環中時,此時的交點可以是A鏈表中的環入口點,也可以是B鏈表中環入口點。
爲什麼這麼說?這是因爲如果把B看出一個完整的鏈表,而A指向了B鏈表,則此時交點是A的環入口點。反之交點是鏈表B的環入口點。
思路:根據上述分析,可以直接求出A的環入口點或者B的環入口點就可以了。
綜合這兩種情況,給出兩個方法求出結點
方法一、先檢測交點是否在第一種情況中。如果是,則直接輸出該結點。如果不是,則直接輸出任意一個環交點。
方法二、使用哈希,只需要把鏈表A或者B所有的元素全部放入哈希表中,之後把B鏈表或者A鏈表中的每一個元素去哈希探測,即可找到交點。
附錄1、
4、如何找到環的入口?
圖說明:如圖,h是鏈表起始點,s是環入口,p是兩個指針碰撞點。r表示環的長度,r = x+y
可以證明, a = y + mr (頭指針 到 環入口的距離 = 碰撞點p 到 環入口的距離 + 循環多次環 )
證明:
當fast若與slow相遇時,slow肯定沒有走遍歷完鏈表,而fast已經在環內循環了n圈(1<=n)。
假設slow走了s步,則fast走了2s步(fast步數還等於s 加上在環上多轉的n圈)。
設環長爲r,則:
2s = s + nr,即s= nr設整個鏈表長L,入口環與相遇點距離爲x,起點到環入口點的距離爲a。
s = nr
a + x = nr
a + x = (n – 1)r +r = (n-1)r + r
a = (n-1)r + r - x
a = (n-1)r + y
由此可知,從鏈表頭到環入口點等於(n-1)循環內環+ 相遇點到環入口點,於是我們從鏈表頭、與相遇點分別設一個指針,每次各走一步,兩個指針必定相遇,且相遇第一點爲環入口點。