Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
- 两数相加-难度中等
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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- 题目数据保证列表表示的数字不含前导零
二、题目和思路分析:
最开始我是这么想的:
逆序,首先要翻转数组
将翻转后数组拼接成字符串,再转为int类型
将两数字相加
数字翻转,再转数组
先翻转数组再拼接可能麻烦,应该直接拼接再翻转字符串,但是字符串并没有直接翻转的方法,还是要借助数组reverse()方法进行翻转
实际做的时候才发现不对劲,传入的根本不是数组,而是链表啊啊啊啊!!!说来惭愧,工作中我没有使用过链表,对链表我只有一个大致的印象,就是根据当前项去取下一项的值。
所以我决定把链表转为数组,累加之后再转为链表,所以我又这么想:
先把传入的链表转为数组
将数组翻转,转成字符串,再转为number
将转过的数组相加
得到的值转数组,再将数组每一项转number,再翻转数组
把数组转为链表
对这个思路我信心满满,结果再次被现实打了脸!!!
问题出在了js自动转换的科学计数法,当数值特别大的时候,数组相加的值是科学计数法表示的,不再是数字,也就是后面步骤得到的结果根本不对。
于是我又考虑把累加的结果转为字符串,然而科学计数法转为字符串并不准确,中间查了n多资料,发现科学计数法在数值精度上是有一定问题的。
功夫不负有心人,就在我一筹莫展时,看到了大神的一段代码,js超大数字求和的:
let temp = 0
let res = ''
while(a.length || b.length || temp){
temp += ~~a.pop() + ~~b.pop()
res = (temp % 10) + res
temp = temp > 9
}
return res.replace(/^0+/g, '')
这段代码很巧妙,但是其中含义只要认真看都能看懂,我看了半小时终于看懂了,在此就不赘述了,以免有凑字数的嫌疑。
不过这段代码相加的和没有考虑0的结果,所以我又加了一句:
if(res === '0') return '0'
至此,半上午的时间过去了,大功告成!
三、代码:
代码实现如下:
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
// 逆序,首先要翻转数组
// 将翻转后数组拼接成字符串,再转为int类型
// 将两数字相加
// 数字翻转,再转数组
// 先翻转数组再拼接可能麻烦,应该直接拼接再翻转字符串,但是字符串并没有直接翻转的方法,还是要借助数组reverse()方法进行翻转
var addTwoNumbers = function(l1, l2) {
// 数组转链表
function toLinkList(arr){
if(!arr.length) return null
let node1 = {val: arr[0], next: null} // 初始根节点
let pnode = node1 // 当前节点
let node // 准备添加的节点
for(let i = 1; i < arr.length; i++) {
node = {val: arr[i], next: null}
pnode.next = node // 将准备添加的节点赋给当前节点
pnode = node // 当前节点改为已添加的节点
}
return node1
}
// 链表转数组
function toArr(link){
if(!link) return []
let a = [link.val]
let b = toArr(link.next) // 遍历节点
return a.concat(b)
}
// 数组求和
function arrSum(a,b){
let temp = 0
let res = ''
while(a.length || b.length || temp){
temp += ~~a.pop() + ~~b.pop()
res = (temp % 10) + res
temp = temp > 9
}
if(res === '0') return '0'
return res.replace(/^0+/g, '')
}
let a = toArr(l1).reverse()
let b = toArr(l2).reverse()
let c = arrSum(a,b).split('').map(item=>{return +item}).reverse()
return toLinkList(c)
}
四、总结:
这是我在力扣刷的第二道题,对于我来说有点难,刚开始不熟悉链表,没有仔细读题目导致运行错误,还很纳闷。后面链表数组的相互转换也想了很久,又查了资料,并且由于考虑不周,没有把js的科学计数法考虑进去,差点无计可施。
不过还好,自己总算做出来了,运行通过之后我又在解题区看了其它各路大神的方案,简洁明了,只有二三十行代码,果然厉害。
加油吧!