单链表OJ题目——C语言

本篇博客并非提供完整解题思路代码,而是重点阐述在OJ的链表题目中容易被忽视的点,从而让部分读者在出错百思不得解的情况下能快速发现自己的漏洞,高效查缺补漏,本博客支持读者按题搜索,同时也支持读者根据博客内容自行完成题目,这都是比较经典且有坑的题目,还是比较支持读者通读全篇的。

目录

一、203.移除链表元素

1.1忽视头结点

1.2忽视cur->next仍指向原链表

1.3忽视tail为空链表 

 1.4通过代码

 二、876.链表的中间结点

2.1忽略fast->next为NULL 

2.2通过代码 

三、链表中倒数第k个结点

3.1忽视k和链表长度的关系

3.2通过代码 

四、CM11.链表分割 

4.1什么是哨兵位 

4.2忽略最后一个结点

4.3通过代码 

 五、206.反转链表

5.1三指针的初始位置错误

5.2通过代码 

六、21.合并两个有序链表 

6.1通过代码 

七、141.环形链表

7.1忽视判断条件

7.2通过代码

八、142.环形链表 II

8.1通过代码

九、160.相交链表

9.1尾结点的条件判断错误 

9.2通过代码 

十、链表的回文结构

10.1通过代码

 十一、138.随机链表的复制

11.1通过代码


一、203.移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

提示:

  • 列表中的节点数目在范围 [0, 104] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

OJ题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

这个题目我们只提供一种思路,那就是遍历先前的链表,用新链表接收原链表不为 val 的结点。

    struct ListNode* cur = head;
    struct ListNode* newnode = NULL;
    struct ListNode* tail = NULL;

以上就是我们的大致思路,我们来写一下代码:

1.1忽视头结点

其实这里是比较容易能想到的,当我们的Newnode为空时,我们要直接给Newnode赋值,而不是给Newnode的next赋值:

1.2忽视cur->next仍指向原链表

 当我们完成上面的代码并返回Newnode时,我们可以发现除了第一个测试用例不对,剩下两个都对了,这又是为什么呢?

 因为当我们的最后一个值与val相同时,我们看似不会把原链表带到新链表,但是我们忽略了cur是一个结构体,它的next一直没有改变,所以我们看似没有做什么操作但是已经把原链表最后的“6”带到了新链表中,这时应该怎么做呢?

我们重新审视我们的代码,可以发现我们当cur->val != val时进行了操作,但当cur->val == val时没有进行任何操作哦,现在我们可以free一下每一个值为val的结点,再把新链表中最后一个结点置空

1.3忽视tail为空链表 

当我们测试上面的代码时,我们又会发现第二个测试用例出错:

这又是因为什么呢?其实当我们没有修改的时候,我们不存在tail->next = NULL ,但修改之后如果tail是NULL时,这就会出现野指针问题,所以在此之前我们只需要判断一下就可以啦。

 1.4通过代码

struct ListNode* removeElements(struct ListNode* head, int val) 
{
    struct ListNode* cur = head;
    struct ListNode* newnode = NULL;
    struct ListNode* tail = NULL;
    while(cur != NULL)
    {
        if(cur->val != val)
        {
            if(newnode == NULL)
            {
                newnode = cur;
                tail = newnode;
            }
            else
            {
                tail->next = cur;
                tail = tail->next;
            }
              cur = cur->next;  
        }
        else
        {
            struct ListNode* tmp = cur;
            cur = cur->next;
            free(tmp);
            tmp = NULL;
        }    
    }
    if(tail != NULL)
    {
        tail->next = NULL;
    }
    return newnode;
}

 二、876.链表的中间结点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

示例 2:

输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

提示:

  • 链表的结点数范围是 [1, 100]
  • 1 <= Node.val <= 100

OJ题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

本题我们提供双指针解法的忽视点,用fast和slow两个指针遍历链表,fast每次走两步,slow每次走一步,当fast走到头时,slow所在位置为链表中间结点。

所以我们要用fast = fast->next->next、slow = slow->next

2.1忽略fast->next为NULL 

当我们的原链表结点为奇数个时,最后会存在fast->next为NULL的情况,这时fast->next->next就涉及了野指针的问题,我们可以在判断fast的同时判断fast->next是否为空。

