[前端]_一起刷leetcode 445. 两数相加 II

179 阅读4分钟

大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。

题目

445. 两数相加 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]

 

提示:

  • 链表的长度范围为 [1, 100]
  • 0 <= node.val <= 9
  • 输入数据保证链表代表的数字无前导 0

 

进阶: 如果输入链表不能修改该如何处理?换句话说,不能对列表中的节点进行翻转。

错误示范

思路

刚开始拿到题目我想偷懒,你不是链表嘛我给你转成数字就完事了。然后咔咔一通操作,最后原地翻车。

  1. l1l2所有节点的值相加,转成数字;
  2. 遍历总数,输出一个新建的链表。

代码

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
    const total = String(getListNumber(l1) + getListNumber(l2));
    const n = total.length;

    let result = new ListNode(0);
    let prev = result;
    
    // 拿总数来生成节点
    for (let i = 0; i < n; i++) {
        prev.next = new ListNode(total[i]);
        prev = prev.next;
    }

    return result.next;
};

// 拿到当前链表的数字值
function getListNumber(list) {
    let str = "";

    while (list) {
        str += list.val;
        list = list.next;
    }

    return Number(str);
}

翻车现场

image.png

好家伙,直接原地翻车,超出数字范围了直接,说明这道题目没这么简单,接下来正儿八经的来给大家做题。

常规解法

思路

  1. 首先我们进行数字的加减,都是从个位数开始加起,所以我们需要对两个链表做一个翻转;
  2. 然后从末尾节点加到头节点,同时需要用一个变量add来记录是否需要加1;
  3. 每一轮两个链表同时往前进,直到有一个链表走完了,跳出循环;
  4. 然后需要就剩下单链表的情况了, 但是要进入到第二次循环,比如9999 + 1要一层层往前进1;
  5. 进到最后的时候,如果已经遍历完链表了,还需要进1,那么需要新增一个节点;
  6. 最后对统计完的结果做一次翻转。

实现

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
    l1 = reverseList(l1);
    l2 = reverseList(l2);

    let result = new ListNode(0);
    let prev = result;
    let add = false;

    // 第一轮, 两个数字都有值,直接相加判断是否进1
    while (l1 && l2) {
        // 判断上一轮是否需要往前进1位
        let cur = l1.val + l2.val + (add ? 1 : 0);

        if (cur >= 10) {
            add = true;
            cur -= 10;
        } else {
            add = false;
        }

        prev.next = new ListNode(cur);
        
        l1 = l1.next;
        l2 = l2.next;
        prev = prev.next;
    }

    prev.next = l1 || l2;

    // 如果只剩下一个值,或者一个值都没有了。还需要再进1
    if (add) {
        // 第二轮,用while是为了兼容9999这种情况需要层层递进
        while (prev.next && add) {
            prev = prev.next;
            // 判断上一轮是否需要往前进1位
            let cur = prev.val + 1;
            if (cur >= 10) {
                add = true;
                cur -= 10;
            } else {
                add = false;
            }
            
            prev.val = cur;
        }

        // 需要新增头节点
        if (add) {
            prev.next = new ListNode(1);
        }
    }

    return reverseList(result.next);
};

// 翻转链表
function reverseList(list) {
    let prev = null;

    while (list) {
        const next = list.next;
        list.next = prev;
        prev = list;
        list = next
    }

    return prev;
}

栈解法

因为题目中进阶说了如果链表不能进行翻转怎么办,那我们需要用栈来存储, 然后待会儿从两个栈最后取元素一个个加,实际上本质跟翻转链表是一样的。

栈代码

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
    // 存放入栈
    let stack1 = pushToStack(l1), 
        stack2 = pushToStack(l2);

    let add = false; // 是否需要进1
    let result = null; // 存储结果

    while (stack1.length || stack2.length) {
        let cur = add ? 1 : 0;
        if (stack1.length) {
            cur += stack1.pop().val;
        }

        if (stack2.length) {
            cur += stack2.pop().val;
        }

        if (cur >= 10) {
            cur -= 10;
            add = true;
        } else {
            add = false;
        }

        result = insertHeadNode(result, new ListNode(cur));
    }

    // 最后判断是否需要进1
    if (add) {
        result = insertHeadNode(result, new ListNode(1));
    }

    return result;
};

// 插入头节点
function insertHeadNode(list, newNode) {
    newNode.next = list;
    list = newNode;

    return list;
}

// 链表转成栈
function pushToStack(list, stack = []) {
    while (list) {
        stack.push(list);
        list = list.next;
    }

    return stack;
} 

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。