单链表leetcode刷题/中(C语言版)

目录

题目1:合并两个有序链表 

题目2:分割链表

题目3:随机链表的复制


“单链表leetcode刷题/上”的链接:https://blog.csdn.net/2302_80297338/article/details/140409360?spm=1001.2014.3001.5501

题目1:合并两个有序链表

e87d7423e5f8409da60c165dcaf32a76.png

 解题思路:
        创建一个新链表,比较两个原链表的结点val值大小,小的尾插到新链表中,然后比较当前结点val小的链表中的下一个结点和当前结点val大的链表的同一结点。即遍历比较两个原链表每个结点的大小,小的尾插到新链表中,直到一个原链表已经全部遍历完结束。

        然后将还有一个原链表的剩余结点直接尾插到新链表后面,题目解决。

代码:

typedef struct ListNode listnode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    //小的就尾插在后面
    //一个为空,以及两个都是空的情况
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    //全都不为空的情况
    listnode* l1,*l2;
    l1=list1;
    l2=list2;
    listnode* newhead,*newtail;
    newhead=newtail=(listnode*)malloc(sizeof(listnode)); //创造一个头结点,作为新链表的头
    while(l1&&l2)
    {
        if(l1->val<l2->val)
        {
            newtail->next=l1;
            l1=l1->next;
        }
        else
        {
            newtail->next=l2;
            l2=l2->next;
        }
        newtail=newtail->next;
    }
    if(l2)//l2还有值
    {
        newtail->next=l2;
    }
    if(l1)
    {
        newtail->next=l1;
    }
    listnode* ret=newhead->next;
    free(newhead);
    newhead=NULL;
    return ret;
}

代码讲解:

        为了方便,笔者通过typedef将struct ListNode类型变为了listnode。

        情况1:list1、list2有一个是空链表。

        情况2:list1、list2两者都是空链表。

        情况3:list1、list2两者都不是空链表。

        针对情况1,可以使用两个if语句,如果某者为空,就直接返回不为空的链表。

        针对情况2,情况1的代码即可有效解决。

        针对情况3,整体思路上文已经解析完毕。在开辟完newhead这个结点后,理应将它free置空,防止内存泄露的出现。

ab9278e468834e49b96527064983de38.png

题目2:分割链表

dd8528d38db4480799efcf60444119bd.png

解题思路:

        开辟两个新链表,一个专门用来存比x小的值,一个专门用来存比x大于或等于的值。再创建一个指针pcur,遍历原链表。

        遍历完原链表以后,让大的新链表的尾元结点的next置为NULL,然后将小的链表和大的链表链接起来。

        最后对开辟的两个指针进行free操作,最后返回结果。

代码:

typedef struct ListNode listnode;
struct ListNode* partition(struct ListNode* head, int x){
    if(head==NULL)
    {
        return head;
    }
    listnode* smallhead,*smalltail;
    listnode* largehead,*largetail;
    listnode* pcur = head;
    smallhead=smalltail=(listnode*)malloc(sizeof(listnode));
    largehead=largetail=(listnode*)malloc(sizeof(listnode));
    while(pcur)
    {
        //两种尾插
        if(pcur->val<x)
        {
            smalltail->next=pcur;
            smalltail=smalltail->next;
        }
        else
        {
            largetail->next=pcur;
            largetail=largetail->next;
        }
        pcur=pcur->next;
    }
    largetail->next=NULL;
    smalltail->next=largehead->next;
    listnode* ret=smallhead->next;
    free(smallhead);
    free(largehead);
    return ret;
}

代码讲解:

        本题有使用到头节点的思想,两个新链表的开辟,开辟的都是头节点。后续的数据全都通过尾插进行,所以返回的时候要返回头结点的下一个结点。同时,因为存放数据小的链表和存放数据大的链表已经链接在一起了,所以只需要返回数据小的链表的首元结点,即可满足题目要求。

8b0015b1e60149cbb26eb5ad8cfd945a.png

题目3:随机链表的复制

1c119f73dcd54a5797b2ac9e43126f4b.png

8967247c9f75434eb88e36d4e2647808.png

解题思路:

        复制每一个结点(除最后一个空指针外),链接到每两个结点中间(或空指针和尾元结点之间)。具体如图一所示。

        让每一个复制好的结点的random指向原链表被复制结点的random所指向的结点的next。具体如图二所示。

        通过尾插的办法,让原链表和复制结点组成的链表分开,将复制结点组成的链表变成一个新链表,返回新链表的首元结点,题目解决。时间复杂度能够控制在O(n)以下。

d44fe61b44234c4e8a3149f1ca8a9b28.jpg

图一

85ca0911106d493cbf36d897024f1b4c.jpg

 图二

代码:

typedef struct Node node;


struct Node* copyRandomList(struct Node* head) {
    if(head ==NULL)
    {
        return head;
    }
    node* pcur=head;
    node* newnode;
    while(pcur)
    {
        node* newnode=(node*)malloc(sizeof(node));
        newnode->val=pcur->val;
        newnode->next=pcur->next;
        pcur->next=newnode;
        pcur=pcur->next->next;
    }

    pcur=head;
    node* copy=head->next;
    while(pcur)
    {
        if(pcur->random == NULL)
        {
            copy->random = NULL;
        }
        else
        {
            copy->random=pcur->random->next;
        }
            pcur=copy->next;
        if(pcur)
        {
            copy=pcur->next;
        }    
    }
    if(head->next->next)
{
    node* newhead,*newtail;
    pcur=newhead=head->next;
    newtail=pcur->next->next;
    while(newtail->next)
    {
        pcur->next=newtail;
        pcur=newtail;
        newtail=newtail->next->next;
    }
    pcur->next=newtail;
    return newhead;
}
    else{
        return (head->next);
    }
}

代码讲解:

        题设说明了,可能会出现空链表的情况。如果是空链表,那么就直接返回该链表。

        开创新的结点,复制原结点的val值进去,插在原链表的两个结点中间。每次完成该操作以后,pcur往后走两个结点(一个结点是newnode、一个结点是原链表中的pcur所在结点的下一个结点)。

        然后开始对random进行操作。当原链表某一被复制结点的random指向NULL,那么对应的复制节点的random也指向NULL。结束该操作以后,让pcur和copy同时往后走。

        最后进行尾插操作,要分为只有一个结点的原链表、有两个及两个以上结点的原链表这两种情况。

        对于只有一个结点的原链表,直接返回首元结点的下一个结点即可。

        对于有两个及两个以上结点的原链表,通过尾插代码,完成操作,返回复制节点所组成的新链表的首元结点即可。

2b88049184ee48e9be0e200c889362a0.png

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值