刷爆leetcode第五期 0016

发布于:2022-10-12 ⋅ 阅读:(386) ⋅ 点赞:(0)

刷爆leetcode第五期 0016

编号0016 复制带随机指针的链表

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/copy-list-with-random-pointer

在这里插入图片描述

讲真的 看到这个题目的第一眼 头疼!

咋有这么多字捏 完全不想看

但是没办法啊 硬着头皮读吧

我用三句话把这个题目解释下

1 有一个链表 链表的节点有三个结构组成 两个指针 一个值

2 两个指针一个指向下一个节点 一个指向一个随机节点

3 我们要拷贝一份这个链表 但是不能改变它的结构

好的 读完了 下机!

才怪 开始想思路

还是一样 我们先看图
在这里插入图片描述
往后找的倒是简单 只要记住它们的相对位置 然后往后面走x步就可以了

在这里插入图片描述

但是往前的呢?

还是要记住它们的相对位置然后从前往后开始遍历= =

woc 这时间复杂度不直接上O(N*N)了

想想就不想写了 下机!

顺手去翻翻评论区

这里就发现了一种很巧妙的解法

在这里插入图片描述

我们先照抄题目给我们的链表写出一个类似的链表出来 (值全部传递)

之后我们将这个单链表插入到题目给我们的链表的下一位去

这样子我们看看 如果是找随机值的话

13的随机值是指向7的

想要找到7我们只需要找到它的下一个位置就可以了! 妙啊!

但是这里有个特殊情况哈

如果随机值是指向NULL的 我们直接赋值NULL就可以了!

也就是加一行代码的事

我们先来看看细节怎么样

在这里插入图片描述

首先我们先来复制这个链表除了随机值以外的其他部分

    // 先创建一个新链表 新链表除了随机值之外一切都相同 
    struct Node* newhead = NULL;
    struct Node* newtail = NULL;
    struct Node* cur = head;
    while(cur)
    {
        if(newhead==NULL)
        {
            newhead=newtail=BUYSList();
            newhead->val = cur->val;
        }
        else
        {
            newtail->next=BUYSList();
            newtail=newtail->next;
            newtail->val = cur->val;
        }
        cur=cur->next;
    }
    newtail->next=NULL;

这样子我们就完成了一个单链表的简单拷贝(无随机值)

现在我们执行插入操作

在这里插入图片描述
我们这里使用cur遍历 下面的链表
使用next记录下面的下一位

使用newcur遍历 上面的链表
使用newnext继续下面链表的下一位

在这里插入图片描述
在这里插入图片描述

上代码

    //按照我们的方式链接两个链表
    cur = head;
    struct Node* next = head;
    struct Node* newcur = newhead;
    struct Node* newnext = newhead;

    while(cur) //画图判断下是否cur指向空指针的时候结束
    {
        // next都往前进一
        next=next->next;
        newnext=newnext->next;

        //开始链接
        cur->next = newcur;
        newcur->next = next;

        //迭代
        cur = next;
        newcur = newnext;
    }

接下来我们就可以开始遍历整个链表赋值随机值了

赋值方式如下图

在这里插入图片描述

    //准备工作完毕 开始赋值随机值 
    cur = head;
    next = head;
    while(cur)
    {
        next=cur;
        next=next->next;
        if(cur->random==NULL)
        {
            next->random=NULL;
        }
        else
        {
            next->random = cur->random->next;
        }
        cur = next->next;
    }

**这里要注意的一点是 我们要找清楚需要赋随机值的位置 **

全部赋完随机值之后我们就可以开始将这两个链表解开了

画图表示如下

在这里插入图片描述
代码表示如下

    // 分开两个链表 
    cur = head;
    next = head;
    while(cur->next)
    {
        // next往前走
        next=next->next;

        //cur链接原来链表的位置
        cur ->next = next->next;

        // 迭代
        cur = next;
    }

以上我们就完成啦

我们来试试看能不能通过

在这里插入图片描述
过啦

那么这就是本题的时间复杂度0(N)的解法啦

所有代码表示如下

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */
struct Node* BUYSList(void)
 {
    struct Node* newnode =(struct Node*)malloc(sizeof(struct Node));
    return newnode;
 }

struct Node* copyRandomList(struct Node* head) 
{
    if(head==NULL)
    {
        return NULL;
    }
    // 先创建一个新链表 新链表除了随机值之外一切都相同 
    struct Node* newhead = NULL;
    struct Node* newtail = NULL;
    struct Node* cur = head;
    while(cur)
    {
        if(newhead==NULL)
        {
            newhead=newtail=BUYSList();
            newhead->val = cur->val;
        }
        else
        {
            newtail->next=BUYSList();
            newtail=newtail->next;
            newtail->val = cur->val;
        }
        cur=cur->next;
    }
    newtail->next=NULL;

    //按照我们的方式链接两个链表
    cur = head;
    struct Node* next = head;
    struct Node* newcur = newhead;
    struct Node* newnext = newhead;

    while(cur) //画图判断下是否cur指向空指针的时候结束
    {
        // next都往前进一
        next=next->next;
        newnext=newnext->next;

        //开始链接
        cur->next = newcur;
        newcur->next = next;

        //迭代
        cur = next;
        newcur = newnext;
    }

    //准备工作完毕 开始赋值随机值 
    cur = head;
    next = head;
    while(cur)
    {
        next=cur;
        next=next->next;
        if(cur->random==NULL)
        {
            next->random=NULL;
        }
        else
        {
            next->random = cur->random->next;
        }
        cur = next->next;
    }

    // 分开两个链表 
    cur = head;
    next = head;
    while(cur->next)
    {
        // next往前走
        next=next->next;

        //cur链接原来链表的位置
        cur ->next = next->next;

        // 迭代
        cur = next;
    }

    return newhead;
	
}

网站公告

今日签到

点亮在社区的每一天
去签到