1. 程式人生 > >1.4 python資料結構之連結串列——移除重複項及帶隨機指標的連結串列複製

1.4 python資料結構之連結串列——移除重複項及帶隨機指標的連結串列複製

這一篇是LeetCode上關於連結串列的兩道題目,難度都是中等,但是我認為難度很大了,尤其是複製連結串列一題,思路清奇。

1)82. Remove Duplicates from Sorted List II (從有序列表中移除重複項)

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given 1->2->3->3->4->4->5, return 1->2->5.

Given 1->1->1->2->3, return 2->3.

要注意83題是保留一項,十分簡單,就不解析了;而這道題威力加強,如果有兩項是重複的,就全都刪掉。先看程式碼再解釋:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head == None or head.next == None:
            return head        
        fhead = ListNode(0)
        fhead.next = head
        pre = fhead        
        cur = head
        
        while cur:
            while cur.next and cur.val==cur.next.val:
                cur = cur.next
            if pre.next == cur:          # 如果只此一個值,不刪除,pre後移
                pre = cur
            else:
                pre.next = cur.next      # 如果不只一個,刪除這些結點,pre暫不後移
            cur = cur.next
        return fhead.next

因為頭結點可能會被刪掉,先加一個結點;判斷相鄰兩項的值,停留在重複項的最後一個位置(或者就原地不動了),通過pre指標與當前指標的關係判斷兩種情況。理解解題思想很關鍵~

2)138. Copy List with Random Pointer(複製含有隨機指標的連結串列)

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.

這一連結串列結點的定義看下面程式碼,這一題其實蠻有難度,甚至題目還如此簡潔,連個樣例都沒有,測試樣例也看不懂。複製問題的關鍵在於,挨個複製結點時,結點的next本身複製了結點間的連線關係並賦予label值,建立了一個label和next屬性都一樣的新結點,而random指向另一結點時,卻不能通過複製label來解決,因為其指向一個已存在的結點(該連結串列中的),你複製的話就分叉了而沒有指向該連結串列中的結點(或者指向了原連結串列中的結點)。

下面的解決方案有點牛逼,看後面的大神的方法寫的:

# Definition for singly-linked list with a random pointer.
# class RandomListNode(object):
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None

class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: RandomListNode
        :rtype: RandomListNode
        """
        if head == None:
            return None
        p = head        
        while p:
            tmp = p.next
            p.next = RandomListNode(p.label)
            p.next.next = tmp
            p = tmp
        p = head
        while p:
            if p.random:
                p.next.random = p.random.next
            p = p.next.next
        newhead = RandomListNode(0)
        p = head
        q = newhead
        while p:
            tmp = p.next.next
            q.next = p.next
            q = q.next
            p.next = tmp
            p = tmp
        return newhead.next

這一方法用了三次迴圈,結合下圖理解一下。該方法的時間複雜度為O(n),空間複雜度O(1),幾乎不佔用額外的記憶體空間。

當然這一問題有一個更直觀的解決方法,就是雜湊表,第一次遍歷儲存各結點,第二遍設定隨機指標,其空間複雜度為O(n).

python語言中用字典也可以解決這個問題,詳情可看如下程式碼:

class Solution:
# @param head, a RandomListNode
# @return a RandomListNode
def copyRandomList(self, head):
    dic = collections.defaultdict(lambda: RandomListNode(0))
    dic[None] = None
    n = head
    while n:
        dic[n].label = n.label
        dic[n].next = dic[n.next]
        dic[n].random = dic[n.random]
        n = n.next
    return dic[head]