劍指 Offer 35. 複雜連結串列的複製

RainsX發表於2021-09-14

劍指 Offer 35. 複雜連結串列的複製

請實現 copyRandomList 函式,複製一個複雜連結串列。在複雜連結串列中,每個節點除了有一個 next 指標指向下一個節點,還有一個 random 指標指向連結串列中的任意節點或者 null。

示例 1:

輸入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
輸出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例 2:

輸入:head = [[1,1],[2,1]]
輸出:[[1,1],[2,1]]

示例 3:

輸入:head = [[3,null],[3,0],[3,null]]
輸出:[[3,null],[3,0],[3,null]]

示例 4:

輸入:head = []
輸出:[]
解釋:給定的連結串列為空(空指標),因此返回 null。

提示:

  • -10000 <= Node.val <= 10000
  • Node.random 為空(null)或指向連結串列中的節點。
  • 節點數目不超過 1000 。

首先說明解題思路的時候,先簡單說一下這個題主要是讓返回的值是你自行復制的連結串列,也就是說可以採用暴力解法、雜湊表或者開闢一個空間來建立一個連結串列讓它進行返回,當然直接return head肯定不行。

一、暴力解法

這個暴力解法在LeetCode裡面提交題解的時候,提示超出了時間限制,然後看了K神的程式碼以後,發現還可以再精簡完善一些。

class Solution {
    public Node copyRandomList(Node head) {
        if(head==null) return null;
        ArrayList<Node> list = new ArrayList<>();
        while(head!=null){
            list.add(head);
            head = head.next;
        }

       //建立結果集合並初始化
        ArrayList<Node> res = new ArrayList<>();
        for(int i = 0;i<list.size();++i){
            res.add(new Node(list.get(i).val));
        }
       //設定結果結合的 random和next
        for (int i = 0; i < list.size(); ++i) {
            res.get(i).random = list.get(i).random == null?null:res.get(list.indexOf(list.get(i).random));
            if(i!=list.size()-1) res.get(i).next = res.get(i+1);
        }

        return res.get(0);
    }
}

二、雜湊表

這裡主要的難點在看懂構建新連結串列的引用指向:

  • 構建新節點的next和random引用指向
  • cur遍歷原連結串列到下一個節點
class Solution {
    public Node copyRandomList(Node head) {
        if (head == null) return null;
        Node cur = head;
        Map<Node,Node> res = new HashMap<>();
        while(cur != null) {//遍歷連結串列,並儲存每個節點的新節點
            res.put(cur, new Node(cur.val));
            cur = cur.next;
        }
        cur = head;//重置cur
        while (cur != null) {
            res.get(cur).next = res.get(cur.next);//用cur.next指向res.get(cur).next
            res.get(cur).random = res.get(cur.random);//用cur.random指向res.get(cur).random
            cur = cur.next;
        }
        return res.get(head);//返回頭結點是因為新連結串列的頭結點也存著在res中
    }
}

三、遞迴

這個做題思路類似於dfs,建立一個節點之後,接著通過遞迴的方式建立他的next節點……(參考連結見下面)

class Solution {
    public Node copyRandomList(Node head) {
        //map儲存已經建立的節點
        HashMap<Node, Node> map = new HashMap<>();
        return copyListHelper(head, map);
    }
public Node copyListHelper(Node head, HashMap<Node, Node> map) {
    if (head == null)
        return null;
    //如果節點建立了,直接從map中取
    if (map.containsKey(head))
        return map.get(head);
    //如果節點沒有建立,就建立一個,然後使用遞迴的方式在建立他的
    //next節點和random節點
    Node res = new Node(head.val);
    map.put(head, res);
    res.next = copyListHelper(head.next, map);
    res.random = copyListHelper(head.random, map);
    return res;
    }
}

參考連結:

https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/9plk45/

https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/solution/shu-ju-jie-gou-he-suan-fa-di-gui-he-fei-wby85/

相關文章