难度 中等
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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
- 题目数据保证列表表示的数字不含前导零
解题思路:根据题意我们可以知道输入的两个链表都是倒序存储的,即链表的头结点就是输入数字的个位数的值,这样我们就可以直接从头结点开始计算。对于结果链表有两种方式可以得到:一种是创建一个新的链表存储计算结果,每次计算都要新建一个节点,但是不会对原链表进行修改;另一种方法是在输入的任意一个链表中进行原地更新操作,将计算后要存储的结果更新到该节点。因为是进行加法运算,我们需要定义一个参数存储进位。在循环计算中要把输入的两个链表遍历完并且进位也是0时才能停止。
题中链表的定义:
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
使用输入的链表原地更新结果:
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//进位的数值,l1中遍历到的值,l2中遍历到的值,要更新的结果
int sign = 0, l1_val, l2_val, value;
//使用l1作为结果链表,root用来记录头结点位置最后用于返回值
ListNode root = l1;
//l1和l2都遍历完,且进位为0时结束循环
while (l1 != null || l2 != null || sign != 0){
//计算完成之前l1不会指向null,原因在循环体倒数第二行
l1_val = l1.val;
//参照示例3,l2如果遍历完就赋值为0进行加法运算
l2_val = l2 == null ? 0 : l2.val;
value = l1_val + l2_val + sign;
if(value >= 10){ //如果结果大于10,就要有进位
/*
因为是加法运算,进位只能是0或1,这里可以直接赋值
如果是乘法的话下面的代码可以改成:
sign = value / 10;
vale = value % 10;
*/
value -= 10;
sign = 1;
}
else sign = 0;
l1.val = value; //将结果更新到l1中
// 如果l2还没遍历完,就进行下一位的计算。
// 如果已经遍历完,此时l2应该是null,会在上面赋值为0进行运算,此处就不用操作
if(l2 != null) l2 = l2.next;
//如果l1要遍历完时l2还没有遍历完(比如l1=12,l2=1234)或者都遍历完了但是还有进位没处理,要在l1后面再加一个节点继续计算
//这样也就保证了l1不会先遍历完,即l1不会先指向null
if(l1.next == null && (l2 != null || sign != 0)) l1.next = new ListNode(0);
l1 = l1.next;
}
return root;
}
}
新建链表存储结果:
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//进位的数值,l1中遍历到的值,l2中遍历到的值,要更新的结果
int sign, l1_val, l2_val, value;
//创建结果链表,确定头结点,初始化进位sign
value = l1.val + l2.val;
if(value >= 10){
value -= 10;
sign = 1;
}
else sign = 0;
//root用来记录头结点位置最后用于返回值,l3用于插入结果子节点
ListNode root = new ListNode(value);
ListNode l3 = root;
//上面已经计算了一次,所以这里要跳过一次
l1 = l1.next;
l2 = l2.next;
//l1和l2都遍历完,且进位为0时结束循环
while (l1 != null || l2 != null || sign != 0){
//进入循环就代表肯定有计算未完成,要新建节点进行计算
l3.next = new ListNode();
l3 = l3.next;
//如果有链表先被遍历完就赋值为0进行加法运算
l1_val = l1 == null ? 0 : l1.val;
l2_val = l2 == null ? 0 : l2.val;
value = l1_val + l2_val + sign;
if(value >= 10){ //如果结果大于10,就要有进位
/*
因为是加法运算,进位只能是0或1,这里可以直接赋值
如果是乘法的话下面的代码可以改成:
sign = value / 10;
vale = value % 10;
*/
value -= 10;
sign = 1;
}
else sign = 0;
l3.val = value; //将结果更新到结果链表中
// 如果l1或l2还没遍历完,就进行下一位的计算。
// 如果已经遍历完,此时l1或l2应该是null,会在上面赋值为0进行运算,此处就不用操作
if(l1 != null) l1 = l1.next;
if(l2 != null) l2 = l2.next;
}
return root;
}
}