題目描述
輸入乙個複雜鍊錶(每個節點中有節點值,以及兩個指標,乙個指向下乙個節點,另乙個特殊指標指向任意乙個節點),返回結果為複製後複雜鍊錶的head。(注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空)
# -*- coding: utf-8 -*-
# @time : 2019-07-05 15:52
# @author : jayce wong
# @projectname : job
# @filename : complexlistnodeclone.py
# @blog :
# @github :
class randomlistnode:
def __init__(self, x):
self.label = x
self.next = none
self.random = none
""" 解法1:
直接複製鍊錶的話,由於每個節點有乙個隨機指標指向任意的位置(包括空指標),因此如果用最樸素的方法
來解決,需要在將所有節點複製完之後,對每個節點的random屬性遍歷一次整個鍊錶,因此假設共有n個
節點,那麼這種最樸素的解法的時間複雜度為o(n^2)
解法2:
解法1之所以效率低是因為每個節點的random指標的指向需要遍歷整個鍊錶才能找到,如果我們犧牲空間來
換時間的話,那麼就可以做到時間複雜度為o(n), 額外使用空間o(n)。
具體做法可以是用乙個字典來儲存每個節點及其對應的轉殖節點的位址,這樣就可以通過查詢這個雜湊表在
o(1)的時間內找到random指標所指向的節點
解法3:
解法2之所以能把時間複雜度降下來,是因為儲存了原始節點和對應轉殖節點的位置關係,因此可以很快找到
原始節點對應的轉殖節點在哪。如果我們在複製鍊錶的時候就讓轉殖節點跟在原始節點後面,那麼就可以在
不額外使用雜湊表的情況下做到時間複雜度為o(n)了
"""class solution2:
def clone(self, phead):
if not phead:
return none
nodetable = dict() # 用於儲存原始節點對應的轉殖節點的位址
pclone = randomlistnode(phead.label)
# 由於節點型別無法雜湊,因此用位址作為key
nodetable[id(phead)] = pclone
pnode = phead
pnode = pnode.next
clonenode = pclone
# 這個迴圈用於將原始鍊錶複製出來,但是先忽略random指標,關鍵在於要用這個字典儲存
# 原始節點和對應轉殖節點的位址
while pnode:
clonenode.next = randomlistnode(pnode.label)
nodetable[id(pnode)] = clonenode.next
clonenode = clonenode.next
pnode = pnode.next
# 根據字典儲存的資訊設定轉殖鍊錶的random指標
clonenode = pclone
while phead:
# 需要注意的是random指標可能是指向none,而我們在字典中並沒有儲存none的key
if phead.random:
clonenode.random = nodetable[id(phead.random)]
phead = phead.next
clonenode = clonenode.next
return pclone
class solution3:
def clone(self, phead):
# 解法3的思路可以分為三步:
# 1. 複製整個鍊錶,這裡先忽略random指標的指向,得到形如a->a'->b->b'->c->c'的複製結果
# 2. 設定轉殖節點的random指標
# 3. 將鍊錶拆分成原始鍊錶和轉殖鍊錶
self.clonenode(phead)
self.connectsiblingnode(phead)
return self.reconnectnode(phead)
def clonenode(self, phead):
pnode = phead
while pnode:
pclone = randomlistnode(pnode.label)
pclone.next = pnode.next
pnode.next = pclone
pnode = pclone.next
def connectsiblingnode(self, phead):
pnode = phead
while pnode:
clone_head = pnode.next
if pnode.random:
clone_head.random = pnode.random.next
pnode = clone_head.next
def reconnectnode(self, phead):
if not phead:
return none
new_head = phead.next
pnode = new_head
"""這裡不知為什麼,如果把phead指向new_head的左邊(即phead和new_head分別指向a和a')
然後進入迴圈就不能通過牛客的oj,
但是將phead指向new_head的右邊(即phead和new_head分別指向b和a')
然後進入迴圈就可以通過。
這兩種方法在本地除錯的時候都是沒問題的。
"""phead.next = pnode.next
phead = phead.next
while phead:
pnode.next = phead.next
pnode = pnode.next
phead.next = pnode.next
phead = phead.next
return new_head
def main():
# 1->3
# 2->1
# 3->2
# node = randomlistnode(1)
# node.next = randomlistnode(2)
# node.next.next = randomlistnode(3)
# node.random = node.next.next
# node.next.random = node
# node.next.next.random = node.next
node1 = randomlistnode(1)
node2 = randomlistnode(2)
node3 = randomlistnode(3)
node4 = randomlistnode(4)
node5 = randomlistnode(5)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node1.random = node3
node2.random = node5
node4.random = node2
solution = solution2()
head = solution.clone(node1)
while head:
if head.random:
print(head.label, head.random.label)
else:
print(head.label, 'none')
head = head.next
if __name__ == '__main__':
main()
劍指offer複雜鍊錶複製
題目描述 輸入乙個複雜鍊錶 每個節點中有節點值,以及兩個指標,乙個指向下乙個節點,另乙個特殊指標指向任意乙個節點 返回結果為複製後複雜鍊錶的head。注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空 我的 思路比較笨,就是首先構造乙個正常的不大random指標的鍊錶,然後再去遍歷...
劍指offer 複雜鍊錶複製
輸入乙個複雜鍊錶 每個節點中有節點值,以及兩個指標,乙個指向下乙個節點,另乙個特殊指標指向任意乙個節點 返回結果為複製後複雜鍊錶的head。注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空 解題思路 1 複製每個節點,如 複製節點a得到a1,將a1插入節點a後面 2 遍歷鍊錶,a...
劍指offer 複雜鍊錶複製
題目描述 輸入乙個複雜鍊錶 每個節點中有節點值,以及兩個指標,乙個指向下乙個節點,另乙個特殊指標指向任意乙個節點 返回結果為複製後複雜鍊錶的head。注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空 非遞迴方法 struct randomlistnode randomlistno...