[LeetCode] 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.html

Return a deep copy of the list.node

 

Example 1:git

Input:
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1}

Explanation:
Node 1's value is 1, both of its next and random pointer points to Node 2.
Node 2's value is 2, its next pointer points to null and its random pointer points to itself.

 

Note:github

  1. You must return the copy of the given head as a reference to the cloned list.

 

這道鏈表的深度拷貝題的難點就在於如何處理隨機指針的問題,因爲每個節點都有一個隨機指針,這個指針能夠爲空,也能夠指向鏈表的任意一個節點,若是在每生成一個新節點給其隨機指針賦值時,都要去遍歷原鏈表的話,OJ 上確定會超時,因此能夠考慮用 HashMap 來縮短查找時間,第一遍遍歷生成全部新節點時同時創建一個原節點和新節點的 HashMap,第二遍給隨機指針賦值時,查找時間是常數級。代碼以下:dom

 

解法一:函數

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if (!head) return nullptr;
        Node *res = new Node(head->val, nullptr, nullptr);
        Node *node = res, *cur = head->next;
        unordered_map<Node*, Node*> m;
        m[head] = res;
        while (cur) {
            Node *t = new Node(cur->val, nullptr, nullptr);
            node->next = t;
            m[cur] = t;
            node = node->next;
            cur = cur->next;
        }
        node = res; cur = head;
        while (cur) {
            node->random = m[cur->random];
            node = node->next;
            cur = cur->next;
        }
        return res;
    }
};

 

咱們可使用遞歸的解法,寫起來至關的簡潔,仍是須要一個 HashMap 來創建原鏈表結點和拷貝鏈表結點之間的映射。在遞歸函數中,首先判空,若爲空,則返回空指針。而後就是去 HashMap 中查找是否已經在拷貝鏈表中存在了該結點,是的話直接返回。不然新建一個拷貝結點 res,而後創建原結點和該拷貝結點之間的映射,而後就是要給拷貝結點的 next 和 random 指針賦值了,直接分別調用遞歸函數便可,參見代碼以下:post

 

解法二:url

class Solution {
public:
    Node* copyRandomList(Node* head) {
        unordered_map<Node*, Node*> m;
        return helper(head, m);
    }
    Node* helper(Node* node, unordered_map<Node*, Node*>& m) {
        if (!node) return nullptr;
        if (m.count(node)) return m[node];
        Node *res = new Node(node->val, nullptr, nullptr);
        m[node] = res;
        res->next = helper(node->next, m);
        res->random = helper(node->random, m);
        return res;
    }
};

 

固然,若是使用 HashMap 佔用額外的空間,若是這道題限制了空間的話,就要考慮別的方法。下面這個方法很巧妙,能夠分爲如下三個步驟:spa

1. 在原鏈表的每一個節點後面拷貝出一個新的節點。指針

2. 依次給新的節點的隨機指針賦值,並且這個賦值很是容易 cur->next->random = cur->random->next。

3. 斷開鏈表可獲得深度拷貝後的新鏈表。

舉個例子來講吧,好比原鏈表是 1(2) -> 2(3) -> 3(1),括號中是其 random 指針指向的結點,那麼這個解法是首先比遍歷一遍原鏈表,在每一個結點後拷貝一個一樣的結點,可是拷貝結點的 random 指針仍爲空,則原鏈表變爲 1(2) -> 1(null) -> 2(3) -> 2(null) -> 3(1) -> 3(null)。而後第二次遍歷,是將拷貝結點的 random 指針賦上正確的值,則原鏈表變爲 1(2) -> 1(2) -> 2(3) -> 2(3) -> 3(1) -> 3(1),注意賦值語句爲:

cur->next->random = cur->random->next;

這裏的 cur 是原鏈表中結點,cur->next 則爲拷貝鏈表的結點,cur->next->random 則爲拷貝鏈表的 random 指針。cur->random 爲原鏈表結點的 random 指針指向的結點,由於其指向的仍是原鏈表的結點,因此咱們要再加個 next,才能指向拷貝鏈表的結點。最後再遍歷一次,就是要把原鏈表和拷貝鏈表斷開便可,參見代碼以下:

 

解法二:

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if (!head) return nullptr;
        Node *cur = head;
        while (cur) {
            Node *t = new Node(cur->val, nullptr, nullptr);
            t->next = cur->next;
            cur->next = t;
            cur = t->next;
        }
        cur = head;
        while (cur) {
            if (cur->random) cur->next->random = cur->random->next;
            cur = cur->next->next;
        }
        cur = head;
        Node *res = head->next;
        while (cur) {
            Node *t = cur->next;
            cur->next = t->next;
            if (t->next) t->next = t->next->next;
            cur = cur->next;
        }
        return res;
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/138

 

參考資料:

Clone Graph

 

相似題目:

https://leetcode.com/problems/copy-list-with-random-pointer/

https://leetcode.com/problems/copy-list-with-random-pointer/discuss/43488/Java-O(n)-solution

https://leetcode.com/problems/copy-list-with-random-pointer/discuss/43567/C%2B%2B-simple-recursive-solution

https://leetcode.com/problems/copy-list-with-random-pointer/discuss/43491/A-solution-with-constant-space-complexity-O(1)-and-linear-time-complexity-O(N)

 

LeetCode All in One 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索