leetcode 2.两数相加

160 阅读3分钟

题目地址: 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的空间