ソードフィンガーオファー35.複雑なリンクリスト(C ++)のスプライシング+スプリッティングのコピー

複雑なリンクリストをコピーするには、copyRandomList関数を実装してください。複雑なリンクリストでは、各ノードには次のノードへの次のポインターと、リンクリスト内の任意のノードまたは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を超えません。

注:この質問は、メインサイトの138の質問と同じです:https://leetcode-cn.com/problems/copy-list-with-random-pointer/

スプライシング+スプリット

元のノード1->新しいノード1->元のノード2->新しいノード2->……のスプライスされたリンクリストを作成することを検討してください。これにより、元のノードのランダムポインティングノードにアクセスしているときに、新しいノードを見つけることができます。新しいノードに対応するランダムポインティングノード。
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します

複雑さの分析:

時間計算量O(N):O(N)時間を使用した、リンクリストの3ラウンドのトラバース。
スペースの複雑さO(1):ノード参照変数は一定量の余分なスペースを使用します。

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/
class Solution {
    
    
public:
    Node* copyRandomList(Node* head) {
    
    
        if(head == nullptr) return nullptr;
        Node* cur = head;
        // 1. 复制各节点,并构建拼接链表
        //拼接成7->7->3->3->1->1->0->0->2->2
        while(cur != nullptr) {
    
    
            Node* tmp = new Node(cur->val);
            tmp->next = cur->next;
            cur->next = tmp;
            cur = tmp->next;
        }
        // 2. 构建各新节点的 random 指向
        cur = head;
        while(cur != nullptr) {
    
    
            if(cur->random != nullptr)
            //以图片中的第一个“3”的节点为例
            //第一个“3”->next就是第二个“3”
            //第二个“3”->random = 第一个“3”->random(第一个“7”)->next,
            //而(第一个“7”)->next就是第二个“7”
                cur->next->random = cur->random->next;
            cur = cur->next->next;
        }
        // 3. 拆分两链表
        cur = head->next;//cur和res起点一样,新的链表就是cur生成的链表
        Node* pre = head, *res = head->next;
        while(cur->next != nullptr) {
    
    
            pre->next = pre->next->next;//pre->next->next表示删除pre->next
            cur->next = cur->next->next;
            pre = pre->next;//遍历到下一个节点
            cur = cur->next;
        }
        pre->next = nullptr; // 单独处理原链表尾节点----切断链表
        return res;      // 返回新链表头节点
    }
};

おすすめ

転載: blog.csdn.net/qq_30457077/article/details/114704997