LeetCode刷题——单链表进阶(详细图解)

这次的题目是LeetCode刷题——单链表(详细图解)进阶版有兴趣的朋友可以看一看

温馨提示:
做数据结构题的时候一定要多画图,考虑到特殊情况。

1、复制带随机指针的链表

在这里插入图片描述
知道整体思路后敲出代码就不难了

整体思路
1️⃣创建n个拷贝空间,依次和原链表相连。
2️⃣给random赋地址。
3️⃣把拷贝链表和原链表断开,单独返回拷贝链表。


①创建结点
在这里插入图片描述

这里要注意判断原链表为空的情况

②链接结点
在这里插入图片描述
③random



在这里插入图片描述
先看第一个拷贝结点,从图中直接看他应该指向NULL,所以①的random指向NULL,这种情况应该特殊处理
再看第二个拷贝结点,通过原结点看②应该指向①,那么用代码如何表示呢?
假设val为13的结点的指针为p

在这里插入图片描述
那么①的结点就可以表示为 p->random->next

④链接拷贝结点后返回

在这里插入图片描述

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */

struct Node* copyRandomList(struct Node* head) {
    if(head == NULL)
    {
        return NULL;
    }
	struct Node* cur = head;
    //链接拷贝结点
    while(cur)
    {
        struct Node* next = cur->next;
        struct Node* tmp = (struct Node*)malloc(sizeof(struct Node));
        tmp->val = cur->val;
        cur->next = tmp;
        tmp->next = next;
        cur = next;
    }
    //random
    cur = head;
    while(cur)
    {
        struct Node* next = cur->next;
        //要考虑NULL情况
        if(cur->random == NULL)
        {
            next->random = NULL;
        }
        else
        {
            next->random = cur->random->next;
        }
        cur = next->next;
    }
    //链接拷贝结点
    cur = head->next;
    //只有一个结点
    if(cur->next == NULL)
    {
        return cur;
    }
    struct Node* next = cur->next->next;
    struct Node* tmp = cur;
    while(next->next)
    {
        cur->next = next;
        cur = next;
        next = cur->next->next;
    }
    cur->next = next;
    return tmp;
}


2、对链表进行插入排序

在这里插入图片描述

关于插入排序,如图所示:
在这里插入图片描述
知道流程以后就可以考虑大致框架和特殊情况思考

我们的大致框架是先把第一个结点当作已经排序好的头,然后把后面的结点依次插入排序。

写出插入排序不难,但是有些特殊情况要考虑到

1️⃣链表为空
2️⃣要插入的数字比头还要小
3️⃣要插入的元素是最大的数字(要排到最后)

①当链表为空,返回NULL。


②当要插入的数字比头还要小
在这里插入图片描述
插入完后

在这里插入图片描述
③要插入的元素是最大的数字(要排到最后)
如果发现是到最后都没有插进去,直接让最后一个元素指向要插入的元素,要插入的元素在指向NULL。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* insertionSortList(struct ListNode* head){
    if(head == NULL && head->val == NULL)
    {
        return head;
    }
    struct ListNode* sorthead = head, *cur = head->next;
    head->next = NULL;
    while(cur)
    {
        struct ListNode* next = cur->next;
        //是不是头结点
        if(cur->val < sorthead->val)
        {
            cur->next = sorthead;
            sorthead = cur;
        }
        else
        {
            struct ListNode* p = sorthead, *pre = NULL;
            while(p)
            {
                if(cur->val < p->val)
                {
                    pre->next = cur;
                    cur->next = p;
                    break;
                }
                pre = p;
                p = p->next;
            }
            if(p == NULL)
            {
                pre->next = cur;
                cur->next = NULL;
            }
        }
        cur = next;
    }
    return sorthead;
}

在这里插入图片描述
几个指针存在的意义:
cur : 要依次往后遍历知道所有元素插入排序
next : 方便cur找到下一个位置
pre : 为了能插入(插入元素要找到前后位置)
p : 既为了能插入,也是判断结点有没有插入进去(循环结束p不为NULL就说明已经插入完,没有就说明要插入的元素是最大的)



3、删除排序链表中的重复元素Ⅰ

在这里插入图片描述

题目给定条件是已经排好序,那么就说明相同元素一定排在一起
那么就比较容易了,用两个指针

在这里插入图片描述

如果cur和next相同,让next往后跳,直到不相同,再让cur移动到next,重复上述操作
在这里插入图片描述
要注意的是后面全是一样也就是next直接走到空的情况,所以要判断next是否为空

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* deleteDuplicates(struct ListNode* head){
    struct ListNode* cur = head;
    while(cur)
    {
        struct ListNode* next = cur->next;
        while(next && cur->val == next->val)
        {
            next = next->next;
        }
        cur->next = next;
        cur = next;
    }
    return head;

}


4、删除排序链表中的重复元素Ⅱ

在这里插入图片描述
这道题跟上一道的区别是这道题只要有相同的元素就把所有这个元素的结点都删除。
为了删除后链表跟前面的相连,所以这道题比上一道题多了个指针。

大致思想:
用cur和next俩指针迭代往后走,碰到相同的就让next往后走,再让cur走到next,删除掉前面相同的结点,再用prev链接

在这里插入图片描述
一些特殊情况

1️⃣有可能前面几个是相同的,此时prev是空,无法使用,头结点就要换位置
2️⃣所有元素都是相同的,所以就用next判断是否结束循环

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* deleteDuplicates(struct ListNode* head){
    if(head == NULL)
    {
        return NULL;
    }
    struct ListNode* cur = head, *next = cur->next, *prev = NULL;
    while(next)
    {
        if(cur->val == next->val)
        {
            while(next && cur->val == next->val)
            {
                next = next->next;
            }
            //删除
            while(cur != next)
            {
                struct ListNode* del = cur;
                cur = cur->next;
                free(del);
            }
            if(prev == NULL)
            {
                head = cur;
            }
            else
            {
                prev->next = cur;
            }
            if(next)
            {
                next = next->next;
            }
        }
        else
        {
            //迭代
            prev = cur;
            cur = next;
            next = next->next;
        }
    }
    
    return head;
}
  • 44
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 73
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 73
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

命由己造~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值