ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-11-06 12:03:32  阅读:192  来源: 互联网

标签:ListNode struct next 链表 tail l2 两道 l1 leetcode


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

小结:

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

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

标签:ListNode,struct,next,链表,tail,l2,两道,l1,leetcode
来源: https://blog.csdn.net/Allen9012/article/details/121171870

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有