目录
思路
本题的整体思路其实算是比较简单的:遍历两个链表然后进行相加,并将相加后的结果放到返回值的每个对应的节点中即可。
我认为这个题目还算是一个简化了的版本,因为题目提供的是单向链表,其中数字的放置顺序是实际数字的逆序了,也就是如果是数字 123 ,题目提供给我们的链表中 val 的顺序是:3、2、1,如果题目没有这样简化,估计还需要从后往前遍历链表进行相加,又是一个难点。
注意点
1. 数字相加之后如果满 10,需要往下一个节点进 1;并且还需要注意,此处的数字相加,不只是题目提供的两个链表中对应的值相加,还需要加上返回值中的上一节点是否有进 1。
假设:题目中提供的两个链表对应的节点值分别是 4 和 5,此时它们相加为 9 ,此时恰逢返回值中的上一节点是满 10 进 1,但是你没有加上这个进了的 1 ,那么结果就为 9 ,但实际是为 10 。
2. 两个链表长度可能不一,所以会出现不同时遍历完的情况。因此我们需要对遍历后的节点判空多加注意。
3. 需要注意一种特殊情况:假设两个链表中的最后一个值分别为:9、1,它们相加之后的结果为进 1 ,当前位为 0,但是还需要创建一个最后一位来表示进位了的 1 。但是此时两个链表都遍历完了,因此我们需要加上对这种特殊情况的判断。
易错点
1. 这个易错点,我不知道是不是我自己在做这个题时才会一直犯错的地方,就是新创建下一个节点的时机,我一开始是这样做的:
class Solution {
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode cur = new ListNode();
ListNode head = cur;
while(l1 != null && l2 != null) {
//满10进1
if (l1.val + l2.val + cur.val >= 10) {
cur.next = new ListNode(1);
} else {
cur.next = new ListNode(0);
}
cur.val = (cur.val + l1.val + l2.val) % 10;
l1 = l1.next;
l2 = l2.next;
cur = cur.next;
}
while(l1 != null) {
if(l1.next != null) {
if (l1.val + cur.val >= 10) {
cur.next = new ListNode(1);
} else {
cur.next = new ListNode(0);
}
cur.val = (cur.val + l1.val) % 10;
cur = cur.next;
l1 = l1.next;
}
}
while(l2 != null) {
if(l2.next != null) {
if (l2.val + cur.val >= 10) {
cur.next = new ListNode(1);
} else {
cur.next = new ListNode(0);
}
cur.val = (cur.val + l2.val) % 10;
cur = cur.next;
l2 = l2.next;
}
}
return head;
}
}
其中 cur 表示返回值中,当前的节点。
我的想法是:在第一个循环中,如果相加之后满 10,就将下一节点创建后并赋初始值为 1,否则赋值为 0 。
但是这样的做法会有一个问题:就是最后一次进入循环时,会多创建一个节点,导致输出返回值时会多输出一个 0 ,这是一个额外创建的节点,本不应该存在。
参考了答案的做法后,修改为了:将 cur = cur.next 这步放在创建节点后进行,也就是创建当前节点而不是创建下一个节点(说起来有点绕,可能看代码比较好理解点)。
2. 如果将未遍历完的链表再额外加多一个 while 遍历完,可能会出现超出时间限制的情况,就像我上面的做法一样,所以尽量需要使用一个 while 循环将两个链表遍历完。
完整代码
class Solution {
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode cur = null;
ListNode head = null;
int flag = 0;
while(l1 != null || l2 != null) {
int n1 = l1 != null ? l1.val : 0;
int n2 = l2 != null ? l2.val : 0;
int tmp = flag + n1 + n2;
if(tmp >= 10) {
flag = 1;
}else {
flag = 0;
}
if(cur == null) {
cur = new ListNode(tmp%10);
head = cur;
}else {
cur.next = new ListNode(tmp%10);
cur = cur.next;
}
if(l1 != null) {
l1 = l1.next;
}
if(l2 != null) {
l2 = l2.next;
}
}
if(flag == 1) {
cur.next = new ListNode(flag);
}
return head;
}
}
上述代码中:
flag代表是否进 1 ;
while 循环中需要对 cur 是不是为第一个节点进行判断:如果为空即为第一个节点,此时就不能为创建 cur.next 节点,而是创建第一个节点,否则就为一般情况:先创建 cur.next 节点,再将其赋值给 cur,即为创建当前节点。由于要判断是否是第一个节点,因此 while 外创建 cur 时,须先将其置空,一开始我的做法是如下:
ListNode cur = new ListNode();
ListNode head = cur;
但是发现这样做,判断是否是第一个节点处就难以判断了,所以此做法不可取。
n1 和 n2 分别表示两个链表中对应的节点的值:如果当前节点为空,则赋为 0 ,此时就不会对相加的结果造成影响,这样就可以达到在一个 while 循环中遍历完两个不同长度的链表的目的;
tmp 表示相加后的结果;
最后一个 if 判断是为了解决上面所提到的特殊情况。
总体来说,这道题不能算难,但是细节可能比较多,需要注意的地方比较多。