leetcode
leetcode 1 ~ 50
两数相加

两数相加

难度:

标签:

题目描述

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

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

你可以假设除了数字 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]

 

提示:

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

代码结果

运行时间: 52 ms, 内存: 16.9 MB


/*
思路:
1. 将链表转换为流,使用IntStream累加两个链表的对应节点值。
2. 使用stream和collect方法创建新的链表,处理进位。
*/
 
import java.util.stream.*;
 
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}
 
public class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode current = dummy;
        int carry = 0;
        while (l1 != null || l2 != null || carry != 0) {
            int sum = (l1 != null ? l1.val : 0) + (l2 != null ? l2.val : 0) + carry;
            carry = sum / 10;
            current.next = new ListNode(sum % 10);
            current = current.next;
            l1 = l1 != null ? l1.next : null;
            l2 = l2 != null ? l2.next : null;
        }
        return dummy.next;
    }
}

解释

方法:

该题解的思路是使用链表的遍历实现两数相加。具体做法是:初始化一个虚拟头节点dummy,同时初始化一个指针p指向dummy,再初始化一个变量carry表示进位。然后同时遍历两个链表l1和l2,每次取出两个链表对应位置的数字相加再加上进位,如果相加结果大于等于10则将进位carry置为1,否则置为0。然后将相加结果的个位数作为新节点的值创建新节点,并将指针p后移。当两个链表都遍历完成后,如果进位carry等于1,还需要再创建一个值为1的新节点。最后返回dummy的下一个节点即为相加的结果。

时间复杂度:

O(max(m,n))

空间复杂度:

O(max(m,n))

代码细节讲解

🦆
在`while l1 or l2 or carry == 1:`循环中,为什么要检查`carry == 1`?
这一检查确保即使当两个链表都已经完全遍历完毕,但仍存在一个未处理的进位(即`carry`为1)时,算法能够正确地处理这个进位。通常在最后一次链表元素相加后,如果最高位相加仍然产生了进位,我们需要添加一个额外的节点来表示这个进位,否则最终的数值会少一位,结果不正确。
🦆
你是如何处理两个链表长度不一致的情况的?
当两个链表长度不一致时,算法会继续遍历较长的链表,同时将较短链表视为已经到达尾部,其对应的数值视为0。这通过在链表遍历的`while`循环中检查`l1`和`l2`是否为`None`实现。如果一个链表已经完全遍历完毕,算法将该链表的节点值视为0,并继续处理另一个链表的剩余部分。
🦆
为什么在每次循环结束时需要更新指针`p`和`carry`?
在每次循环中,需要更新指针`p`以连接新创建的节点,这是因为我们需要构建一个新的链表来存储相加的结果。同时,更新`carry`是必要的,因为每次两个数值相加可能产生一个进位,这个进位需要在下一次循环中被加到下一位的计算中。如果不更新这两个值,我们将无法正确构建结果链表和处理进位,这将导致错误的结果。
🦆
在`if num >= 10:`判断中,为什么要将`num`减去10,并将`carry`设置为1?
这个操作是处理十进制加法中的进位情况。当两个数相加(包括进位)的结果`num`等于或大于10时,说明产生了一个进位。在这种情况下,我们需要将个位数作为新节点的值,并将高位的1作为进位传递到下一位的计算中。因此,`num`减去10后的结果是新节点的值,而将`carry`设置为1意味着下一位的计算需要加上这个进位。
🦆
为什么最终返回的是`dummy.next`而不是`dummy`?
在这个算法实现中,`dummy`节点是一个虚拟的头节点,它不存储任何实际的数据,而是用来简化链表操作,使得链表的处理逻辑更加统一和简洁。`dummy.next`指向的是链表中第一个存储实际数据的节点,因此返回`dummy.next`是返回结果链表的开始部分,而不包括没有实际意义的虚拟头节点。

相关问题

字符串相乘

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

 

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

 

提示:

  • 1 <= num1.length, num2.length <= 200
  • num1 和 num2 只能由数字组成。
  • num1 和 num2 都不包含任何前导零,除了数字0本身。

二进制求和

给你两个二进制字符串 ab ,以二进制字符串的形式返回它们的和。

 

示例 1:

输入:a = "11", b = "1"
输出:"100"

示例 2:

输入:a = "1010", b = "1011"
输出:"10101"

 

提示:

  • 1 <= a.length, b.length <= 104
  • ab 仅由字符 '0''1' 组成
  • 字符串如果不是 "0" ,就不含前导零

两整数之和

给你两个整数 ab不使用 运算符 + 和 - ​​​​​​​,计算并返回两整数之和。

 

示例 1:

输入:a = 1, b = 2
输出:3

示例 2:

输入:a = 2, b = 3
输出:5

 

提示:

  • -1000 <= a, b <= 1000

字符串相加

给定两个字符串形式的非负整数 num1num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

 

示例 1:

输入:num1 = "11", num2 = "123"
输出:"134"

示例 2:

输入:num1 = "456", num2 = "77"
输出:"533"

示例 3:

输入:num1 = "0", num2 = "0"
输出:"0"

 

 

提示:

  • 1 <= num1.length, num2.length <= 104
  • num1num2 都只包含数字 0-9
  • num1num2 都不包含任何前导零

两数相加 II

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

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

 

示例1:

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]

示例2:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[8,0,7]

示例3:

输入:l1 = [0], l2 = [0]
输出:[0]

 

提示:

  • 链表的长度范围为 [1, 100]
  • 0 <= node.val <= 9
  • 输入数据保证链表代表的数字无前导 0

 

进阶:如果输入链表不能翻转该如何解决?

数组形式的整数加法

整数的 数组形式  num 是按照从左到右的顺序表示其数字的数组。

  • 例如,对于 num = 1321 ,数组形式是 [1,3,2,1]

给定 num ,整数的 数组形式 ,和整数 k ,返回 整数 num + k数组形式

 

示例 1:

输入:num = [1,2,0,0], k = 34
输出:[1,2,3,4]
解释:1200 + 34 = 1234

示例 2:

输入:num = [2,7,4], k = 181
输出:[4,5,5]
解释:274 + 181 = 455

示例 3:

输入:num = [2,1,5], k = 806
输出:[1,0,2,1]
解释:215 + 806 = 1021

 

提示:

  • 1 <= num.length <= 104
  • 0 <= num[i] <= 9
  • num 不包含任何前导零,除了零本身
  • 1 <= k <= 104