持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
题目描述
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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- 题目数据保证列表表示的数字不含前导零
解题思路
- 加法我们小学都学过,就是从右向左按位相加,并处理进位。根据数据范围,直接转化成整数相加会越界,因此要保持链表的存储格式,按位计算。题目给的链表是逆序的,所以我们只要从左向右按位相加并进位即可。O(n+m)
- 边界条件
- 链表节点数为0
- 两链表等长,最后有进位
- 两链表不等长,最后有进位
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
head := &ListNode{}
t := head
pre := 0
for l1 != nil && l2 != nil {
t.Next = &ListNode{(pre + l1.Val + l2.Val) % 10, nil}
pre = (pre + l1.Val + l2.Val) / 10
l1 = l1.Next
l2 = l2.Next
t = t.Next
}
if l1 != nil || l2 != nil {
var p *ListNode
if l1 != nil {
p = l1
} else {
p = l2
}
for p != nil {
t.Next = &ListNode{(pre + p.Val) % 10, nil}
pre = (pre + p.Val) / 10
p = p.Next
t = t.Next
}
}
if pre != 0 {
t.Next = &ListNode{1, nil}
}
return head.Next
}
- 常数级优化:在处理剩余的单个链表时,如果没有进位可以直接把剩下的链表拼接到结果里直接结束。
func addTwoNumber(l1 *ListNode, l2 *ListNode) *ListNode {
head := &ListNode{}
t := head
pre := 0
for l1 != nil && l2 != nil {
t.Next = &ListNode{(pre + l1.Val + l2.Val) % 10, nil}
pre = (pre + l1.Val + l2.Val) / 10
l1 = l1.Next
l2 = l2.Next
t = t.Next
}
if l1 != nil || l2 != nil {
var p *ListNode
if l1 != nil {
p = l1
} else {
p = l2
}
for p != nil {
t.Next = &ListNode{(pre + p.Val) % 10, nil}
pre = (pre + p.Val) / 10
p = p.Next
t = t.Next
if pre == 0 {
t.Next = p
break
}
}
}
if pre != 0 {
t.Next = &ListNode{1, nil}
}
return head.Next
}
- 也可以有更优雅的写法
func addTwoNumbers3(l1 *ListNode, l2 *ListNode) *ListNode {
head := &ListNode{}
tail := head
t := 0
for l1 != nil || l2 != nil || t != 0 {
if l1 != nil {
t += l1.Val
l1 = l1.Next
}
if l2 != nil {
t += l2.Val
l2 = l2.Next
}
tail.Next = &ListNode{t % 10, nil}
tail = tail.Next
t /= 10
}
return head.Next
}