【题目描述】
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 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]
【解题代码】
package list;
import list.base.ListNode;
public class AddTwoNumbers {
public static void main(String[] args) {
ListNode head1 = ListNode.makeList(9);
ListNode head2 = ListNode.makeList(99999999);
head1.printList();
head2.printList();
new AddTwoNumbers().addTwoNumbers(head1, head2).printList();
}
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int carry = 0;
ListNode head = l1;
while (l1 != null && (l2 != null || carry != 0)){
int n = l1.val + carry;
if (l2 != null) {
n += l2.val;
l2 = l2.next;
}
carry = n / 10;
l1.val = n - carry *10;
if (l1.next == null) {
if (l2 != null) {
l1.next = l2;
l2 = null;
} else {
if (carry > 0) {
l1.next = new ListNode(carry);
}
break;
}
}
l1 = l1.next;
}
return head;
}
}
【解题思路】
根据题目描述,解决方案的大体思路应该是同时从头遍历两个链表,将当前两个节点以及上一次进位数值进行求和,模时之后将余数设置为当前节点的数值,并新的进位数带到下一个节点,根据上述思路完成代码开发,并提交LeetCode成功
【解题步骤】
- 定义进位值和保存头结点的变量
int carry = 0; ListNode head = l1;
- 同从遍历变量两个链表,注意循环中止条件是节点L1不为空,并且节点2不为空或者进位值不为0
while (l1 != null && (l2 != null || carry != 0)){
- 根据节点1,2和进位的值计算当前节点值,和下一位的进位值,这里将结果直接存在L1里,而没有新建一个链表了
int n = l1.val + carry; if (l2 != null) { n += l2.val; l2 = l2.next; } carry = n / 10; l1.val = n - carry *10;
- 如果节点l1下个节点为空,如果节点l2不为空,直接将l1的下一个节点指向l2,将l2设置为空,否则。如果carry大于0,那么在l1后面新建一个值为carry的节点。然后跳出循环
if (l1.next == null) { if (l2 != null) { l1.next = l2; l2 = null; } else { if (carry > 0) { l1.next = new ListNode(carry); } break; } }
- 将节点l1设置为下一个节点
l1 = l1.next; }
- 循环结束后,返回之前保存的首节点
return head;
【思考总结】
- 这道题解法的关键流程在于:1)当前两个节点以及上一次进位数值进行求和,模时之后将余数设置为当前节点的数值,并新的进位数带到下一个节点;2)L1或者L2节点为空的情况特殊处理 3)最后一个节点只剩进位值carry的特殊情况处理
- 算法中的小技巧:将L1作为返回值,节省了申请新链表的空间,另外l1下个节点为空L2不为空时将,l1的下个节点指向l2,并将l2置空
- LeetCode解题之前,一定不要看题解,看了就“破功”了!