试水刷题,先从简单的练起。

题目

2. 两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

解题思路

简单题,说白了就是高精度加法,也可以理解为列竖式算加法。
题目示例存在陷阱,如果一开始写反了方向会发现也能得出正确的解答。

不妨更换一个样例:

输入:(1-> 4 -> 5 -> 0 -> 3) + (5 -> 6 -> 4)
输出:(6-> 0 -> 0 -> 1 -> 3)

这份样例同时包含了以下特殊情况:

  • 两个链表长度不一致
  • 进位情况

    • 连续进位情况

未包含的情况:

  • 答案链表比原始链表长度更长

列一个竖式就很好理解了:

基本上,只需要遍历 L1 和 L2,其中单个链表出现 next 为空的时候,当作 0 来处理,当两个链表的 next 都为空的时候,只需要处理进位的问题就可以结束战斗。

解答

Java 代码:

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode res = new ListNode(0); 
        ListNode ans = res; 
        int add = 0;

        while (true){
            ans.val = (l1.val + l2.val) % 10;
            add = (l1.val + l2.val) / 10;
            if (l1.next == null && l2.next == null) 
                break;
            l1 = l1.next = l1.next == null ? new ListNode(0) : l1.next;
            l2 = l2.next = l2.next == null ? new ListNode(0) : l2.next;
            l1.val += add;
            ans.next = new ListNode(0);
            ans = ans.next;
        }

        if (add != 0)
            ans.next = new ListNode(add);
        return res;
    }

}

Java 代码优化

其实观察一下,l1 l2 并没有被有效利用,完全可以直接使用 l1 来存储算出来的答案,这样可以少占不少内存。

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode a1 = l1;
        int add = 0;
        while (true){
            add = (l1.val + l2.val) / 10;
            l1.val = (l1.val + l2.val) % 10;
            l2.val = l1.val;
            if (add == 0){
                if (l2.next == null)
                    return a1;
                if (l1.next == null){
                    l1.next = l2.next;
                    return a1;
                }
            }
            l1 = l1.next = l1.next == null ? new ListNode(0) : l1.next;
            l2 = l2.next = l2.next == null ? new ListNode(0) : l2.next;
            l1.val += add;
        }
    }
}

修改后的代码,性能还算可以接受的样子

继续优化?

顺着刚才的路子再继续想,如果是 l1 或者 l2 比另一边长,那其实算到最后一个进位以后就不用算了。
l1 长的话直接返回 l1,l2 长的话就把循环中 l1 的 next 指向 l2 就好了。
不过这里在悲观情况下需要处理 l1 的进位问题,就不专门写了。

文章目录