Python算法题集_两数相加

本文为Python算法题集之一的代码示例

题2:两数相加

1. 示例说明

  • 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

    请你将两个数相加,并以相同形式返回一个表示和的链表。

    你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

    示例 1:

    img

    输入: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. 题目解析

- 题意分解

  1. 本题为两个链表结构的数字求和
  2. 本题的主要计算有2处,1是链表遍历,2是数字求和
  3. 基本的解法是循环,链表1读一遍,链表2读一遍,所以基本的时间算法复杂度为O(m+n)

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 链表1、链表2按顺序求和计算是标准的方式

    2. 如果对链表1、链表2的数据进行位置对齐,代码维护性会更好,性能也可能可以提升

    3. 可以用列表结构进行合并再转换为链表,看看效果


- 测量工具

  • 本地化测试说明: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 ~

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长孤秋落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值