题目地址: 2.两数相加
说明:如果对链表还不熟悉,可以看我上一篇文章,先了解一下我的上一篇文章js数据结构之-链表
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
题目分析
回到题目,先不考虑链表这个东西,就考虑加法法则,来看示例中的代码,算术题没问题,谁都看得懂,但是如何用代码来实现这个过程是难点。我也是看高票的解答,一点点理解。说明一下我的理解。
- 1、这题会默认给你个ListNode构造函数,让你初始化链表用。具体写在注释中。
- 2、定义一个哑结点(有点类似之前说过的指针,这个哑结点是一直在移动的)
- 3、取l1,l2两当前节点的值相加求和
- 4、
4+6=10遇见这种和大于等于10的,当前节点val=sum % 10 = 0,将进的一位存放到add变量中,下次求和时加上 - 5、返回除头节点外的完整链表,既head.next。
如果上面步骤不太懂就直接看解答,我加一些注释进去。
解题
/**
* Definition for singly-linked list.
* function ListNode(val) {
* val代表当前节点的内容
* this.val = val;
* next储存下一个节点所在的位置
* this.next = null;
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function (l1, l2) {
// 以示例代码为例,此时head = { val: 'head', next: null }
let head = new ListNode("head");
// 哑结点cur = { val: 'head', next: null }
let cur = head;
// 存放进位
let add = 0;
// 两节点相加的和
let sum = 0;
// 注意这里要用||,l1=123,l2=1234,l2的4也要算进去
while (l1 || l2) {
// 节点求和,如果上次求和有进一,就在加上进位的值
// 第一次循环:2 + 5 + 0 = 7
// 第二次循环:4 + 6 + 0 = 10
// 第三次循环:3 + 4 + 1 = 8;
sum = (l1 ? l1.val : 0) + (l2 ? l2.val : 0) + add;
// 新建一个节点,cur.next指向这个节点,val=sum % 10,对应上面第四条说明
cur.next = new ListNode(sum % 10);
// 更新哑结点
/**第一次循环:cur = ListNode { val: 7, next: null }
* head = ListNode { val: 'head', next: ListNode { val: 7, next: null } }
*/
// 第一次循环:cur = ListNode { val: 7, next: null }
// head = ListNode { val: 'head', next: ListNode { val: 7, next: null } }
// ===========================================
// 第二次循环:cur = ListNode { val: 0, next: null }
// head = ListNode {
// val: 'head',
// next: ListNode { val: 7, next: ListNode { val: 0, next: null } }
// }
// ===========================================
// 第三次循环:cur = ListNode { val: 7, next: null }
// ListNode {
// val: 7,
// next: ListNode { val: 0, next: ListNode { val: 8, next: null } }
// }
cur = cur.next;
// 如果求和大于等于10,进位加一
add = sum >= 10 ? 1 : 0;
// l1, l2链表移动
l1 && (l1 = l1.next);
l2 && (l2 = l2.next);
}
// 这里是为了处理,如果l1,l2两个最后一个节点相加大于10的问题
add && (cur.next = new ListNode(add));
// head = ListNode {
// val: 7,
// next: ListNode { val: 0, next: ListNode { val: 8, next: null } }
// }
return head.next;
};
let l1 = {
val: 2,
next: {
val: 4,
next: {
val: 3,
next: null
}
}
}
let l2 = {
val: 5,
next: {
val: 6,
next: {
val: 4,
next: null
}
}
}
addTwoNumbers(l1, l2);
// 执行用时:136 ms, 在所有 JavaScript 提交中击败了57.48%的用户
// 内存消耗:41.6 MB, 在所有 JavaScript 提交中击败了13.23%的用户
// 时间复杂度:On,遍历列表需要On的时间复杂度
// 空间复杂度:On,新链表存放需要On的空间