剑指Offer: 复杂链表的复制

剑指Offer: 复杂链表的复制

题目描述

请实现一个函数可以复制一个复杂链表。

在复杂链表中,每个结点除了有一个指针指向下一个结点外,还有一个额外的指针指向链表中的任意结点或者null。

注意

  • 函数结束后原链表要与输入时保持一致。

算法 暴力求解

双重for循环的主要目的是查找random节点的位置
分为两步实现:

  1. 根据next指针新建链表
  2. 双重for循环,每次查找到一个random节点,就重新遍历查找其位置
时空分析

时间复杂度: 时间复杂度 O(n^2)

C++ 代码
/**
 * Definition for singly-linked list with a random pointer.
 * struct ListNode {
 *     int val;
 *     ListNode *next, *random;
 *     ListNode(int x) : val(x), next(NULL), random(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *copyRandomList(ListNode *head) {
        ListNode* newList = new ListNode(-1);
        auto nextNode = newList;

        //第一步,根据next指针新建链表
        for (auto node = head; node; node = node->next) {
            ListNode* newNode = new ListNode(node->val);
            nextNode->next = newNode;
            nextNode = nextNode->next;
        }

        // 第二步,双重for循环,每次查找到一个random节点,就重新遍历查找其位置
        for (auto curNode = newList->next, node = head; curNode && node; ) {
            if (node->random) {
                auto r_curNode = newList->next, r_node = head;
                while (r_node != node->random && r_node) {
                    r_curNode = r_curNode->next;
                    r_node = r_node->next;
                }
                curNode->random = r_curNode;
            }
            curNode = curNode->next;
            node = node->next;
        }

        return newList->next;
    }
};

算法 使用hash表求解

分两步来实现:

  1. 建立原链表和目标链表的对应关系,存储到hash表中
  2. 遍历原链表,查看random节点,根据hash表中存储的对应关系,建立目标链表的random节点关系
时空分析

时间复杂度: 时间复杂符 O(n)

空间复杂符: 需要申请额外空间存放哈希表映射 O(n)

C++ 代码
/**
 * Definition for singly-linked list with a random pointer.
 * struct ListNode {
 *     int val;
 *     ListNode *next, *random;
 *     ListNode(int x) : val(x), next(NULL), random(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *copyRandomList(ListNode *head) {
        unordered_map<ListNode*, ListNode*> hash;
        ListNode* newList = new ListNode(-1);
        auto nextNode = newList;

        // 第一步,建立原链表和目标链表的对应关系,存储到hash表中
        for (auto node = head; node; node = node->next) {
            ListNode* newNode = new ListNode(node->val);
            nextNode->next = newNode;
            hash.insert({node, newNode});
            nextNode = nextNode->next;
        }

        // 第二步,遍历原链表,查看random节点,根据hash表中存储的对应关系,
        // 建立目标链表的random节点关系
        for (auto node = head; node; node = node->next) {
            if (node->random) {
                auto curNode = hash[node];
                curNode->random = hash[node->random];
            }
        }

        return newList->next;
    }
};

算法 并行求解

主要思路是通过复制链表的方式,来解决random节点的查找问题。大体可以分为三步:

  1. 链表所有节点中间都插入一个复制节点,作为并行链表
  2. 遍历新链表,遇到Random节点后对应改变并行链表中的节点
  3. 提取出并行链表
时空分析

时间复杂度: 时间复杂度 O(n)

C++ 代码
/**
 * Definition for singly-linked list with a random pointer.
 * struct ListNode {
 *     int val;
 *     ListNode *next, *random;
 *     ListNode(int x) : val(x), next(NULL), random(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *copyRandomList(ListNode *head) {
        for (auto p = head; p;)
        {
            auto np = new ListNode(p->val);
            auto next = p->next;
            p->next = np;
            np->next = next;
            p = next;
        }

        for (auto p = head; p; p = p->next->next)
        {
            if (p->random)
                p->next->random = p->random->next;
        }

        auto dummy = new ListNode(-1);
        auto cur = dummy;
        for (auto p = head; p; p = p->next)
        {
            cur->next = p->next;
            cur = cur->next;
            p->next = p->next->next;
        }

        return dummy->next;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Erice_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值