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='\n')
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



posted @ 2019-04-04 14:51  三年一梦  阅读(528)  评论(1编辑  收藏  举报