2.2通过代码 

struct ListNode* middleNode(struct ListNode* head) 
{
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

三、链表中倒数第k个结点

描述

输入一个链表,输出该链表中倒数第k个结点。

示例1

输入:

1,{1,2,3,4,5}

返回值:

{5}

OJ题目链接:链表中倒数第k个结点_牛客题霸_牛客网

其是这题和我们上题用的方法如出一辙,都是通过两个指针的差值巧妙得出答案,上次我们用了两个指针的倍数关系,这次我们可以使用两个指针的固定距离。

同样定义一个fast指针,一个slow,那么如何让他们相差k个结点呢?

好啦,思路已经写到这里,下面我们一起来看看代码吧!

while(k>0)
    {
        fast = fast->next;
        k--;
    }
    while(fast != NULL)
    {
        fast = fast->next;
        slow = slow->next;
    }

3.1忽视k和链表长度的关系

本来以为天衣无缝的代码可还是报错了,明明自测运行的时候是正确的呀?下面我们来看看错误的测试用例:

我们其实不难看出,我们在写代码时并未想全面k的取值,如果k比链表的长度还要大怎么办? 

我们应该如何判断呢? 

我们如果像这样进行判断,那么有一种情况会被我们忽略,那就是 k == 链表长度时,我们无法返回整个链表,而是返回NULL。

那这样怎么避免呢?我们可以把判断的代码提到循环体的最上面:

简单的一个操作,就可以让我们的题目通过。

3.2通过代码 

四、CM11.链表分割 

描述

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

OJ题目链接:链表分割_牛客题霸_牛客网

我们的思路是创建两个新链表,让他们分别存储小于x和另外的值,最后再链接两个链表。

4.1什么是哨兵位 

我们在做这题之前要了解什么是哨兵位,因为这题如果不设置哨兵位会多很多麻烦。

在我们之前做的题中我们不难发现,当要传入第一个结点时,我们都要判断头结点是否为空,以此来确定是给头结点赋值还是给头结点的next赋值,这就是不带哨兵位的链表,哨兵位其实就是我们动态开辟了一块空间给头结点,这样头结点永远都不会为空

既然头结点永远不会为空,那我们在传值的时候完全可以不用考虑,直接传给phead->next,需要注意的是,在需要返回值时,我们不可以单一的返回phead,而是返回phead->next,另外因为还需要free掉malloc的空间,所以我们得出答案后最好还要用原链表的头结点指向我们的答案,以此来free掉malloc开辟的空间

4.2忽略最后一个结点

其实这和我们1.2出现的错误一样,都是忘记了我们倒数第二个结点的next其实还是指向原链表的,当最后一个结点不满足我们的条件时,倒数第二个结点还是会指向它,所以我们最好的办法就是像1.2那样,将最后一个可能的结点直接置空。

记得要free掉malloc开辟的空间哦~

4.3通过代码 

class Partition 
{
public:
    ListNode* partition(ListNode* pHead, int x) 
    {
       ListNode* newHead1 = (ListNode*)malloc(sizeof(ListNode));
       ListNode* newHead2 = (ListNode*)malloc(sizeof(ListNode));
       ListNode* tail1 = newHead1;
       ListNode* tail2 = newHead2;
       ListNode* cur = pHead;
       while(cur != NULL)
       {
        if(cur->val < x)
        {
            tail1->next = cur;
            tail1 = tail1->next;
        }
        else
        {
            tail2->next = cur;
            tail2 = tail2->next;
        }
        cur = cur->next;
       }
       tail1->next = newHead2->next;
       tail2->next = NULL;
       pHead =  newHead1->next;
       free(newHead1);
       free(newHead2);
       return pHead;
    }
};

