Python算法题集_两数相加
- 题2:两数相加
- 1. 示例说明
- 2. 题目解析
- - 题意分解
- - 优化思路
- - 测量工具
- 3. 代码展开
- 1) 标准求解【直接相加】
- 2) 改进版一【对齐链表】
- 3) 改进版二【数组求和】
- 4. 最优算法
本文为Python算法题集之一的代码示例
题2:两数相加
1. 示例说明
-
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0] 输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 输出:[8,9,9,9,0,0,0,1]
提示:
- 每个链表中的节点数在范围
[1, 100]
内 0 <= Node.val <= 9
- 题目数据保证列表表示的数字不含前导零
- 每个链表中的节点数在范围
2. 题目解析
- 题意分解
- 本题为两个链表结构的数字求和
- 本题的主要计算有2处,1是链表遍历,2是数字求和
- 基本的解法是循环,链表1读一遍,链表2读一遍,所以基本的时间算法复杂度为O(m+n)
- 优化思路
-
通常优化:减少循环层次
-
通常优化:增加分支,减少计算集
-
通常优化:采用内置算法来提升计算速度
-
分析题目特点,分析最优解
-
链表1、链表2按顺序求和计算是标准的方式
-
如果对链表1、链表2的数据进行位置对齐,代码维护性会更好,性能也可能可以提升
-
可以用列表结构进行合并再转换为链表,看看效果
-
- 测量工具
- 本地化测试说明:LeetCode网站测试运行时数据波动很大,因此需要本地化测试解决这个问题
CheckFuncPerf
(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块- 本题很难超时,本地化超时测试用例自己生成,详见【最优算法章节】
3. 代码展开
1) 标准求解【直接相加】
链表直接求和,性能表现不错
性能优异,超越92
import CheckFuncPerf as cfp
def addTwoNumbers_base(l1, l2):
result = ListNode()
sumtmp = 0
lastnode = ListNode()
result.next = lastnode
while 1:
sumtmp = (l1.val + l2.val + sumtmp) // 10
valtmp = (l1.val + l2.val + sumtmp) % 10
now = ListNode(valtmp)
sumtmp = sumtmp
lastnode.next = now
lastnode = lastnode.next
l1 = l1.next or ListNode(0)
l2 = l2.next or ListNode(0)
if (l1.next is None
and l2.next is None
and not sumtmp
and l1.val == 0
and l2.val == 0):
break
return result.next.next
result = cfp.getTimeMemoryStr(Solution.addTwoNumbers_base, head1, head2)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 运行结果
函数 addTwoNumbers_base 的运行时间为 158.03 ms;内存使用量为 16644.00 KB 执行结果 = <__main__.ListNode object at 0x000002115CF31860>
2) 改进版一【对齐链表】
将两个链表先对齐后,再进行求和
马马虎虎,超过69%
import CheckFuncPerf as cfp
def addTwoNumbers_ext1(l1, l2):
head = newnode = ListNode()
len1, len2 = 0, 0
l1_copy, l2_copy = l1, l2
while l1.next:
len1 += 1
l1 = l1.next
while l2.next:
len2 += 1
l2 = l2.next
if len1 > len2:
for iIdx in range(len1 - len2):
l2.next = ListNode(0)
l2 = l2.next
elif len2 > len1:
for iIdx in range(len2 - len1):
l1.next = ListNode(0)
l1 = l1.next
sumtmp = 0
while l1_copy:
valtmp = l1_copy.val + l2_copy.val + sumtmp
sumtmp = valtmp // 10
valtmp = valtmp % 10
newnode.next = ListNode(valtmp)
newnode = newnode.next
l1_copy = l1_copy.next
l2_copy = l2_copy.next
if sumtmp == 1:
newnode.next = ListNode(1)
return head.next
result = cfp.getTimeMemoryStr(Solution.addTwoNumbers_ext1, head1, head2)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 运行结果
函数 addTwoNumbers_ext1 的运行时间为 129.03 ms;内存使用量为 16640.00 KB 执行结果 = <__main__.ListNode object at 0x000002115DF766D8>
3) 改进版二【数组求和】
将链表转换为数组,再求和转为链表,性能下降比较厉害
马马虎虎,超过66%
import CheckFuncPerf as cfp
def addTwoNumbers_ext2(l1, l2):
if l1 is None:
return l2
elif l2 is None:
return l1
list1, list2 = [], []
while l1:
list1.insert(0, l1.val)
l1 = l1.next
while l2:
list2.insert(0, l2.val)
l2 = l2.next
num1, iunit = 0, 1
for iIdx in range(len(list1)):
num1 += list1[-iIdx-1] * iunit
iunit *= 10
num2, iunit = 0, 1
for iIdx in range(len(list2)):
num2 += list2[-iIdx-1] * iunit
iunit *= 10
num3 = num1 + num2
list3 = str(num3)
num3Node = ListNode(-100)
headNode = num3Node
for iIdx in range(len(list3)):
num3Node.next = ListNode(int(list3[-iIdx-1]))
num3Node = num3Node.next
return headNode.next
result = cfp.getTimeMemoryStr(Solution.CheckFuncPerf, head1, head2)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 运行结果
函数 addTwoNumbers_ext2 的运行时间为 8411.89 ms;内存使用量为 17080.00 KB 执行结果 = <__main__.ListNode object at 0x000002115DF76358>
4. 最优算法
根据本地日志分析,最优算法为第2种addTwoNumbers_ext1
import random
nums1 = [random.randint(0, 9) for x in range(100000)]
nums2 = [random.randint(0, 9) for x in range(100000)]
def generateOneLinkedList(data):
head = ListNode(-100)
current_node = head
for num in data:
new_node = ListNode(num)
current_node.next = new_node
current_node = new_node
return head.next, new_node
head1, tail1 = generateOneLinkedList(nums1)
head2, tail2 = generateOneLinkedList(nums2)
result = cfp.getTimeMemoryStr(Solution.addTwoNumbers_base, head1, head2)
print(result['msg'], '执行结果 = {}'.format(result['result']))
# 算法本地速度实测比较
函数 addTwoNumbers_base 的运行时间为 158.03 ms;内存使用量为 16644.00 KB 执行结果 = <__main__.ListNode object at 0x000002115CF31860>
函数 addTwoNumbers_ext1 的运行时间为 129.03 ms;内存使用量为 16640.00 KB 执行结果 = <__main__.ListNode object at 0x000002115DF766D8>
函数 addTwoNumbers_ext2 的运行时间为 8411.89 ms;内存使用量为 17080.00 KB 执行结果 = <__main__.ListNode object at 0x000002115DF76358>
一日练,一日功,一日不练十日空
may the odds be ever in your favor ~