leetcode 链表的合并和分割两道题

1.合并两个有序链表

1.1 题目描述

本题目来源于leetcode 21.合并两个有序链表

image-20211105184854068

提示:

image-20211105184917214

1.2 接口函数

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


struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){

}

1.3 大致框架

1.3.1 思路分析

  1. 新建立一个链表,即建立一个头结点

这里我们要有2个指针,分别都指空

  • 为什么要一个head,因为要返回头指针
  • 为什么要一个tail,因为要方便尾插

image-20211105213113419

  1. 然后数组上下两两比较,小的就依次放在新链表

比较是用一个L1和一个L2指针分别指向原来两个链表的头节点

image-20211105213432658

  1. l1指向下一个指针然后新链表的head不动,tail指针指向这一个节点,即叫做尾指针的意思
    image-20211105213928780
  2. 不断循环,最后当其中一个链表的L1或L2指针指向NULL时,就停止循环
    image-20211105214323018
  3. 最后将剩下来的一个链表连接在新链表后面就可以了

1.3.2 具体步骤

先要防止传进来的而指针是空的

 //注意第一次凡是有空指针也会崩
//如果为空直接返回另外一个就可以了
        if(l1==NULL)
        {
            return l2;
        }
        if(l2==NULL)
        {
            return l2;
        }

这里,头插最好不要放在while循环里面,在循环之前解决掉就可以了

 	   if(l1->val<l2->val)
        {
            head=tail=l1;
            l1=l1->next;
        }
        else
        {
            head=tail=l2;
            l2=l2->next;
        }

while循环不断走直到最后走到由一个指针NULL

 while(l1&&l2)
        {
             //取小的尾插到新链表
            if(l1->val<l2->val)
            {
                tail->next=l1;
                l1=l1->next;
            }
            else
            {
                tail->next=l2;
                l2=l2->next;
            }
            //tail走到新的位置上
             tail=tail->next;
        }

当由一个为空时把另外一个连到新链表上然后,返回头指针

	   //l2为空
        if(l1)
        {
            tail->next=l1;
        }
        //l1为空
        if(l2)
        {
            tail->next=l2;
        }
       return head;

1.4 具体实现

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
         //注意第一次凡是有空指针也会崩
        if(l1==NULL)
        {
            return l2;
        }
        if(l2==NULL)
        {
            return l1;
        }
        struct ListNode* head=NULL;
        struct ListNode* tail=NULL;
        //第一次不要放在循环里面
        if(l1->val<l2->val)
        {
            head=tail=l1;
            l1=l1->next;
        }
        else
        {
            head=tail=l2;
            l2=l2->next;
        }
        while(l1&&l2)
        {
             //取小的尾插到新链表
            if(l1->val<l2->val)
            {
                tail->next=l1;
                l1=l1->next;
            }
            else
            {
                tail->next=l2;
                l2=l2->next;
            }
            //tail走到新的位置上
             tail=tail->next;
        }
        //l2为空
        if(l1)
        {
            tail->next=l1;
        }
        //l1为空
        if(l2)
        {
            tail->next=l2;
        }
        return head;
}

image-20211105221237712

1.5 方法选择

另一个带头节点法:

  1. 设置一个哨兵位头节点

  2. 一样的判断步骤,进行尾插

    这里不能忘记==tail->next=NULL;==避免两个都是空的

    image-20211106092345668

  3. 剩下的步骤同样道理,主要是少一点开始的判断步骤

  4. 注意最后要处理释放之前的节点

 //创建一个哨兵位头节点
        struct ListNode* head=NULL;
        struct ListNode* tail=NULL;
        head =tail=(struct ListNode*)malloc(sizeof(struct ListNode));
        tail->next=NULL;//防止两个都是空的,方便尾插
        while(l1&&l2)
        {
             //取小的尾插到新链表
            if(l1->val<l2->val)
            {
                tail->next=l1;
                l1=l1->next;
            }
            else
            {
                tail->next=l2;
                l2=l2->next;
            }
    
             tail=tail->next;
        }
        //l2为空
        if(l1)
        {
            tail->next=l1;
        }
        //l1为空
        if(l2)
        {
            tail->next=l2;
        }
        struct ListNode* node=head;
        head=head->next;
        free(node);
        return head;

