這道題目主要討論單鏈表相交的一系列問題。在本題中,單鏈表可能有環,也可能無環。給定兩個單鏈表的頭節點 head1 和 heda2 ,這兩個鍊錶可能相交,也可能不相交。請實現乙個函式,如果兩個鍊錶相交,請返回相交的第乙個節點;如果不相交返回 null 即可。
要求:如果鍊錶 1 的長度為n,鍊錶 2 的長度為 m,時間複雜度請達到 o(n+m),空間複雜帶請達到 o(1)。
這道題需要分析的情況非常多,同時因為有額外空間複雜度為 o(1) 的限制,非常具有挑戰。
這道題可以使用數學中的分類討論思想,分成三個子問題:
問題一:如何判斷乙個鍊錶是否相交,相交則返回第乙個相交節點,不相交則返回 null。
問題二:如何判斷兩個無環鏈表是否相交,相交則返回第乙個相交節點,不相交則返回null。
問題三:如何判斷兩個有環鏈表是否相交,相交則返回第乙個相交節點,不相交則返回null。
這道題目主要就兩個任務:一是如何判斷有環,二是如何判斷相交。在判斷相交分兩種情況,兩個無環鏈表是否相交,兩個有環鏈表是否相交。
注意:如果乙個鍊錶有環,另外乙個鍊錶無環,它們是不可能相交的,直接返回null。下面逐個分析每個問題。
問題一:如何判斷乙個鍊錶是否相交,相交則返回第乙個相交節點,不相交則返回 null。
如果乙個鍊錶沒有環,那麼遍歷鍊錶一定可以遇到鍊錶的終點;如果乙個鍊錶有環,那麼遍歷鍊錶就永遠在環裡轉下去了。下面給出找到第乙個入環節點的思路:
使用乙個快指標 fast,和乙個慢指標 slow,快指標的移動速度是慢指標的2倍;
如果鍊錶沒有環,fast 先到鍊錶尾,且next為null;
如果鍊錶有環,最後快指標和慢指標會在某個位置相遇,即 slow==fast;
此時讓其中乙個指標指向head,例如 slow = head,然後slow,fast速度同步繼續往前,當 slow == fast,此時的節點便是第乙個入環的節點。
**實現如下:
1//問題一:如何判斷乙個鍊錶是否有環,如果有,則返回進入環的第乙個節點,否則返回null
2 public node getloopnode(node head)
6 node slow = head.next;
7 node fast = head.next.next;
8 while (slow != fast)
13 fast = fast.next.next;
14 slow = slow.next;
15 }
16 fast = head;
17 while (slow != head)
21 return slow;
22 }
問題二:如何判斷兩個無環鏈表相交,相交則返回第乙個相交節點,否則返回null
如果兩個無環鏈表相交,那麼從相交節點開始,直到煉表表尾,這段節點是兩個鍊錶共享的。思路如下:
遍歷兩個無環鏈表,並統計鍊錶的長度,len1、len2;
判斷兩個鍊錶的 end 節點是否相等,如果 end1 != end2,兩個鍊錶無相交,直接返回null;end1 == end2,兩個鍊錶相交,進入3,尋找相交的第乙個節點;
如果len1-len>0,則鍊錶1 先走 len1-len2 的長度,如果len2-len1>0,則鍊錶2先走len2-len1的長度,然後兩個鍊錶一起向前走,當鍊表第一次走到一起的那個節點時,這個節點就是相交的第乙個節點。
**實現如下:
1//問題二:如何判斷兩個無環鏈表相交,相交則返回第乙個相交節點,否則返回null
2 public node noloop(node head1,node head2)
6 node cur1 = head1;
7 node cur2 = head2;
8 int n = 0;
9 while (cur1.next != null)
13 while (cur2.next != null)
17 cur1 = n > 0 ? head1 : head2;//cur1 始終指向較長鍊錶的head
18 cur2 = cur1 == head1 ? head2 : head1;
19 n = math.abs(n);
20 while (n != 0)
24 while (cur1 != cur2)
28 return cur1;
29 }
問題三:如何判斷兩個有環鏈表是否相交,相交則返回第乙個相交節點,否則返回null
在解決問題三的時候,已經可以通過前面的方法可以獲得入環的第乙個節點了,假設鍊錶 1 的第一入環節點為 loop1,鍊錶二的第乙個入環節點為 loop2。具體思路如下:
如果鍊錶的loop1、loop2 相等,則鍊錶1和鍊錶2相交的第乙個節點在 loop1 之前,只需使用問題二的方式找出即可,唯一的區別,問題二鍊錶的終點是null ,而這裡終點是loop1 或 loop2;
如果 loop1 != loop2 ,讓 節點從loop1 開始,因為鍊錶有環,所以肯定會回到 loop1,如果在這個過程中,遇到了loop2 ,則說明兩個鍊錶相交,返回loop1 或者loop2 ,如果沒有遇到 loop2 ,則說明兩個鍊錶不相交,返回null 即可。
**實現如下:
1//問題三:如何判斷兩個有環鏈表是否相交,相交則返回第乙個相交節點,否則返回null
2 public node bothloop (node head1,node loop1,node head2,node loop2)
14 while (cur2.next != loop2)
18 cur1 = n>0 ? head1 : head2;
19 cur2 = cur1==head1 ? head2 : head1;
20 n = math.abs(n);
21 while (n != 0)
25 while (cur1 != cur2)
29 return cur1;
3031 } else
38 cur1 = cur1.next;
39 }
40 return null;
41 }
42 }
回到最開始的那個問題,全部的實現過程看如下**,這也是整個問題的主方法。
1class node
7public node getintersectnode(node head1,node head2)
11 //獲取兩個鍊錶的第乙個入環節點(如果有)
12 node loop1 = getloopnode(head1);
13 node loop2 = getloopnode(head2);
14 //如果第乙個入環節點為空,說明是問題二的情況
15 if (loop1 == null & loop2 == null)
18 //如果第乙個入環節點不為空,說明是問題三的情況
19 if (loop1 != null & loop2 != null)
22 return null;
23 }
單鏈表操作系列
include includetypedef int elemtype 定義結點型別 typedef struct node lnode,linklist 單鏈表的建立1,頭插法建立單鏈表,逆序生成 linklist linklistcreateh return l 單鏈表的建立2,尾插法建立單鏈表...
單鏈表操作 單鏈表反轉問題?
單鏈表 typedef struct nodelnode 關於但鍊錶的操作很多 增刪改查,逆序,子交並補等,以及一些經典的變式 考研題目中,有很多好的演算法值得學習。下面是c語言實現的,採用乙個method,乙個test method,方便逐個學習,這個需要不斷的積累,最好用敲幾遍,再在紙上多寫寫,...
演算法系列 單鏈表
public class linkedlist else size 插入方法 public void add int index,e e this.top.addnewnode index,newnode size 修改方法 public void set int index,e e 刪除方法 pu...