2. 两数相加

193 阅读2分钟

题目

image.png

这题考的就一个加法运算和进位,以及链表。

链表的实现就用了一个比较简单的构造函数ListNode,有val,next两个属性,多个ListNode通过next连起来形成链表。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */

扩展

这里题目输入的[2,4,3]/[5,6,4]看起来是数组其实应该是由ListNode连起来的链表,如下:

ListNode {
  val: 2,
  next: ListNode { val: 4, next: ListNode { val: 3, next: null } }
}
ListNode {
  val: 5,
  next: ListNode { val: 6, next: ListNode { val: 4, next: null } }
}

然后写了个转换的函数,如下:

/**
 * 
 * @param {Array} arr 
 * @returns {ListNode}
 */
function createLink(arr) {
  // 第一个节点和最后一个节点
  let resNode, curNode;
  while(arr.length){
    let tempNode = new ListNode(arr.shift());
    // 如果是第一个节点
    if (!resNode) resNode = curNode = tempNode;
    // 非第一个节点
    else {
      curNode.next = tempNode;
      curNode = curNode.next;
    };
  }
  return resNode;
}

思路一

很明显给到的链表的顺序和原数字的倒序,并且加法运算也是从个位开始计算,然后大于10的就进位,就是最基本的加法即可。

/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
function addTwoNumbers(l1, l2) {
  // 进位
  let curry = 0;
  // 第一个节点和最后一个节点
  let resNode, curNode;

  // 首先考虑链表长度,最后考虑是否有进位
  while (l1 || l2 || curry !== 0) {
    // 当前位置与进位相加
    let sum = (l1 && l1.val || 0) + (l2 && l2.val || 0) + curry;
    // 更新进位
    curry = Math.floor(sum / 10);

    // 当前位置
    let tempNode = new ListNode(sum % 10);

    // 如果是第一个节点
    if (!resNode) {
      resNode = curNode = tempNode;
    } 
    // 非第一个节点
    else {
      curNode.next = tempNode;
      curNode = curNode.next;
    }

    // 遍历链表
    l1 = l1 ? l1.next : null;
    l2 = l2 ? l2.next : null;
  }
  return resNode;
};

可以大致看到和上面的转换链表的函数相似,只是while循环的条件变为了链表节点,以及多了进位计算。

复杂度

空间复杂度:没使用与数据量相关的额外空间,O(1)

时间复杂度:要算的位数取决于两个数的最大值,假设两个链表长度分别为M,N,时间复杂度为O(Max(M,N))