分治法:把分解後的小問題各個解決,然後把小問題的解決方案結合起來解決大問題。
面試題35:複雜鍊錶的複製。請實現函式complexlistnode* clone(complexlistnode* phead)
,複製乙個複雜鍊錶。在複雜鍊錶中,每個節點除了有乙個m_pnext指標指向下乙個節點,還有乙個m_psibling指標指向鍊錶中任意節點或者nullptr。節點定義如下:
struct complexlistnode
;
這個問題很多人的方法是把複製過程分為兩步,第一步複製原始鍊錶上的每個節點,再用m_pnext鏈結起來;第二步是設定每個節點的m_psibling指標。對於第二步,找到乙個節點的m_psibling指標指向的節點需要從頭結點沿著m_pnext遍歷鍊錶,因為我們不知道m_psibling指向的節點在當前節點的前面還是後面。對於乙個含有n個結點的複雜鍊錶,這種方法的總的時間複雜度是o(n²)。
以上方法的時間主要花費在定位節點的m_psibling指標指向的節點上,我們可以優化第二步:將原始鍊錶的節點n和新鍊錶的節點n放到乙個雜湊表中,用表示,若原始鍊錶中節點n的m_psibling指向節點s,那麼新煉表中節點n的m_psibling指向s,有了雜湊表,我們可以用o(1)的時間根據s找到s。這種方法相當於以空間換時間,對於n個節點的複雜鍊錶,我們需要乙個大小為o(n)的雜湊表,把時間複雜度降為了o(n)。
還有一種思路,可以不用輔助空間就實現o(n)的時間效率。第一步,將根據原始節點建立的新節點插入到原始節點後邊;第二步設定新建立節點的m_psibling指標,如原始鍊錶上節點n的m_psibling指向s,則它的對應複製節點n的m_psibling指向s;第三步把長鍊錶拆分為兩個鍊錶:
#include
#include
using
namespace std;
struct complexlistnode
;void
printlistreversingly_iteratively
(complexlistnode* phead)
while
(!nodes.
empty()
)}void
clonenodes
(complexlistnode* phead)
}void
connectsiblingnode
(complexlistnode* phead)
phead = phead-
>m_pnext-
>m_pnext;}}
complexlistnode*
reconnectnodes
(complexlistnode* phead)
poldnode-
>m_pnext =
nullptr
;// 因為迴圈只能到最後兩個新舊節點還沒分開的狀態,需要將最後乙個舊節點與最後乙個新節點分開
cout <<
"反向列印舊鍊錶驗證舊鍊錶狀態:"
<< endl;
printlistreversingly_iteratively
(oldlist)
;return newlist;
}complexlistnode*
clone
(complexlistnode* phead)
clonenodes
(phead)
;// 第一步,轉殖節點
connectsiblingnode
(phead)
;// 第二步,設定新節點的m_psibling指標
return
reconnectnodes
(phead)
;// 第三步,分鍊錶
}int
main()
劍指offer 學習筆記 鍊錶
我們說鍊錶是一種動態資料結構是因為在建立鍊錶時,無需知道鍊錶的長度。當插入乙個節點時,我們只需要為新節點分配記憶體,然後調整指標的指向來確保新節點被鏈結到鍊錶當中。記憶體分配不是建立鍊錶時一次性完成的,而是每新增乙個節點分配一次記憶體,由於沒有閒置的記憶體,鍊錶的空間效率比較高。如果單向鍊錶的節點定...
劍指offer複雜鍊錶複製
題目描述 輸入乙個複雜鍊錶 每個節點中有節點值,以及兩個指標,乙個指向下乙個節點,另乙個特殊指標指向任意乙個節點 返回結果為複製後複雜鍊錶的head。注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空 我的 思路比較笨,就是首先構造乙個正常的不大random指標的鍊錶,然後再去遍歷...
劍指offer 複雜鍊錶複製
輸入乙個複雜鍊錶 每個節點中有節點值,以及兩個指標,乙個指向下乙個節點,另乙個特殊指標指向任意乙個節點 返回結果為複製後複雜鍊錶的head。注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空 解題思路 1 複製每個節點,如 複製節點a得到a1,將a1插入節點a後面 2 遍歷鍊錶,a...