image-20211105221237712

2. 分割链表

2.1 题目描述

这是遇到的第一道难度为中等的题
本题目来源于leetcode 分割链表

image-20211106094320438

提示:

image-20211106094337567

2.2 接口函数

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


struct ListNode* partition(struct ListNode* head, int x){

}

2.3 大致框架

假如给出这样的例子,虽说原题没有要求说顺序不变,但是这里用牛客网的要求做试试看

image-20211106102633422

image-20211106094917442

那么这时我们的答案应该是,因为要求了相对顺序是不能变的,所以最后输出就是这样

image-20211106094959201

2.3.1 思路分析

把小于x的尾插到一个链表,再把大于x的尾插到一个链表,最后连接两个链表

  1. 创建两个哨兵位的头节点,分别创建对应的头尾指针

image-20211106095447485

  1. 分别判断假如该节点的值小于给出的x,就尾插到小数链表,反之大的链表

image-20211106095806017

  1. 当然尾指针要自动跟上,变成尾,走完后会发现大致顺序没有变化

image-20211106095916164

  1. 最后来链接在一起就ok了,终止条件是原链表走完

2.3.2 具体步骤

按照第一次的思路按部就班地做

出现了问题,提示image-20211106101446095

struct ListNode* partition(struct ListNode* head, int x){
struct ListNode* lessHead,*lessTail,*greaterHead,*greaterTail;
    lessHead=lessTail=(struct ListNode*)malloc(sizeof(struct ListNode));
    greaterHead=greaterTail=(struct ListNode*)malloc(sizeof(struct ListNode));
    lessTail->next=NULL;
    greaterTail->next=NULL;
      struct ListNode*cur=head;
      while(cur)
      {
          if(cur->val<x)//只处理<的
          {
            lessTail->next=cur;
            lessTail=lessTail->next;
          }
          else
          {
              greaterTail->next=cur;
               greaterTail=greaterTail->next;
          }
                cur=cur->next;
     }
        //连接两个链表
            lessTail->next=greaterHead->next;
            head=lessHead->next;
            free(lessHead);
            free(greaterHead);
            return head;
}

这样说明出现问题,就要改进一下

一般时间超限原因是出现死循环

内存超限有时候是因为其他原因导致,这道题不是因为这里超过内存复杂度问题,应该想一下极端情况

这个情况是很难想到的,需要多多体会

我们将 greater 的 next指针置空,这是因为当前节点复用的是原链表的节点,而其 next指针可能指向一个小于 x 的节点,这样就会形成,我们需要切断这个引用。

正是因为死循环所以才会报错

image-20211106113534611

解决方法就是把最后一个节点置空

 //关键
greaterTail->next=NULL;

2.4 具体实现

struct ListNode* partition(struct ListNode* head, int x){
   struct ListNode* lessHead,*lessTail,*greaterHead,*greaterTail;
    lessHead=lessTail=(struct ListNode*)malloc(sizeof(struct ListNode));
    greaterHead=greaterTail=(struct ListNode*)malloc(sizeof(struct ListNode));
    lessTail->next=NULL;
    greaterTail->next=NULL;
      struct ListNode*cur=head;
      while(cur)
      {
          if(cur->val<x)//只处理<的
          {
            lessTail->next=cur;
            lessTail=lessTail->next;
          }
          else
          {
            greaterTail->next=cur;
            greaterTail=greaterTail->next;
          }
          cur=cur->next;
     }
        //连接两个链表
            lessTail->next=greaterHead->next;
            //关键
            greaterTail->next=NULL;
            head=lessHead->next;
            free(lessHead);
            free(greaterHead);
            return head;
}

image-20211106114207120

小结:

这道题其实还有多种解法,有兴趣可以看一下多题解

这篇题目就到此为止,大家觉得有收获就请一键三连,谢谢

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

言之命至9012

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

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

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

打赏作者

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

抵扣说明:

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

余额充值