正题
两数相加 II
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例1:
输入: l1 = [7,2,4,3], l2 = [5,6,4]
输出: [7,8,0,7]
示例2:
输入: l1 = [2,4,3], l2 = [5,6,4]
输出: [8,0,7]
示例3:
输入: l1 = [0], l2 = [0]
输出: [0]
解析:
看到图第一反应:这不是我们平时算加法的竖式吗?!那么归根到底,我们可以认为他是两个整数相加。所以我会想到第一个解决方案:转整相加
转整相加真的可行吗
拿图示为例:链表 7 -> 2 -> 4 -> 3 转成整数为 7243, 链表 5 -> 6 -> 4 转成整数为 564,然后做一个简单的加法 7243 + 564 = 7807,再将数按照位数从高到低转化为链表不就ok了嘛。
原理:
- 分别遍历链表
l1和l2分别转成s1s2- 将
s1s2转为 整数后相加得res - 创建新的链表,将
res每一位遍历压入链表中
var addTwoNumbers = function(l1, l2) {
let p1 = l1
let p2 = l2
let s1 = ''
let s2 = ''
while(p1 || p2) {
if (p1) {
s1 += p1.val
p1 = p1.next
}
if (p2) {
s2 += p2.val
p2 = p2.next
}
}
let res = parseInt(s1) + parseInt(s2) + ''
let head = new ListNode(res[0])
let p = head
for (let index = 1 ; index < res.length; index++) {
p.next = new ListNode(res[index])
p = p.next
}
return head
};
似乎没有任何问题,提交。
当测试用例到达 1561 个时,出现了 NaN,这是怎么回事?
开始找原因,尝试打印 res 后发现:
8.074864864864864e+60
原来链表的长度太长,转成整数后溢出了。。。
这样一来是不能通过的,并且有很大的限制,所以此方案不可行!
转换思路,反转链表
按照图示,我们需要先将两个链表的最后一位相加,再将倒数第二位和倒数第二位相加,但是链表是顺序的,无法回退,那么每一次相加都需要重新遍历。所以将链表反转无疑是解决这个问题优解!
反转后则变为 分别第一位和第一位相加,第二位和第二位相加,那么则只需要再遍历一次即可!
关于进位
当相加值大于等于10的时候,我们就会提到进位,那么下一位相加之后得到进位就 再+1,所以我们还需要一个标识,表示上一位相加是否有进位,那么当前的结果就为 (n1 + n2) % 10即可。
完成代码
-
首先需要实现链表的反转,具体可参考前面的文章: 一张图说明链表的反转
-
记录进位
isAdd -
创建新的链表将结果压入新的链表,注意是否进位,若进位则结果上再
+1 -
链表遍历完后,最后再次判断进位
-
将结果再次反转即可
var transList = function (head) {
let cur = head
let pre = null
while (cur) {
const next = cur.next
cur.next = pre
pre = cur
cur = next
}
return pre
}
var addTwoNumbers = function(l1, l2) {
let tL1 = transList(l1)
let tL2 = transList(l2)
const res = new ListNode(0)
let p = res
let isAdd = false
while(tL1 || tL2) {
const number1 = tL1 ? tL1.val : 0
const number2 = tL2 ? tL2.val : 0
let res = isAdd ? number1 + number2 + 1 : number1 + number2
isAdd = res >= 10
p.next = new ListNode(res % 10)
p = p.next
tL1 = tL1 ? tL1.next : null
tL2 = tL2 ? tL2.next: null
}
if (isAdd) {
p.next = new ListNode(1)
}
return transList(res.next)
}