题目
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers
示例
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
解法
题中要求采用链表去做,最普通的链表形式就是数据+地址,每一个链表节点的数据后面都跟着下一个节点的地址。在C语言里我们可以用指针+地址来实现链表,在python中我们可以用标签+类来实现链表,因为类的实例化对象对应的是一个地址,而标签名则起到指针的作用,python中允许多个标签对应同一个地址,且修改其中一个标签对应的值时,另外一个标签对应的值也会变化。(注意:1. 是修改,不是重新赋值。2. 对整型数据修改不能产生这种效果。)
class ListNode(object):
'''
定义链表节点
'''
def __init__(self, x):
self.val = x
self.next = None
class Solution(object):
def addTwoNumbers(self, l1, l2):
carry = 0 # 进位
sum = ListNode(0) # 和链表
res = sum # 和链表的首地址
while l1 or l2: # 两链表非空时开始循环
if l2 == None: # l2链表某一位为空时,和链表对应为为l1链表与进位之和
sumNext = ListNode(0)
sum.next = sumNext
sum_real = (l1.val + carry)
sum.val = sum_real % 10
carry = sum_real // 10
l1 = l1.next
s=sum
sum = sum.next
elif l1 == None: # l1链表某一位为空时,和链表对应为为l2链表与进位之和
sumNext = ListNode(0)
sum.next = sumNext
sum_real = (l2.val + carry)
sum.val = sum_real % 10
carry = sum_real // 10
l2 = l2.next
s=sum
sum = sum.next
else:
sumNext = ListNode(0)
sum.next = sumNext
sum_real = (l1.val + l2.val + carry)
sum.val = sum_real % 10
carry = sum_real // 10
l1 = l1.next
l2 = l2.next
s=sum # s指向和链表的倒数第二位
sum = sum.next
if carry: # 判断l1和l2链表相加是否产生新位
sum.val = 1 # 产生新位,和链表最后一位写1
else:
s.next = None # 未产生新位,修改和链表的倒数第二位为最后一位
return res # 返回和链表的首地址
if __name__ == '__main__':
sol = Solution()
l1 = ListNode(2) # 定义l1链表
l1.next = l11 = ListNode(4)
l11.next = l12 = ListNode(5)
l2 = ListNode(3) # 定义l2链表
l2.next = l21 = ListNode(6)
l21.next = l22 = ListNode(9)
res = sol.addTwoNumbers(l1, l2) # 获取返回值的链表
while res:
print(res.val)
res = res.next
将Solution
部分提交到LeetCode,发现效果竟然很好。多次测试基本稳定在90%以上。
但是我觉得下面这个代码更好一些。不过它在LeetCode里运行时间稍长一些,不太清楚为什么,但是差别不大,而且下面的代码更加精炼。
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
# 这里一开始不做l1、l2非空判断,题意表明非空链表
# 记录是否需要增加新节点,或在链表下一个节点是否需要加1,同时记录链表同级节点的和
carry = 0
# 这里的执行顺序是res = ListNode(0), pre = res
res = pre = ListNode(0)
# 判断l1、l2、carry是否有值,carry有值的话需要增加新节点,或在链表下一个节点需要加1
while l1 or l2 or carry:
# 判断l1是否有值
if l1:
carry += l1.val
l1 = l1.next
# 判断l2是否有值
if l2:
carry += l2.val
l2 = l2.next
# carry有同级节点的和
# divmod返回商与余数的元组,拆包为carry和val
# carry有值的话需要增加新节点,或在链表下一个节点需要加1,在循环中会用到
carry, val = divmod(carry, 10)
# 新建链表节点
# 这里是n.next = ListNode(val), n = n.next()
pre .next = pre = ListNode(val)
# res等价于pre,res.val=0,所以返回res.next
return res.next