leetcode#21两个有序链表的合并

5 篇文章 0 订阅
3 篇文章 0 订阅
这篇博客详细介绍了如何解决LeetCode中的第21题,即合并两个有序链表。作者提供了两种解法,一种是直观的循环解法,利用辅助链表在遍历过程中比较并合并两个链表;另一种是递归解法,通过递归调用来实现合并。两种方法的时间复杂度均为O(n),空间复杂度分别为O(1)和O(n)。博客内容涵盖了算法思路、代码实现和复杂度分析,并给出了递归解法的思路图。
摘要由CSDN通过智能技术生成

leetcode#21两个有序链表的合并

一.题目

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:

输入:l1 = [], l2 = []
输出:[]
示例 3:

输入:l1 = [], l2 = [0]
输出:[0]
提示:两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按非递减顺序 排序

二.解法:用一个辅助链表

2.1直观循环解法:

由于链表的遍历不能回头,所以我采取使用辅助链表,在两个链表遍历的时候通过比较,将较小的一个插到辅助链表。这样只需用l1l2和辅助链表通过一次遍历实现合并。

2.1.1复杂度分析

时间复杂度:对于每个数据做一次比较插入O(n)
空间复杂度:只需两个指针的空间O(1)

2.1.2代码
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode() : val(0), next(nullptr) {}
*     ListNode(int x) : val(x), next(nullptr) {}
*     ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
  ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
      if(l1==NULL)
  return l2;
       if(l2==NULL)
      return l1;//特殊
      
      ListNode* head;//初始化
      if((l1->val)<=(l2->val))
      {head=l1;
      l1=l1->next;
      }
      else 
      {head=l2;
      l2=l2->next;//若不更新则可能造成next再次指向自己,编译器报错
      }//为了避免这种情况,l1l2的第一个val相等时,赋值与插入应选不同的l
      ListNode* end=head;
      while(l2!=NULL&&l1!=NULL)//插入
      {
          
          if((l1->val)<(l2->val))
        {  end->next=l1;
          l1=l1->next;}
          else
          {
           end->next=l2;
          l2=l2->next;
          }
          end=end->next;
      }
      if(l2==NULL)
        end->next=l1;
          else
           end->next=l2;
      
      return head;

  }
};

2.2递归解法

可以看出,我们的解法在不断重复“对比插入移动”的动作,
那么我们可以考虑用递归实现合并。
在这里插入图片描述
图片来源:leetcode腐烂的橘子:一看就会,一写就废?详解递归
通过倒着思考倒着画图
可以看出,导火索是其中一个I1或l2为空,重复的步骤是返回那个值较小的节点的指针。

2.2.1复杂度分析

如何计算递归的时间复杂度和空间复杂度呢? 力扣对此进行了 详细介绍 ,其中时间复杂度可以这样计算:

递归的时间复杂度

给出一个递归算法,其时间复杂度 O ( T ) {\mathcal{O}(T)} O(T) 递归调用的数量,记作 R {R} R 计算的时间复杂度 O ( s ) {\mathcal{O}(s)} O(s)那么 O ( T ) = R ∗ O ( s ) O(T)=R∗O(s) O(T)=RO(s)

该题的时间复杂度: O ( n ) {\mathcal{O}}(n) O(n)

分析:m,n 为 l1和 l2 的元素个数。递归函数每次去掉一个元素,直到两个链表都为空,因此 R = m + n R=m+n R=m+n在递归函数中只进行了 next 指针的赋值操作,计算的时间复杂度为 O ( 1 ) O(1) O(1)故递归的总时间复杂度为 O ( T ) = R ∗ O ( 1 ) = O ( n ) {\mathcal{O}(T) = R * \mathcal{O}(1)}={\mathcal{O}}( n) O(T)=RO(1)=O(n)

空间复杂度

计算整个算法的辅助空间单元的个数
调用的空间中储存常量级数据则 O ( 1 ) O(1) O(1)
调用的空间中储存n个数据则 O ( n ) O(n) O(n)
调用的空间中储存n^2个数据则 O ( n 2 ) O(n^2) O(n2)

该题的空间复杂度

O ( n ) O(n) O(n)

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (l1 == NULL) {
            return l2;
        }
        if (l2 == NULL) {
            return l1;
        }
        if (l1->val <=l2->val)//使用递归不会有2.1.1中next指自己的情况
         {
            l1->next = mergeTwoLists(l1->next, l2);//因为这一步将它本身排除了
            return l1;
         }
         else 
        {
        l2->next = mergeTwoLists(l1, l2->next);
        return l2;
        }
    }
};

参考来源:
递归的解法:
作者:z1m
链接:link

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值