一、原题
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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]
二、心得
乍眼一看,链表(这个我会,我可是好好研究过链表的),再眼一看,真抽象,好端端的加法硬是要反过来算(注意,此处埋下伏笔),算了,直接开干!(现在的我有多猖狂,等会儿我就有多狼狈~)
我的思路(思路是错误的,勿学!)是这样的:(开始搞笑🤡)将已知的两个链表的最后一位相加得到新链表的第一位,然后两链表依次向前推一个节点,再加得新值。我知道有进位这一说法,所以初步有:(l1 + l2) % 10 = 新值,(l1 + l2) / 10 = 进位值(只能是1)。把进位值加入到新链表的下一节点的数据上,最后输出即可。(我是不是太聪明了哈,简直无懈可击(p≧w≦q))
然后每日手废(1/1),研究半天,求助官方,然后,开始思考人生······
不是啊?它为什么会没有向前推一节点,而是向后推一节点?(此处沉默30分钟)
直至我仔细琢磨了示例1,!,正向加也是正确的~~~这题出的太有迷惑性了,正向得结果和反向得结果都正确,@官方“逆序”是几个意思?误导我┭┮﹏┭┮
直接看结果:
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = null, tail = null;
int carry = 0;
while (l1 != null || l2 != null) {
int n1 = l1 != null ? l1.val : 0;
int n2 = l2 != null ? l2.val : 0;
int sum = n1 + n2 + carry;
if (head == null) {
head = tail = new ListNode(sum % 10);
} else {
tail.next = new ListNode(sum % 10);
tail = tail.next;
}
carry = sum / 10;
if (l1 != null) {
l1 = l1.next;
}
if (l2 != null) {
l2 = l2.next;
}
}
if (carry > 0) {
tail.next = new ListNode(carry);
}
return head;
}
}
首先官方巧妙地设置了一个进位值carry,并初始化为0,开始循环,int n1 = l1 != null ? l1.val : 0;,这个我熟悉,单指物理意义上的熟悉——见过,有过了解,但忘了。
补充:A ?B : C 怎么理解?
若A为真,则执行B;若A为假,则执行C
这里若节点不为空,则取该节点的数据,反之,取0(补位0,如示例3)
随后计算相同位置上的两数之和,开始录入新链表中,因为链头和链尾初始都为空,则第一个值取模存入头结点,之后录入,则只需执行尾节点的后移即可。tail.next = new ListNode(sum % 10);和tail = tail.next;重中之重,先给下一节点录入数据,再把下一节点赋给当前节点,这样实现了节点的后移。
由于carry值为1时,表示进位了,若链表已到头,此时carry为1,则需要再尾节点后增添一个新的节点,值为carry(即1)。
最后再返回链头(当我们返回链表的头节点时,实际上返回的是整个链表的引用,相当于,你把水匝的阀给取出来,水自然跟着出来了)。(我不明白,chat的(●ˇ∀ˇ●)🌼)