Python算法题集_合并两个有序链表
- 题21:合并两个有序链表
- 1. 示例说明
- 2. 题目解析
- - 题意分解
- - 优化思路
- - 测量工具
- 3. 代码展开
- 1) 标准求解【直接合并】
- 2) 改进版一【列表合并】
- 3) 改进版二【递归大法】
- 4. 最优算法
本文为Python算法题集之一的代码示例
题21:合并两个有序链表
1. 示例说明
-
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 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. 题目解析
- 题意分解
- 本题为两个单项链表带顺序合并
- 本题的主要计算有2处,1是链表遍历,2是元素比较
- 基本的解法是单层循环,链表1、链表2依次添加,所以基本的时间算法复杂度为O(m+n)
- 优化思路
-
通常优化:减少循环层次
-
通常优化:增加分支,减少计算集
-
通常优化:采用内置算法来提升计算速度
-
分析题目特点,分析最优解
-
由于链表已经排序,因此从左侧进行比较合并是常规做法
-
可以使用列表将链表节点排序后连接,性能下降,但是可维护性提升
-
可以搬出递归大法,但是超时测试就不行了,因为递归的层次有上限【之前的算法已经出现过,好像是990层】
-
- 测量工具
- 本地化测试说明:LeetCode网站测试运行时数据波动很大,因此需要本地化测试解决这个问题
CheckFuncPerf
(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块- 超时测试用例文件是官网的,已上传到CSDN,地址在这里:力扣算法题超时测试用例:缺失的第一个正数,数组长度10W
- 本题很难超时,本地化超时测试用例自己生成,详见【最优算法章节】
3. 代码展开
1) 标准求解【直接合并】
列表节点依次比较合并,其实是性能最高的
依次合并,超过60%
import CheckFuncPerf as cfpclass Solution:@staticmethoddef mergeTwoList_base(list1, list2):if not list1:return list2if not list2:return list1if list1.val <= list2.val:icurval = list1.valnodenew = list1list1 = list1.nextelse:icurval = list2.valnodenew = list2list2 = list2.nextnodestep = nodenewwhile list1 and list2:if list1.val <= list2.val:if list1.val == icurval:icurval = list1.valnodestep.next = list1list1 = list1.nextelse:if list2.val == icurval:icurval = list2.valnodestep.next = list2list2 = list2.nextnodestep = nodestep.nextif not list1:nodestep.next = list2if not list2:nodestep.next = list1return nodenewresult = cfp.getTimeMemoryStr(Solution.mergeTwoList_base, head1, head2)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 运行结果
函数 mergeTwoList_base 的运行时间为 80.02 ms;内存使用量为 4.00 KB 执行结果 = 1
2) 改进版一【列表合并】
采用列表排序和并,代码简洁易维护,不过性能下降
注意:即使原始链表未排序,此代码一样能合并称为排序链表
性能优良,超过80%
import CheckFuncPerf as cfpclass Solution:@staticmethoddef mergeTwoList_ext1(list1, list2):if list1 is None:return list2elif list2 is None:return list1listNode = []while list1:listNode.append([list1.val, list1])list1 = list1.nextwhile list2:listNode.append([list2.val, list2])list2 = list2.nextsorted_note = sorted(listNode, key=lambda x: x[0])for iIdx in range(len(sorted_note)-1):sorted_note[iIdx][1].next = sorted_note[iIdx+1][1]return sorted_note[0][1]result = cfp.getTimeMemoryStr(Solution.mergeTwoList_ext1, head1, head2)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 运行结果
函数 mergeTwoList_ext1 的运行时间为 206.05 ms;内存使用量为 1228.00 KB 执行结果 = 1
3) 改进版二【递归大法】
采用递归大法进行排序,代码更简洁,但是递归有限制,反而不如列表更好维护
性能优良,超过80%
import CheckFuncPerf as cfpclass Solution:@staticmethoddef mergeTwoList_ext2(list1, list2):if list1 is None:return list2elif list2 is None:return list1elif list1.val < list2.val:list1.next = Solution.mergeTwoList_ext2(list1.next, list2)return list1else:list2.next = Solution.mergeTwoList_ext2(list1, list2.next)return list2result = cfp.getTimeMemoryStr(Solution.mergeTwoList_ext2, head1, head2)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 运行结果
Traceback (most recent call last):......
RecursionError: maximum recursion depth exceeded in comparison
4. 最优算法
根据本地日志分析,最优算法为第1种mergeTwoList_base
import random
nums1 = [random.randint(1, 1000000) for x in range(100000)]
nums2 = [random.randint(1, 1000000) for x in range(100000)]
nums1.sort()
nums2.sort()
def generateOneLinkedList(data):head = ListNode(-100)current_node = headfor num in data:new_node = ListNode(num)current_node.next = new_nodecurrent_node = new_nodereturn head.next, new_node
head1, tail1 = generateOneLinkedList(nums1)
head2, tail2 = generateOneLinkedList(nums2)
result = cfp.getTimeMemoryStr(Solution.mergeTwoList_base, head1, head2)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 6种算法本地速度实测比较
函数 mergeTwoList_base 的运行时间为 80.02 ms;内存使用量为 4.00 KB 执行结果 = 1
函数 mergeTwoList_ext1 的运行时间为 206.05 ms;内存使用量为 1228.00 KB 执行结果 = 1
Traceback (most recent call last): 【mergeTwoList_ext2报错】......
RecursionError: maximum recursion depth exceeded in comparison
一日练,一日功,一日不练十日空
may the odds be ever in your favor ~