文章目录
- 1:问题描述
- 2:问题分析
- 2.1 Python链表实现
- 2.2 问题分析
1:问题描述
来源:LeetCode
难度:中等
问题详情:
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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]
2:问题分析
2.1 Python链表实现
链表按照逆序存储数值,输入中的l1= [2,4,3]
实际表示的是342
。存入链表后,则变成了2 -> 4 -> 3 -> None
。
在开始写解题代码前,先回顾下python如何实现链表形式,LeetCode已经给了提示。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
按照提示简单实现一下:
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def generate_ListNode(value_list: list) -> ListNode:
"""
通过列表元素生成ListNode
:param value_list:
:return:
"""
cur_node = None
for item in value_list[::-1]:
node = ListNode(item)
node.next = cur_node
cur_node = node
return cur_node
l1_value = [2,4,3]
l2_value = [5,6,4]
l1 = generate_ListNode(l1_value)
l2 = generate_ListNode(l2_value)
看一下上述代码的思路,首先构造ListNode类,里面包含val
和 next
属性。
其次通过generate_ListNode
类按照3->None
, 4->3->None
, 2->4->3->None
的顺序构建l1
。也就是说,构建链表是从右往左构建的。
2.2 问题分析
两个链表都是按照同样的逆序排列的,那么就只需要将链表对应位置相加并考虑进位即可。
但是需要考虑以下三种情况:
- 两个链表同长度,且相加后的值与二者仍旧同长度;
e.g. 1 + 1 = 2
- 两个链表不同长度,且相加后的值与最长链表同长度;
e.g. 19 + 1 = 20
- 相加后的值大于两个链表的长度,
e.g. 91 + 9 = 100 或 9 + 1 = 10
- 情况1,属于一般情况,只需要考虑进位即可;
- 情况2,两个列表不同长度,则需要考虑对应位置两个链表是否存在None值;
- 情况3,则需要考虑两个链表所有的元素遍历完后,最后的进位需要在循环外添加进去。
代码如下,详细解释在注释中提到。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# 需要考虑如下三种情况:
# 1:两个链表同长度,且相加后的值与二者仍旧同长度;e.g. 1 + 1 = 2
# 2:两个链表不同长度,且相加后的值与最长的那个链表同长度;e.g. 19 + 1 = 20
# 3:相加后的值大于两个链表的长度,e.g. 91 + 9 = 100 或 9 + 1 = 10
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
# 创建一个指针, head 和 end分别表示头指针和尾指针
head = end = ListNode(-1)
# 进位项
carry = 0
# 如果l1、l2、carry不全为None的话,进入循环
# carry这个判断条件则是为了情况3,
# 如果两个链表已经遍历完成,而carry还有进位,
# 比如1+9=10,有一个进位1,则需要再进入循环
while l1 or l2 or carry:
total = 0
# 解决情况2,如果当前链表不是None,则指针继续右移,
# 否则跳过,None元素是没有next属性的,
# 所以必须要判断。
if l1:
total += l1.val
l1 = l1.next
if l2:
total += l2.val
l2 = l2.next
total += carry
carry = total//10 # 计算进位
end.next = ListNode(total%10) # 余数作为链表的当前值
end = end.next
# 头指针的下一个指针作为输出,因为尾部指针end已经到了链表的末尾,没法再回去了。
# 所以只能返回头指针head.next,因为head目前的指向是没有意义的,只是为了初始化
# 生成的一个元素,其下一个元素才是相加结果开始的地方。
return head.next
假设最长的链表长度为n
,则循环次数为n
或者n+1
,则时间复杂度为O(n)