题目描述
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
1. 链表本身的Val的范围是0到9,两个链表Val相加结果可能会超过10,会产生进位(carry),这个进位要作为链表下一个节点(Next)的Val处理要加的数值
2. 链表l1和l2长度不一定相等,有可能一个链表结束(Next指向Null),另一个链表仍然有有效节点
3. 两个链表全部处理完毕可能会产生进位,所以两个链表全部处理完毕后,要考虑如果产生了进位,该进位需要作为结果链表的新节点
4. 两个链表全部处理完毕的条件需要是 链表l1和l2都为NULL,就退出golang的for处理代码块
要考虑的场景
1. 两个链表都只有一个节点,但是有进位
l1: [5]
l2: [5]
进位为1
2. 一个链表为空,一个链表非空
l1: []
l2: [5, 7, 9]
3. l1和l2非空,长度不相等
l1: [5, 3, 8]
l2: [4, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 9]
代码实现
package main
import (
"fmt"
"strconv"
)
// Definition for singly-linked list.
type ListNode struct {
Val int
Next *ListNode
}
// Rule
// 1. for循环退出的条件是l1和l2都为nil,代表两条链表全部处理完毕
// 场景考虑
// 1. l1和l2全部处理完毕,但是有进位(carry=1), 需要在for循环退出后,将carry当作Val新增一个节点
// 2. l1为空,l2非空
// 3. l1和l2非空,长度相等
// 4. l1和l2非空,长度不相等
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
var head, curr, node *ListNode
var carry int
for {
var a, b, sum, val int
if l1 == nil && l2 == nil {
break
}
if l1 != nil {
a = l1.Val
l1 = l1.Next
}
if l2 != nil {
b = l2.Val
l2 = l2.Next
}
sum = a + b + carry
if sum >= 10 {
carry = 1
val = sum % 10
} else {
carry = 0
val = sum
}
if curr == nil {
head = &ListNode{
Val: 0,
}
node = &ListNode{
Val: val,
}
head.Next = node
curr = node
} else {
node = &ListNode{
Val: val,
}
curr.Next = node
curr = node
}
}
// l1 and l2 all processed, but has carry(carry=1)
if carry == 1 && curr != nil {
node = &ListNode{
Val: carry,
}
curr.Next = node
}
if head == nil {
return nil
}
return head.Next
}
// 模拟打印链表
func printListNode(l *ListNode) {
var nums []int
for {
if l == nil {
break
}
nums = append(nums, l.Val)
l = l.Next
}
fmt.Printf("ListNode=%+v\n", nums)
}
// 模拟构建数值链表
func buildListNode(s string) *ListNode {
var p, n *ListNode
for _, b := range s {
v, err := strconv.Atoi(fmt.Sprintf("%c", b))
if err != nil {
return nil
}
if n == nil {
l := &ListNode{
Val: v,
}
n = l
p = n
} else {
l := &ListNode{
Val: v,
}
n.Next = l
n = l
}
//fmt.Printf("%c\n", b)
}
return p
}
// 入口函数,各种场景测试
func main() {
// l1 长度远远大于l2,且中间有进位
l1 := buildListNode("1001000000000000000000000000001")
l2 := buildListNode("5649")
l := addTwoNumbers(l1, l2)
printListNode(l)
// 输出结果:
// ListNode=[6 6 4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]
// l1和l2长度相等,且节点运算完后有进位
l1 = buildListNode("5")
l2 = buildListNode("5")
l = addTwoNumbers(l1, l2)
printListNode(l)
// 输出结果:
// ListNode=[0 1]
// l1为空, l2非空
l1 = buildListNode("")
l2 = buildListNode("5649")
l = addTwoNumbers(l1, l2)
printListNode(l)
// 输出结果:
// ListNode=[5 6 4 9]
}