【力扣刷题记2】——《两数相加》

158 阅读4分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

  1. 两数相加-难度中等

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 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的科学计数法考虑进去,差点无计可施。

不过还好,自己总算做出来了,运行通过之后我又在解题区看了其它各路大神的方案,简洁明了,只有二三十行代码,果然厉害。

加油吧!

image.png