415. 字符串相加(Add Strings)

频次 ★★★★ · 难度 🟢 · 高频:字节/腾讯/美团/阿里

题目

给定两个非负整数(以字符串形式给出),计算它们的和并同样以字符串形式返回。不能使用 BigInteger 或直接将输入转为整数。

示例

输入: "11", "123"
输出: "134"

输入: "456", "77"
输出: "533"

输入: "0", "0"
输出: "0"

思路

双指针从右向左逐位模拟竖式加法:两个指针 ij 分别指向两个字符串的末尾,用 carry 记录进位。每次取出当前位的数字(如果指针已到头则取 0),相加后 % 10 为当前位结果,/ 10 为进位。最后如果还有进位需要在最前面补 1

因为是从低位向高位计算,每位的数字要加到结果字符串的头部(StringBuilder.insert(0, ...)),或者先追加到 StringBuilder 末尾再整体反转。

代码

public String addStrings(String num1, String num2) {
    StringBuilder sb = new StringBuilder();
    int i = num1.length() - 1, j = num2.length() - 1;
    int carry = 0;
 
    while (i >= 0 || j >= 0 || carry != 0) {
        int digit1 = (i >= 0) ? num1.charAt(i) - '0' : 0;
        int digit2 = (j >= 0) ? num2.charAt(j) - '0' : 0;
        int sum = digit1 + digit2 + carry;
        sb.append(sum % 10);
        carry = sum / 10;
        i--;
        j--;
    }
 
    return sb.reverse().toString();
}

复杂度

  • 时间:O(max(m, n)) — m、n 分别是两个字符串的长度
  • 空间:O(max(m, n)) — 结果字符串的长度(不算输入)

边界条件

  • 两个字符串都是 "0":循环一次后 sum = 0carry = 0,结果 "0"
  • 一个为空(题目说了非负整数,不会为空串,但防御性考虑):如果允许空串,当作 "0" 处理即可。
  • 不同长度:如 "999" + "1",短字符串走完后只剩长的部分和进位 carry,循环条件中的 i >= 0 || j >= 0 保证继续处理剩余位数。
  • 最高位产生进位:如 "9" + "1" = "10",循环条件中的 carry != 0 保证最后多输出一位 "1"

变式

  • 二进制相加67. 二进制求和):思路完全一样,只是逢 2 进 1。
  • 字符串相乘43. 字符串相乘):需要每一位相乘后错位相加,是本题的扩展。
  • 链表版两数相加:见 2. 两数相加(逆序存储,正序还需先反转)。

易错点

  • 字符转数字要用 num.charAt(i) - '0',不是 Integer.parseInt(int) num.charAt(i)(后者是 ASCII 码)。
  • 结果用 sb.reverse() 而不是每算出一位就 sb.insert(0, ...)——后者每次插入是 O(n) 操作,整体变成 O(n²)。
  • 循环条件不能漏掉 carry != 0:所有位数都处理完但最后还有进位时,需要多生成一位。“9”+“1” 就是典型例子。
  • 指针 ij 每轮循环都要减 1,不能遗漏(容易忘记在条件分支中减)。

面试追问

  • 字符串相加和链表相加(如 2. 两数相加)的本质区别是什么? 字符串高位在左、低位在右,只能从右向左模拟竖式,最后要反转结果;链表版因为是逆序存储,个位在链表头,从左到右遍历就是低位到高位,不用反转。两者的核心都是”逐位计算 + carry 进位 + 收尾进位”三段式。
  • 如果字符串可能包含前导零(如 “00123”),需要处理吗? 题目通常约定”非负整数不包含前导零,除非数字本身就是 0”。如果前导零可能出现,一种做法是计算结果后去掉前导零(但注意 “0” 本身要保留),另一种是计算时不受影响(前导零不影响加法的正确性)。
  • 如果要支持浮点数字符串相加,该怎么做? 先找到小数点位置,把整数部分和小数部分分别对齐(小数部分补零到长度一致),然后分别做整数加法和小数加法,最后处理小数部分向整数部分的进位。

关联题

  • 同套路:2. 两数相加(链表版)、66. 加一(数组版)
  • 进阶:43. 字符串相乘(多位数乘法,每位相乘后错位相加)
  • 知识点:大数模拟的 carry 中间变量 + 收尾补进位的三段式是”任意进制加法”的通用骨架