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

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

1.合并两个有序链表

1.1 题目描述

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

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

提示:

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

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,因为要方便尾插

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

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

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

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

  1. l1指向下一个指针然后新链表的head不动,tail指针指向这一个节点,即叫做尾指针的意思
    leetcode 链表的合并和分割两道题
  2. 不断循环,最后当其中一个链表的L1或L2指针指向NULL时,就停止循环
    leetcode 链表的合并和分割两道题
  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;
}

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

1.5 方法选择

另一个带头节点法:

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

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

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

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

  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;

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

2. 分割链表

2.1 题目描述

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

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

提示:

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

2.2 接口函数

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


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

}

2.3 大致框架

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

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

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

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

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

2.3.1 思路分析

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

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

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

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

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

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

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

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

2.3.2 具体步骤

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

出现了问题,提示leetcode 链表的合并和分割两道题

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 的节点,这样就会形成,我们需要切断这个引用。

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

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

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

 //关键
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;
}

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

小结:

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

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

上一篇:js leetcode 21. 合并两个有序链表


下一篇:L1-044 稳赢