LeetCode HOT 100 —— 2. 两数之和

111 阅读4分钟

题目描述

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

image-20220406211745361.png

提示:

  • 每个链表中的节点数在范围 [1, 100]
  • 0 <= Node.val <= 9
  • 题目数据保证列表表示的数字不含前导零

实现这个函数

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
  // TODO: write Code
};

解题思路

这道题直观的看图就能想到是两个链表相加之后得到一个新的链表

  1. 我们先写出将一个链表搬到另一个链表上,关键代码
var addTwoNumbers = function(l1, l2) {
  // 首先创建一个新的链表,生成一个节点
  let li = new ListNode()
  // 为了防止把li链表的节点顶掉,重新声明一个变量指向li节点
  let pre = li
  // 当l1为null时,结束循环
  while(l1) {
    // 创建li链表的下一个节点,并赋值为l1的val
    pre.next = new ListNode(li.val)
    // 将变量指针向后移动
    pre = pre.next
    // l1指针向后移动
    l1 = l1.next
  }
  // 返回li之后的所有节点,因为新建节点时li头部的值为0,我们得到新的值时li.next之后添加的
  return li.next
};
  1. 在此基础上添加进1的功能并将l2也加进去,我们为进位的值声明一个变量来存储,并且求除数和余数区分出要存储的值和进位值,在while判断时,可能出现l1和l2长度不同的情况,所以采用或运算
var addTwoNumbers = function(l1, l2) {
  let li = new ListNode()
  let pre = li
  // 进位
  let carry = 0
  while(l1 || l2) {
    // 如果长度不同,当l1还有值,l2没有值时,l2.val=null了,没有办法进行运算了
    let x = l1 ? l1.val : 0
    let y = l2 ? l2.val : 0
    // 求和
    let sum = x + y + carry
    // 求除数
    carry = parseInt(sum / 10)
    // 如果进位为1时 求余 否则 等于sum
    carry === 1 ? val = sum % 10 : val = sum
    // 创建值为val的节点并和li连接
    pre.next = new ListNode(val)
    pre = pre.next
    
    // 如果长度不同,next为null,做判断减少一直往后next的操作
    if(l1 !== null) l1 = l1.next
    if(l2 !== null) l2 = l2.next
  }
  // 返回li之后的所有节点,因为新建节点时li头部的值为0,我们得到新的值时li.next之后添加的
  return li.next
};
  1. 还有一种情况要考虑到,就是当l1、l2某一最大长度运算后还需要进1
var addTwoNumbers = function(l1, l2) {
  let li = new ListNode()
  let pre = li
  // 进位
  let carry = 0
  while(l1 || l2) {
    // 如果长度不同,当l1还有值,l2没有值时,l2.val=null了,没有办法进行运算了
    let x = l1 ? l1.val : 0
    let y = l2 ? l2.val : 0
    // 求和
    let sum = x + y + carry
    // 求除数
    carry = parseInt(sum / 10)
    // 如果进位为1时 求余 否则 等于sum
    carry === 1 ? val = sum % 10 : val = sum
    // 创建值为val的节点并和li连接
    pre.next = new ListNode(val)
    pre = pre.next
    
    // 如果长度不同,next为null,做判断减少一直往后next的操作
    if(l1 !== null) l1 = l1.next
    if(l2 !== null) l2 = l2.next
  }
  // 在循环结束后,判断carry === 1,如果存在,继续为next添加一个值为1的节点连接
  if(carry === 1) pre.next = new ListNode(1)
  // 返回li之后的所有节点,因为新建节点时li头部的值为0,我们得到新的值时li.next之后添加的
  return li.next
};

完整代码

注释版

var addTwoNumbers = function(l1, l2) {
   // 首先创建一个新的链表,生成一个节点
  let li = new ListNode()
  // 为了防止把li链表的节点顶掉,重新声明一个变量指向li节点
  let pre = li
  // 进位
  let carry = 0
  // 当l1或l2为null时,结束循环
  while(l1 || l2) {
    // 如果长度不同,当l1还有值,l2没有值时,l2.val=null了,没有办法进行运算了
    let x = l1 ? l1.val : 0
    let y = l2 ? l2.val : 0
    // 求和
    let sum = x + y + carry
    // 求除数
    carry = parseInt(sum / 10)
    // 如果进位为1时 求余 否则 等于sum
    carry === 1 ? val = sum % 10 : val = sum
    // 创建值为val的节点并和li连接
    pre.next = new ListNode(val)
    // 将变量指针向后移动
    pre = pre.next
    // 如果长度不同,next为null,做判断减少一直往后next的操作
    if(l1 !== null) l1 = l1.next
    if(l2 !== null) l2 = l2.next
  }
  // 在循环结束后,判断carry === 1,如果存在,继续为next添加一个值为1的节点连接
  if(carry === 1) pre.next = new ListNode(1)
  // 返回li之后的所有节点,因为新建节点时li头部的值为0,我们得到新的值时li.next之后添加的
  return li.next
};

纯净版

var addTwoNumbers = function(l1, l2) {
  let li = new ListNode()
  let pre = li
  let carry = 0

  while(l1 || l2) {
    let x = l1 ? l1.val : 0
    let y = l2 ? l2.val : 0
    
    let sum = x + y + carry
    carry = parseInt(sum / 10)
    carry === 1 ? val = sum % 10 : val = sum
 
    pre.next = new ListNode(val)
    pre = pre.next
    
    if(l1 !== null) l1 = l1.next
    if(l2 !== null) l2 = l2.next
  }
  if(carry === 1) pre.next = new ListNode(1)
  
  return li.next
};