 五、206.反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

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

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000  

OJ题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

这题的思路我们可以采用三指针来做,一个指针记录原链表的位置,一个指针记录前一个结点的位置,另一个指针负责遍历整个链表并改变每个结点的指向。

5.1三指针的初始位置错误

我们根据我们的思路写出以上代码,可我们还是通不过, 因为我们知道链表的最后一个结点肯定是NULL,如果按照我们的思路,显然我们没有指向NULL的结点,所以我们要把我们三个指针的位置前移一个结点:

5.2通过代码 

struct ListNode* reverseList(struct ListNode* head) 
{
    if(head == NULL)
    {
        return NULL;
    }
    else
    {
        struct ListNode* prev = NULL;
        struct ListNode* cur = head;
        struct ListNode* next = cur->next;
        while(cur != NULL)
        {
            cur->next = prev;
            prev = cur;
            head = cur;
            cur = next;
            if(next != NULL)
            {
                next = next->next;
            }
        }
        return head;
    }
    
}

六、21.合并两个有序链表 

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列

OJ题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

这题其实没什么坑,只要注意多加判断list1和list2为空时的情况就可以啦,我们一起来看通过代码 

6.1通过代码 

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{
    if(list1 == NULL)
    {
        return list2;
    }
    else if(list2 == NULL)
    {
        return list1;
    }
    else
    {
        struct ListNode* NewNode = (struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode* tail1 = list1;
        struct ListNode* tail2 = list2;
        struct ListNode* cur = NewNode;
        while(tail1 != NULL && tail2 != NULL)
        {
            if(tail1->val < tail2->val)
            {
                cur->next = tail1;
                tail1 = tail1->next;
            }
            else
            {
                cur->next = tail2;  
                tail2 = tail2->next;
            }
            cur = cur->next;
        }       
        if(tail1 == NULL)
        {
            cur->next = tail2;
        }
        else
        {
            cur->next = tail1;
        }
        list1 = NewNode->next;
        free(NewNode);
        return list1;
    }
}

七、141.环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos 为 -1 或者链表中的一个 有效索引 。

OJ题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

这题我们的思路是快慢指针,让快指针的速度是慢指针的二倍,如果这个链表有环,那么他们一定会在环内相遇。

7.1忽视判断条件

根据上面的思路,我们很快就能写出代码,可是我们会得到一个执行出错:

原因是什么呢?我们是要让fast一次走两步,可是当fast->next为NULL时,就会产生野指针的问题,我们只需要将fast->next也列入循环的判断条件就可以啦。

7.2通过代码

bool hasCycle(struct ListNode *head) 
{
    struct ListNode* slow = head;
    struct ListNode*fast = head;
    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
        {
            return true;
        }
    }
    return false;
}

八、142.环形链表 II

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

OJ题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

因为快指针走的距离是慢指针走的距离的二倍,所以我们能得到:L + nC - X = 2( L + C - X )

化简得: X = L + ( n - 1 ) * C

我们再对照一下图就可以得到,如果一个指针从相遇点开始走,一个指针从头开始走,那他们相遇的位置正好会是入环点! 

8.1通过代码

感觉这题并没有什么坑,只是推导会有一些难受,下面我们直接来看通过代码:

struct ListNode *detectCycle(struct ListNode *head) 
{
    struct ListNode* slow = head;
    struct ListNode*fast = head;
    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
        {
            struct ListNode* tail1 = fast;
            struct ListNode* tail2 = head;
            while(tail1 != tail2)
            {
                tail1 = tail1->next;
                tail2 = tail2->next;
            }
            return tail1;
        }
    }
    return NULL;
}

九、160.相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

  • intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
  • listA - 第一个链表
  • listB - 第二个链表
  • skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
  • skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。

 

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。

 

示例 2:

输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。

 

提示:

  • listA 中节点数目为 m
  • listB 中节点数目为 n
  • 1 <= m, n <= 3 * 104
  • 1 <= Node.val <= 105
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listA 和 listB 没有交点,intersectVal 为 0
  • 如果 listA 和 listB 有交点,intersectVal == listA[skipA] == listB[skipB]

OJ题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

我们的思路还是使用双指针,可是如何控制两个指针的差结点呢?

通过对比我们可以知道,我们要得出的是相交结点之前的差值,我们又可以观察出其实相交结点之前的差值就是两链表的差值,这样我们就可以先分别统计两链表的长度,并且可以进一步判断两链表尾结点是否相同来先一步确认是否相交。

再让一个指针先走差值后,启动另一个指针,当他们相同时,就是两链表的交点。 

