題目描述
輸入一個複雜鏈表(每個節點中有節點值,以及兩個指針,一個指向下一個節點,另一個特殊指針指向任意一個節點),返回結果爲複製後複雜鏈表的head。(注意,輸出結果中請不要返回參數中的節點引用,否則判題程序會直接返回空)
首先這道題可以在這裏進行算法測試:複雜鏈表的複製
定義一下算法描述的鏈表節點的數據結構:
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
算法其實並不複雜,但是要將其清楚且完整地表達並且實現出來,還是需要一定的時間與代碼功底。
認真分析之後,將問題分解,問題分解的好處就是,不要求算法能夠一蹴而就,並且一蹴而就的算法代碼實現會極大增加算法的實現難度。
所以通過分析,將算法分成如下3個步驟
:
(1). 第一步:首先拷貝出每個節點,由於鏈表是從頭到尾拷貝的,那麼後面的拷貝子節點還暫時沒有生成,所以我們就暫時僅僅拷貝單個節點,拷貝的子節點字段暫時不設置。等到完全拷貝之後,到第二部再進行設置。
private void cloneNodes(RandomListNode node){
RandomListNode cur = node, clonedNode = null;
while(cur != null){
clonedNode = new RandomListNode(cur.label);
clonedNode.next = cur.next;
cur.next = clonedNode;
cur = clonedNode.next;
}
}
代碼很簡單,就是單純地在每個源鏈表節點中間拷貝一個節點插入進去即可。
(2). 第二步:補充拷貝後節點的完整性。即,設置每個拷貝的節點的子節點(即數據結構中的random字段)
private void connectSilblingNodes(RandomListNode node){
RandomListNode cur = node, clonedNode = null;
while(cur != null){
clonedNode = cur.next;
if(cur.random != null){
clonedNode.random = cur.random.next;
}
cur = clonedNode.next;
}
}
(3). 第3步:將整個鏈表拆成兩個鏈表,一個是源鏈表,一個是拷貝後的鏈表。
private RandomListNode reconnectNodes(RandomListNode node){
RandomListNode cur = node;
RandomListNode dummyHead = new RandomListNode(-1);
RandomListNode clonedNode = dummyHead;
while(cur != null){
clonedNode.next = cur.next;
clonedNode = clonedNode.next;
cur.next = clonedNode.next;
cur = cur.next;
}
return dummyHead.next;
}
這裏用到了設置虛擬頭節點
技巧,這是一個亮點,其它沒啥技巧,很容易懂。
下面是整個運行通過測試的代碼:
public class Solution {
// the algorithm entrance ...
public RandomListNode Clone(RandomListNode pHead) {
cloneNodes(pHead);
connectSilblingNodes(pHead);
return reconnectNodes(pHead);
}
private void cloneNodes(RandomListNode node){
// ... ignore
// reference the article above
}
private void connectSilblingNodes(RandomListNode node){
// ... ignore
// reference the article above
}
private RandomListNode reconnectNodes(RandomListNode node){
// ... ignore
// reference the article above
}
}
更多
總的來說還是基本的鏈表操作,但是問題要分析清楚,問題分析清楚就簡單了。