力扣刷题15

第一题:合并两个有序链表

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

先明确一下题目的要求,有两个升序排列的单链表,要求合并后得到一个新的升序链表,不修改原链表节点值,仅仅调整节点的next指向。我想到的方法是迭代法和递归法,经过我的不懈努力,我把代码写出来了。

先展示代码,我把知识点写在一起。

迭代法:

python 复制代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        # 建立一个虚拟头节点,方便操作
        dummy = ListNode(-1)
        current = dummy
        
        # 遍历两个链表,每次选较小的节点接上
        while list1 and list2:
            if list1.val <= list2.val:
                current.next = list1
                list1 = list1.next
            else:
                current.next = list2
                list2 = list2.next
            current = current.next
        
        # 把剩下的节点直接接上
        current.next = list1 if list1 else list2
        
        return dummy.next

递归法:

python 复制代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        if not list1:
            return list2
        if not list2:
            return list1
        
        if list1.val <= list2.val:
            list1.next = self.mergeTwoLists(list1.next, list2)
            return list1
        else:
            list2.next = self.mergeTwoLists(list1, list2.next)
            return list2

迭代法的核心是"搭架子+逐个选小节点拼接",类比生活中合并两个有序的排队队伍:

1、先摆一个"空排头",也就是我设的虚拟头节点,避免处理第一个节点选谁的难题;

2、用一个指针指着当前队伍的末尾,负责接下一个节点;

3、两个队伍的排头对比,把较小的那个接到当前队伍末尾,然后该队伍排头后移;

4、重复步骤3,直到其中一个队伍空了;

5、把剩下的那个非空队伍直接接到当前队伍末尾,本身已经有序,无需再对比;

6、最后的结果是空排头的下一个节点,也就是要跳过排头。

用例子模拟一下:以 list1 = [1,3,5],list2 = [2,4,6]为例。

1、初始:dummy(-1) -> None,current指向dummy,list1指向1,list2指向2;

2、第一次循环:1 < 2 -> current.next=1,list1移到3,current移到1;

3、第二次循环:3 > 2 ->current.next = 2,list2移到4,current移到2;

4、第三次循环:3 < 4 -> current.next = 3,list1移到5,current移到3;

5、第四次循环:5 > 4 -> current.next = 4,list2移到6,current移到4;

6、第五次循环:5 < 6 -> current.next = 5,list1移到None,current移到5;

7、list1为空,循环结束,current.next = list2,也就是剩下的数字6;

8、最终结果:dummy(-1) -> 1 -> 2 -> 3 -> 4 -> 5 -> 6,返回dummy.next即1开头的链表。

分析一下时间复杂度:O(m + n),n和m分别是两个链表的节点数,每个节点仅仅被访问一次。


递归法:

核心思路:把大问题拆成小问题,直到触达终止条件。

当前问题:合并list1和list2,得到一个升序链表。

拆分子问题:

1、对比list1.val和list2.val,选较小的节点作为当前层的结果节点;

2、该节点的next,指向"该节点的下一个节点"和"另一个链表的当前节点";

3、终止条件:如果list1为空,直接返回list2;如果list2为空,直接返回list1。

用示例进行模拟验证:以 list1 = [1,3,5],list2 = [2,4,6]为例。

1、第一层调用:merge(1->3->5,2->4->6) -> 1 < 2 -> 1.next = merge(3->5,2->4->6),返回1;

2、第二层调用:merge(3->5,2->4->6) -> 3 > 2 ->2.next = merge(3->5,4->6),返回2;

3、第三层调用:merge(3->5,4->6) -> 4 > 3 ->3.next = merge(5,4->6),返回3;

4、第四层调用:merge(5,4->6) -> 5 > 4 ->4.next = merge(5,6),返回4;

5、第五层调用:merge(5,6) -> 6 > 5 ->5.next = merge(None,6),返回5;

6、第六层调用:merge(None,6) -> 触发终止条件,返回6;

7、递归回溯:从第六层开始,依次给上一层的next赋值,最终拼接成结果。

分析一下时间复杂度:O(m + n),n和m分别是两个链表的节点数,每个节点仅仅被访问一次。


ok,写完收工。

相关推荐
2301_817497331 小时前
C++中的装饰器模式高级应用
开发语言·c++·算法
m0_549416662 小时前
C++编译期字符串处理
开发语言·c++·算法
m0_581124192 小时前
C++中的适配器模式实战
开发语言·c++·算法
A尘埃2 小时前
零售连锁店生鲜品类销量预测——线性回归(Linear Regression)
算法·线性回归·零售
u0109272712 小时前
C++与人工智能框架
开发语言·c++·算法
Fleshy数模2 小时前
从欠拟合到正则化:用逻辑回归破解信用卡失信检测的召回率困境
算法·机器学习·逻辑回归
im_AMBER2 小时前
Leetcode 111 两数相加
javascript·笔记·学习·算法·leetcode
TracyCoder1232 小时前
LeetCode Hot100(21/100)——234. 回文链表
算法·leetcode·链表
可涵不会debug2 小时前
Redis魔法学院——第四课:哈希(Hash)深度解析:Field-Value 层级结构、原子性操作与内部编码优化
数据库·redis·算法·缓存·哈希算法