9.1尾结点的条件判断错误 

我们在上面已经说了我们可以顺便判断尾结点是否相同,那就说明了我们不能再将 tailA 和 tailB 作为循环进行的条件了,因为最后都是NULL,我们无法判断两链表尾结点是否相同,所以在这里我们要将 tail->next 作为循环进行的条件。

9.2通过代码 

下面我们一起来看通过代码:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    struct ListNode* tailA = headA;
    int LenA = 1;
    struct ListNode* tailB = headB;
    int LenB = 1;
    while(tailA->next != NULL)
    {
        tailA = tailA->next;
        LenA++;
    }
    while(tailB->next != NULL)
    {
        tailB = tailB->next;
        LenB++;
    }
    if(tailA != tailB)
    {
        return NULL;
    }
    int count = abs(LenA - LenB);//求绝对值的函数
    struct ListNode* longlist = headA;
    struct ListNode* shortlist = headB;
    if(LenB > LenA)
    {
        longlist = headB;
        shortlist = headA;
    }

    while (count--)
    {
        longlist = longlist->next;
    }
    while (longlist != shortlist)
    {
        longlist = longlist->next;
        shortlist = shortlist->next;
    }

    return longlist;
}

十、链表的回文结构

描述

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

测试样例:

 

OJ题目链接:链表的回文结构_牛客题霸_牛客网

我们可以将链表的后半段逆置,所以这题既用到了寻找中间结点,也用到了逆置链表的方法,我们只需要祭出我们的CV大法就可以轻松解决。

下面我们直接来看代码:

10.1通过代码

class PalindromeList {
public:
//ctrl+v逆置链表的代码
    ListNode* reverseList(struct ListNode* head) 
    {
        if(head == NULL)
        {
            return NULL;
        }
        else
        {
            struct ListNode* prev = NULL;
            struct ListNode* cur = head;
            struct ListNode* next = cur->next;
            while(cur != NULL)
            {
                cur->next = prev;
                prev = cur;
                head = cur;
                cur = next;
                if(next != NULL)
                {
                    next = next->next;
                }
            }
            return head;
        }
        
    }
//ctrl+v寻找中间结点的代码
    ListNode* middleNode(struct ListNode* head) 
    {
        struct ListNode* fast = head;
        struct ListNode* slow = head;
        while(fast != NULL && fast->next != NULL)
        {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
    bool chkPalindrome(ListNode* A) 
    {
        // write code here
        ListNode* mid = middleNode(A);
        ListNode* rA = reverseList(A);
        while(A !=NULL && rA != NULL)
        {
            if(A->val != rA->val)
            {
                return false;
            }
            A = A->next;
            rA = rA->next;
        }
        return true;
    }
};

 十一、138.随机链表的复制

给你一个长度为 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 作为传入参数。

示例 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]]

提示:

  • 0 <= n <= 1000
  • -104 <= Node.val <= 104
  • Node.random 为 null 或指向链表中的节点。

OJ题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

就目前来说,这题最好的方法就是先复制结点,把每个结点都对应放在原链表结点的后面,当我们要复制random时,其对应的就是原链表random指向结点的下一个结点。

如图,这样插入后我们再进行random的寻找就不用再遍历整个链表了,时间复杂度从O(N^2)简化到了O(N),在写代码过程中,要进行random指向的判断,有可能为NULL,也有可能是它本身。

11.1通过代码

struct Node* copyRandomList(struct Node* head) 
{
        struct Node* cur = head;
        while(cur != NULL)
        {
            struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
            copy->val = cur->val;

            copy->next = cur->next;
            cur->next = copy;

            cur = copy->next;
        }

        cur = head;
       
