4

算法(leetode,附思维导图 + 全部解法)300题之(2)两数相加

 2 years ago
source link: https://segmentfault.com/a/1190000040764021
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

标题:算法(leetode,附思维导图 + 全部解法)300题之(2)两数相加

我的解法很多 且 很 sao,你忍一下~

项目&作者

1 GitHub - LeetCode项目仓库

0)本项目地址: https://github.com/CYBYOB/algorithm-leetcode 。
目标、愿景:
让每个人都能拥有一定的算法能力、以应对面试中(会举一反三的同学还可以将其融入自己的肌肉和血液,甚至能够赋能于公司的业务和技术)的算法。

1)项目的根目录下的 README.md 文件,
可以帮您快速查阅每1道题的来源、难度、所有的题解方案等。

2)而每个题解(即 index.md 文件)中,
还将附带题目描述、所有的题解方案的思维导图( .xmind 文件)、思路和技巧等。

3)每种题解方案都有详细的注释,
通过“数字步骤”将抽象的算法逻辑、
清晰和有层次的展示于您的面前。
可以说是,
开箱即用~

4)所有的题解方案都是经过作者1人之手,
故代码风格及其统一。
一旦阅读达到一定量后,
后续将大大提升您的阅读速度 —— “正所谓、量变引起质变”。

5)本人每周仍在不断的更新 —— 保证每周都有新的题目、题解方案刺激着您的神经 和 刷题欲望。
欢迎对算法感兴趣的同学加入我们的社群。
QQ群: 933919972 ;
作者QQ: 1520112971 ;
作者VX: c13227839870(可拉您进群、一起学习与交流~) 。

algorithm-leetcode - 题目总览

2 作者标签

1)“伪全栈工程师,主攻前端,偶尔写点后端”。

2)2019年的微信小程序应用开发赛 - 全国三等奖;
2019CODA比赛 - 前 17/211 强 且 荣获“优秀团队”称号 等。

3)“半自媒体人”,
在校期间、个人公众号(IT三少。新自媒体(公众号)号: 码农三少 )
在半年内实现了0到5.8K+的粉丝增长等。

一 题目描述

题目描述
题目描述
题目描述

二 解法总览(思维导图)

思维导图

三 全部解法

1)代码:

var addTwoNumbers = function(l1, l2) {
    // 获取链表所代表的值
    const getValueByLink = (link) => {
        let resVal = 0
            // weight表示当前位置的权重,10的“整幂倍”
            weight = 1;
        while (link) {
            resVal += (link.val * weight);
            // 权重乘10,链表位置往后走
            weight *= 10;
            link = link.next;
        }
        return resVal;
    }

    const val_1 = getValueByLink(l1),
        val_2 = getValueByLink(l2);
    let sum = val_1 + val_2;

    // 根据sum值不断遍历、将相应的位置值放入 curLink 里
    // 若 sum = 807 ,则 resLink = [7, 0, 8]
    const resLink = curLink = new ListNode(sum % 10);
    sum = parseInt(sum/10);
    while (sum) {
        // curLink不断放当前sum值的“个位数值”。sum不断赋成parseInt(sum/10)
        curLink.next = new ListNode(sum % 10);
        curLink = curLink.next;
        // 别错写成 sum /= 10,漏了 parseInt !!
        sum = parseInt(sum/10);
    }

    return resLink;
}

1)代码:

var addTwoNumbers = function(l1, l2) {
    let resArr = [],
        // carry 是否有进位(其值范围一定是 [0, 1])
        carry = 0;

    // 1)不断往后拉2个链表
    while (l1 && l2) {
        resArr.push((l1.val + l2.val + carry) % 10);
        carry = parseInt((l1.val + l2.val + carry) / 10);
        
        l1 = l1.next;
        l2 = l2.next;
    }
    // 2)判断l1、l2 长度情况。谁长就继续“往后拉”谁
    let tmpLink = l1 ? l1 : l2;
    while (tmpLink) {
        resArr.push((tmpLink.val + carry) % 10);
        carry = parseInt((tmpLink.val + carry) / 10);
        tmpLink = tmpLink.next;
    }
    // 3)最后1位可能有进位 —— 需要继续放
    if (carry) {
        resArr.push(carry);
    }
    // 因为 两个非空 的链表,遍历 resArr 将相应位置上的值放到 resLink 即可
    // resLink 是返回的“链表头”,curLink 用于存放“遍历所取到的值”
    let resLink = curLink = new ListNode(resArr[0]),
        i = 1,
        l = resArr.length;
    while (i < l) {
        curLink.next = new ListNode(resArr[i]);
        curLink = curLink.next;
        i++;
    }

    return resLink;
};

3 方案3(方案2的优化版:不用 resArr 中间变量,直接存链表里、节约内存开销)

1)代码:

var addTwoNumbers = function(l1, l2) {
    let resLink = curLink = null,
        // carry 是否有进位(其值范围一定是 [0, 1])
        carry = 0;

    // 1)不断往后拉2个链表
    while (l1 && l2) {
        const tmpVal = (l1.val + l2.val + carry) % 10;
        carry = parseInt((l1.val + l2.val + carry) / 10);
        // resLink 为 null,需初始化!
        if (!resLink) {
            resLink = curLink = new ListNode(tmpVal);
        } else {
            curLink.next = new ListNode(tmpVal);
            curLink = curLink.next;
        }
        
        l1 = l1.next;
        l2 = l2.next;
    }
    // 2)判断l1、l2 长度情况。谁长就继续“往后拉”谁
    let tmpLink = l1 ? l1 : l2;
    while (tmpLink) {
        curLink.next = new ListNode((tmpLink.val + carry) % 10);
        curLink = curLink.next;
        carry = parseInt((tmpLink.val + carry) / 10);
        tmpLink = tmpLink.next;
    }
    // 3)最后1位可能有进位 —— 需要继续放
    if (carry) {
        curLink.next = new ListNode(carry);
        curLink = curLink.next;
    }
    
    return resLink;
};

4 方案4(递归)

1)代码:

var addTwoNumbers = function(l1, l2) {
    // “一般递归的特点”:
    // 1 2种实现 —— dfs(深度优先搜索) 和 bfs(广度优先搜索)
    // 2 3个核心
    // 1)确定返回值得类型及其含义
    // 2)确定递归的出口条件及对应的值
    // 3)递归处理的函数体
    const dfs = (l1, l2, carry) => {
        // 其实可以简写成 if (!l1 && !l2 && !carry)。
        // 1)下面3行是递归出口
        if (l1 === null && l2 === null && carry === 0) {
            return null;
        }

        // 2)下面7-8行是递归处理的函数体
        // 此时必定是 l1、l2或carry中存在“真值”(即有 非null 或 非0 值)
        const val_1 = l1 ? l1.val : 0,
            val_2 = l2 ? l2.val : 0,
            next_1 = l1 ? l1.next : null,
            next_2 = l2 ? l2.next : null,
            sum = (val_1 + val_2 + carry);

        let resLink = new ListNode(sum % 10);
        // 边界:别漏了 parseInt ,别的语言也需可直接 sum/10 !
        resLink.next = dfs(next_1, next_2, parseInt(sum/10));

        // “本次递归”的返回值
        return resLink;
    }

    return dfs(l1, l2, 0);
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK