• 21. Merge Two Sorted Lists


    1. 原始题目

    Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

    Example:

    Input: 1->2->4, 1->3->4
    Output: 1->1->2->3->4->4

    2. 题目理解

    合并两个排序的链表,使得结果仍然是排序的。

    坑:输入为空链表单独处理。

    3. 解题之前:Python实现链表基础功能

    在解题之前,我想先实现一下python中的链表,这样方便在本地调试。实现链表的基础功能,例如:添加,插入,删除,查找,打印。

    思路:首先定义每个结点类型。在leetcode中,大都是如下的类型:(python中没有指针。所以实现节点时,用一个简单类就好。该节点包含数据和“指针next”。)

    1) 结点定义

    class ListNode:
         def __init__(self, x):
             self.val = x             # 存放数据
             self.next = None         # 存放该结点的下一个结点的地址(其实就是当前结点.next = 下一个结点)

    2)链表实现

     1 class ListNode_handle:               # 链表操作类型
     2     def __init__(self, node):
     3          self.head = node            # 该类需要初始化头节点和当前节点。即用一个链表的头结点来实例化,可以用ListNode_handle(None)来实例化一个空链表
     4          self.cur_node = node 
     5         
     6         
     7     def add(self, data):             # 添加结点操作,该结点的数值为data
     8         node = ListNode(None)        # 新建ListNode类型
     9         node.val = data
    10         node.next = None
    11         if self.head == None:        # 若当前链表为空,则直接将其作为头结点
    12             self.head = node
    13             self.cur_node = node
    14         else:                        # 否则将该结点连到后面,将当前结点更新 
    15             self.cur_node.next = node
    16             self.cur_node = self.cur_node.next
    17         return self.head
    18     
    19     
    20     def insert_i(self, i, data):     # 在第i个位置插入一个数值为data的结点  
    21         node = ListNode(None)
    22         node.val = data
    23         node.next = None
    24         
    25         curr_node = self.head
    26         for j in range(i-1):         # 索引到位置i 
    27             curr_node = curr_node.next
    28         node.next = curr_node.next
    29         curr_node.next = node
    30              
    31         
    32     def delete_i(self,i):            # 删除位置为i的结点
    33         
    34         curr_node = self.head
    35         for j in range(i-1):         # 索引到位置为i的结点
    36             curr_node = curr_node.next
    37         curr_node.next = curr_node.next.next
    38 
    39 
    40     def print_node(self,node):       # 从头开始打印所有结点的数值
    41         while node:
    42             print(node.val, end=' ')
    43             node = node.next
    44         print(end='
    ')
    45         
    46         
    47     def find_node(self, value):      # 寻找链表中是否存在数值value  
    48         if self.head == None:
    49             return False
    50         else:
    51             node = self.head
    52             while(node):
    53                 if node.val == value:
    54                     return True
    55                 else:
    56                     node = node.next
    57             return False

    好了,以上就是链表操作类型。如果要新建一个结点对象,就实例化类 ListNode。 如果要新建一个链表对象,就实例化类 ListNode_handle。

    3)为了演示方便,我们将题目中的两个链表建立起来:

    # 新建链表1
    listnode1 = ListNode_handle(None)
    s1 = [1,2,4]
    for i in s1:
        listnode1.add(i)
    listnode1.print_node(listnode1.head)

    打印:1 2 4 

    # 新建链表2
    listnode2 = ListNode_handle(None)
    s2 = [1,3,4]
    for i in s2:
        listnode2.add(i)
    listnode2.print_node(listnode2.head)

    打印:1 3 4

    好了,下面正式进入正题,实现两个有序链表的合并。

    4. 解法

    1) 传统解法

    思路:先定义一个头结点p,然后两个指针同时指向l1和l2,比较谁更小,更小者赋给p,然后指针后移。到最后如果有哪个链表不为空,则直接将其连在已排序好的链表末尾。注意,无需新建空链表,只在原有基础上链接。注意对输入为空链表情况的处理。

     1 class Solution:
     2     def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
     3         if l1 == None:
     4             return l2
     5         if l2 == None:
     6             return l1
     7         p = ListNode(0)
     8         q = p
     9         while l1 and l2:
    10             if (l1.val<l2.val):
    11                 p.next = l1
    12                 l1 = l1.next
    13             else:               # 小坑: 注意这里不可将 else 替换为 if(l1.val>=l2.val),if else是非a即b,而两个if语句则可能同时满足条件。。。
    14                 p.next = l2
    15                 l2 = l2.next
    16             p = p.next
    # 如果合并之后有链表还不为空,则直接将其连在排好序的链表之后
    17 if l1 : # 小技巧:这一下几句可以合并为 p.next = l1 or l2 18 p.next = l1 19 if l2: 20 p.next = l2 21 22 return q.next # 因为第一个结点是最开始定义的一个无效结点(头结点) 而这里我们一般不需要头结点存储额外信息,链表的第一个结点就是有意义的第一个结点

    2)Leetcode和剑指offer里给出了递归的解法:

    因为有重复的步骤,是典型的递归过程。

     1 class Solution:
     2 
     3     def mergeTwoListsRecursion(self, l1: ListNode, l2: ListNode) -> ListNode:
     4         if l1 == None:
     5             return l2
     6         if l2 == None:
     7             return l1
     8         p = ListNode(0)   
     9 
    10         if(l1.val<l2.val):
    11             p = l1
    12             p.next = self.mergeTwoListsRecursion(l1.next, l2)
    13         else:
    14             p = l2
    15             p.next = self.mergeTwoListsRecursion(l1, l2.next)
    16         
    17         return p 

    5. 验证合并结果

    我们将合并后的链表打印出来,看看是否满足我们的预期:

    1 # 合并两个有序链表
    2 s = Solution()
    3 newlist_head = s.mergeTwoLists(listnode1.head, listnode2.head)      # 非递归
    4 #newlist_head = s.mergeTwoListsRecursion(listnode1.head, listnode2.head)         # 递归
    5 newlist = ListNode_handle(newlist_head)         # 递归或者非递归返回的都是表头,所以可以直接用第一个结点来实例化类 ListNode_handle
    6 newlist.print_node(newlist.head)     # 打印该链表

    结果: 1 1 2 3 4 4 

    6. 验证其他功能

     1 # 查找值为3的结点是否存在
     2 print(newlist.find_node(3))
     3 
     4 # 在链表第三个位置插入666
     5 newlist.insert_i(3,666)
     6 newlist.print_node(newlist.head)
     7 
     8 # 删除链表第三个位置的元素
     9 newlist.delete_i(3)
    10 newlist.print_node(newlist.head)

    True
    1 1 2 666 3 4 4
    1 1 2 3 4 4



  • 相关阅读:
    python中的json
    vmware workstation中的NAT配置
    python内置的一些模块
    datetime
    线程池的工作过程示例
    java io read中申请读的长度与实际长度不同|RocketMQ源码
    RocketMQ集群搭建及安装rocketmq-console
    使用MAT分析JVM内存溢出
    jdbcTemplate小用总结
    Spring线程安全为何非安全,场景重现,解决安全小结
  • 原文地址:https://www.cnblogs.com/king-lps/p/10654834.html
Copyright © 2020-2023  润新知