        while(cur != NULL)
        {
            struct Node* copy = cur->next;
            if(cur->random == NULL)
            {
                copy->random = NULL;
            }
            else
            {
                copy->random = cur->random->next;
            }
            cur = copy->next;
        }
        struct Node* newhead = NULL;
        struct Node* tail = NULL;
        cur = head;
        while(cur != NULL)
        {   
            struct Node* copy = cur->next;
            struct Node* next = copy->next;
            if(tail == NULL)
            {
                newhead = tail = copy;
            }
            else
            {
                tail->next = copy;
                tail = tail->next;
            }
            cur->next = next;
           cur = next;
        }
        return newhead;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/144148.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安装pr缺少wmvcore.dll的解决方法,分享4个有效的方法

在当今数字化时代&#xff0c;计算机软件在我们的生活中扮演着重要的角色。然而&#xff0c;有时候我们可能会遇到一些软件问题&#xff0c;其中之一就是缺少某个关键的动态链接库文件。在这篇文章中&#xff0c;我将分享关于如何解决Adobe Premiere Pro&#xff08;PR&#xf…

【官宣】守护四年,“惠医保”暖心回归!

11月13日&#xff0c;惠州参保人专属的城市定制型商业健康险——“惠医保2024”正式升级上线&#xff0c;面向全市基本医保参保人开放参保&#xff0c;超200万保障&#xff0c;150元/人/年起&#xff01; 惠州市医疗保障局、惠州市卫生健康局、惠州市金融工作局及国家金融监督…

c#桥接模式详解

基础介绍&#xff1a; 将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。适用于不希望在抽象和实现部分之间有固定的绑定关系的情况&#xff0c;或者类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充的情况。 将抽象部分与实现部分分离&#xff0c;…

C语言中自己实现了一个排序为什么会比 qsort 的速度慢几十倍不止

C语言中自己实现了一个排序&#xff0c;为什么会比 qsort 的速度慢几十倍不止? 讲到算法&#xff0c;有一个非常重要的前置知识叫时间复杂度&#xff0c;脱离了这个讲算法的优劣是没什么意义的。这个概念主要是指&#xff0c;你数据量的增加&#xff0c;会让算法的处理时间增加…

mini型光学3D表面轮廓仪,上车即走,上桌即用!

“小身材&#xff0c;大作用”——一个简单的比喻&#xff0c;恰当地总结了SuperView WM100光学3D表面轮廓仪的特点。mini型光学3D表面轮廓仪SuperView WM100&#xff0c;回应了市场对小型化、便携式光学3D表面轮廓仪的需求。 轻便的机身&#xff0c;简约的设计——没有控制箱…

element el-upload上传功能

2023.11.14今天我学习了如何使用el-upload: <!--drag设置可拖动--><!--accept".xlsx"设置上传的文件类型--><!--:limit1上传文件的最大个数--><!--:auto-upload"false"是否在选取后直接上传--><!--:before-upload"beforeU…

cout的输出整数格式

cout默认以十进制格式显示整数 cout << oct和cout << hex不会显示出来&#xff0c;而只是修改cout显示整数的方式 使用std::hex和std::oct时&#xff0c;可以将hex和oct当做变量名&#xff0c;否则不可以 #include<iostream>int main() {int a;std::cout &l…

高并发场景下,如何设计订单库存架构,一共9个关键性问题

库存系统可以分为实物库存和虚拟库存两种类型。实物库存的管理涉及到采购、存储、销售和库存轮换等复杂的活动&#xff0c;需要进行供应链管理和仓库管理等工作。相比之下&#xff0c;虚拟库存的管理相对简单&#xff0c;主要适用于线上资源的数量管理&#xff0c;包括各类虚拟…

安装部署Esxi7.0并创建虚拟机

1. Esxi介绍 ESXI虚拟平台是VMware出品的一个强大平台&#xff0c;它可以直接安装在物理机上&#xff0c;从而充分利用物理奖性能&#xff0c;虚拟多个系统出来。ESXI是一个带WEB管理后台的软件&#xff0c;非常适合安装在服务器上&#xff0c;然后直接通过网页进行远程管理。…

发布自研大模型 夸克App将迎来全面升级

国产大模型阵营再添新锐选手。11月14日&#xff0c;阿里巴巴智能信息事业群发布全栈自研、千亿级参数的夸克大模型&#xff0c;将应用于通用搜索、医疗健康、教育学习、职场办公等众多场景。夸克App将借助自研大模型全面升级&#xff0c;加速迈向年轻人工作、学习、生活的AI助手…

分享一下微信会员充值管理系统怎么做

在当今数字化时代&#xff0c;微信作为中国最流行的社交平台&#xff0c;其功能已经从简单的沟通交流扩展到了生活的方方面面。微信会员充值管理系统就是其中之一&#xff0c;它为商家提供了一个高效、便捷的充值体验&#xff0c;同时也为用户提供了更加个性化的服务。本文将详…

操作系统——死锁(一文详解死锁,死锁产生的原因和死锁的解决方案)

1、什么是死锁&#xff1f;死锁产生的条件&#xff1f; 1.1、什么是死锁&#xff1f; 答&#xff1a; 在两个或者多个并发进程中&#xff0c;如果每个进程持有某种资源而又等待其它进程释放它或它们现在保持着的资源&#xff0c;在未改变这种状态之前都不能向前推进&#xff…

22款奔驰C260L升级小柏林音响 全新15个扬声器 提升音乐效果

奔驰新款C级号称奔驰轿车的小“S”&#xff0c;在配置方面上肯定也不能低的&#xff0c;提了一台低配的车型&#xff0c;通过后期升级加装件配置提升更高档次&#xff0c;打造独一无二的奔驰C级&#xff0c;此次来安排一套小柏林之声音响&#xff0c;效果怎么样&#xff0c;我们…

bclinux aarch64 ceph 14.2.10 对象存储 http网关 CEPH OBJECT GATEWAY Civetweb

相关内容 bclinux aarch64 ceph 14.2.10 文件存储 Ceph File System, 需要部署mds&#xff1a; ceph-deploy mds-CSDN博客 ceph-deploy bclinux aarch64 ceph 14.2.10【3】vdbench fsd 文件系统测试-CSDN博客 ceph-deploy bclinux aarch64 ceph 14.2.10【2】vdbench rbd 块设…

独立站邮件营销大佬,手把手教你如何做好!

做独立站邮件营销的方式&#xff1f;独立站怎么做邮件营销&#xff1f; 邮件营销&#xff0c;作为独立站营销的重要手段之一&#xff0c;越来越受到卖家的重视。如何才能做好邮件营销呢&#xff1f;蜂邮EDM将手把手教你如何做好独立站邮件营销&#xff0c;让你在电商领域中更上…

银行转账p图手机软件,实现回执单截图生成,用Swing或JavaFX实现

其实总体用了很少的代码&#xff0c;就是模版图框架代码实现&#xff0c;模版也是网上的&#xff0c;非常多总体实现的原理还是绘图功能&#xff0c;捕捉用户输入。 用户界面 (UI): 我们可以使用Swing或JavaFX来创建一个窗口界面&#xff0c;允许用户输入所需的信息。 数据处理…

Sui上TVL突破1.28亿美金,浅谈DeFi续创新高背后的基础知识

根据财富商业洞察研究&#xff0c;DeFi市场预计从2022年的555.8亿美元增长到2030年的3370.4亿美元。推动这一增长的活动包括对token的交易、借贷和借款&#xff0c;这通常是点对点的&#xff0c;无需传统金融机构的参与。随着Sui网络于今年五月份启动主网和其SUI token&#xf…

MCU常见通信总线串讲(五)—— CAN总线协议

&#x1f64c;秋名山码民的主页 &#x1f602;oi退役选手&#xff0c;Java、大数据、单片机、IoT均有所涉猎&#xff0c;热爱技术&#xff0c;技术无罪 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 获取源码&#xff0c;添加WX 目录 前言一…

【原创】java+swing+mysql车辆维修管理系统设计与实现

摘要&#xff1a; 车辆维修管理系统是一个用于管理和追踪车辆维修过程的系统&#xff0c;它能够提高效率&#xff0c;减少错误&#xff0c;并提供详细的车辆历史记录&#xff0c;可以帮助车辆维修企业实现信息化管理&#xff0c;提高工作效率和客户满意度&#xff0c;降低运营…

生成式AI:压缩与加密的新方式

目前围绕生成式AI的大部分讨论都纯粹集中在结果上&#xff1a;你可以与它交谈&#xff0c;你可以生成艺术作品和视频&#xff0c;它可以生成声音。 这些都是非凡的成就。 然而&#xff0c;我相信&#xff0c;如果你以几种方式重新构建生成式AI&#xff0c;你会得到一些非常有趣…