leetcode-cn 题解 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 的进位问题,就不专门写了。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。