当前位置: 首页 > news >正文

415. 字符串相加

目录

题目链接:

题目:

解题思路:

代码:

总结:


题目链接:

415. 字符串相加 - 力扣(LeetCode)

题目:

415. 字符串相加

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

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

解题思路:

使用StringBuffer可变字符串来接受每位的结果,然后使用i,j双指针从 每个字符串的末尾开始相加,使用carry来表示每位结果和下一位的进位

代码:

class Solution {public String addStrings(String num1, String num2) {StringBuilder s=new StringBuilder("");int i=num1.length()-1;int j=num2.length()-1;int carry=0;while(i>=0||j>=0){carry+=i>=0?num1.charAt(i)-'0':0;carry+=j>=0?num2.charAt(j)-'0':0;s.append(carry%10);carry/=10;i--;j--;}if(carry==1) s.append(1);return s.reverse().toString();}
}

以下从问题背景、代码结构、逐行逻辑、算法细节、边界场景、优缺点、扩展对比等维度,深入拆解这段字符串相加代码,帮你吃透核心逻辑(
一、问题背景:字符串相加的意义
LeetCode 第 415 题要求模拟手工加法:把两个用字符串表示的非负整数(可能非常大,超出 long 范围),按「竖式加法」规则求和,返回字符串结果。
核心约束:不能直接转整数(比如 Integer.parseInt),必须手动实现进位逻辑 —— 这正是这段代码要解决的问题。
二、整体思路:竖式加法的模拟
手工计算加法时,我们会:

对齐末尾:从个位(字符串末尾)开始逐位相加;
处理进位:每一位的和 = 位 1 + 位 2 + 进位,结果取个位(sum % 10),新的进位取十位(sum / 10);
处理剩余进位:如果最后进位还有剩余(比如 99 + 1 最后进位为 1),要补到结果里。

这段代码完全模拟了这个过程,用指针、进位变量、字符串拼接实现。
三、代码逐行拆解(核心逻辑)
类与方法定义
java
运行
class Solution {
    public String addStrings(String num1, String num2) {

Solution 是 LeetCode 约定的解题类,addStrings 是题目要求的方法,入参是两个字符串 num1、num2,返回值是相加后的字符串。
初始化变量
java
运行
StringBuilder s = new StringBuilder("");
int i = num1.length() - 1;
int j = num2.length() - 1;
int carry = 0;

StringBuilder s:动态拼接结果。因为要频繁在末尾追加字符(类似手工从个位开始写结果),最后再反转,比 String 高效。
i、j:双指针,分别指向 num1、num2 的末尾字符(模拟手工从个位开始遍历)。
carry:进位值(初始为 0),记录每一位相加后的进位(比如 8+5=13,进位 1)。
核心循环:逐位相加
java
运行
while (i >= 0 || j >= 0) {
    carry += i >= 0 ? num1.charAt(i) - '0' : 0;
    carry += j >= 0 ? num2.charAt(j) - '0' : 0;
    s.append(carry % 10);
    carry /= 10;
    i--;
    j--;
}

这是代码的灵魂,逐行拆解:

处理指针越界:
i >= 0 ? num1.charAt(i) - '0' : 0:如果 i 没越界(还能取到 num1 的字符),就取该位的数字(char 转 int,通过 - '0' 实现);否则补 0(比如 num1 比 num2 短,高位补 0 对齐)。
同理处理 num2 的 j 指针。
累加进位与当前位:
carry 先加上 num1 当前位,再加上 num2 当前位 ——模拟手工加法的「当前位总和 = 位 1 + 位 2 + 进位」。
计算当前位结果,更新进位:
s.append(carry % 10):当前位总和的个位是结果位(比如 13 % 10 = 3,记为当前位结果)。
carry /= 10:当前位总和的十位是新的进位(比如 13 / 10 = 1,进位更新为 1)。
指针前移:
i--; j--;:双指针同时左移,处理下一位(更高位)。
处理最后进位
java
运行
if (carry == 1) s.append(1);

循环结束后,如果还有进位(比如 99 + 1,最后进位是 1),需要补到结果最高位。
反转结果
java
运行
return s.reverse().toString();

因为我们是从个位开始拼接结果(比如先拼 3,再拼 2,得到 "32"),所以需要反转成正常顺序("23")。
四、算法细节:为什么这么写?
1. 为什么用 StringBuilder?
String 是不可变对象,每次 + 都会创建新对象,效率低;
StringBuilder 是可变的,append 直接操作数组,效率高,适合频繁拼接。
2. 为什么从末尾开始遍历?
手工加法是从低位(个位)开始算,字符串的末尾正好对应数字的低位,所以双指针从 length-1 开始,天然契合手工逻辑。
3. 进位的处理逻辑
carry 变量贯穿整个过程:

初始为 0(还没相加时,进位是 0);
每一位计算后,carry 被更新为「新的进位」;
循环结束后,可能还有剩余进位(比如 999 + 1,最后进位是 1),必须补上。
4. 字符转数字的细节
num1.charAt(i) - '0':

char 本质是 Unicode 编码,'0' 的 ASCII 是 48,'1' 是 49…… 所以用 char - '0' 可以把字符转成对应的数字(比如 '5' - '0' = 5)。
五、边界场景测试
场景 1:普通情况(位数相同)
输入:num1 = "123", num2 = "456"
过程:

个位:3+6=9 → 结果 9,进位 0
十位:2+5=7 → 结果 7,进位 0
百位:1+4=5 → 结果 5,进位 0
反转前:"975" → 反转后:"573"(正确)
场景 2:位数不同
输入:num1 = "99", num2 = "1"
过程:

个位:9+1=10 → 结果 0,进位 1
十位:9+0+1=10 → 结果 0,进位 1
循环结束,进位 1 → 补 1
反转前:"001" → 反转后:"100"(正确)
场景 3:全零
输入:num1 = "0", num2 = "0"
过程:

个位:0+0=0 → 结果 0,进位 0
循环结束,进位 0 → 无补充
反转前:"0" → 反转后:"0"(正确)
场景 4:最大进位
输入:num1 = "9999", num2 = "9999"
过程:

每一位相加都会产生进位,最后进位 1 补上,结果 19998(代码可正确处理)。
六、代码优缺点分析
优点:
高效:
时间复杂度 O(max(M, N))(M、N 是两个字符串长度),只遍历一次。
空间复杂度 O(max(M, N))(StringBuilder 存储结果,反转后不额外占空间)。
逻辑清晰:
完美模拟手工加法,双指针、进位、拼接、反转的流程,和人类思维一致,易理解。
鲁棒性:
处理了「位数不同」「最后进位」等所有边界,通过测试。
缺点(几乎没有,硬找的话 ):
依赖 StringBuilder 的 reverse,如果对反转有性能洁癖(实际影响极小),可以用数组手动控制顺序 —— 但没必要,reverse 内部是双指针交换,效率很高。
七、与其他解法对比
解法 2:补零后遍历(低效版)
java
运行
// 伪代码,不推荐
while (num1 长度 < num2 长度) num1 = "0" + num1;
while (num2 长度 < num1 长度) num2 = "0" + num2;
// 然后从 0 开始遍历

缺点:补零会产生额外字符串,空间复杂度更高(尤其数字极大时),不如双指针灵活。
解法 3:递归(不实用)
递归实现手工加法,会因栈深度(位数)过大导致栈溢出,且代码复杂,不如迭代直观。
八、扩展:如何支持负数?
如果题目扩展为「字符串表示的整数(可能负)」,需要额外处理:

提取符号(+/-);
处理绝对值相加或相减(借位逻辑);
符号与结果的拼接。
这段代码的「无符号加法」是基础,扩展时可在此逻辑上封装。
九、总结:代码的价值
这段代码把人类手工加法的逻辑,完美映射到代码中:

双指针模拟「从低位到高位」;
carry 模拟「进位传递」;
StringBuilder 模拟「草稿纸写结果」;
反转操作修复「低位先写」的顺序问题。

它不仅解决了 LeetCode 问题,更传递了 **「算法是人类思维的代码化」** 这一核心思想 —— 理解手工逻辑,再用循环、指针、进位等编程工具实现,就是算法的本质。

如果你在面试中写出这段代码,面试官不仅能看到你对问题的理解,更能看到你把现实逻辑转化为代码的能力 —— 这才是算法题考察的核心。

总结:

本文深入解析了LeetCode 415题&quot;字符串相加&quot;的解法。该题要求模拟手工加法,在不直接转换整数的情况下,对两个字符串形式的非负整数进行相加。文章详细拆解了代码实现思路:使用双指针从字符串末尾开始遍历,逐位相加并处理进位,最后反转字符串得到正确结果。重点分析了核心逻辑、边界场景处理、算法复杂度,并对比了其他解法。该方案时间复杂度O(max(M,N)),空间复杂度O(max(M,N)),完美模拟了手工加法过程,具有良好的鲁棒性和可扩展性。

http://www.xdnf.cn/news/1310689.html

相关文章:

  • Java设计模式之《工厂模式》
  • 【Java web】HTTP 协议详解
  • HTTP 1.0, 2.0 和 3.0 有什么区别?
  • OpenAI TTS API + Web 前端 AudioContext 实战方案
  • (论文速读)ViDAR:视觉自动驾驶预训练框架
  • leetcode-139. 单词拆分-C
  • 中本聪思想与Web3的困境:从理论到现实的跨越
  • 从依赖到自研:一个客服系统NLP能力的跃迁之路
  • 昇腾AI自学Day2-- 深度学习基础工具与数学
  • Spring AI 进阶之路01:三步将 AI 整合进 Spring Boot
  • 异构数据库兼容力测评:KingbaseES 与 MySQL 的语法・功能・性能全场景验证解析
  • linux设备驱动之字符设备驱动
  • Python代码规范与静态检查(ruff/black/mypy + pyproject.toml + Makefile)自动化工具链介绍
  • 【LeetCode 热题 100】70. 爬楼梯——(解法二)自底向上
  • 在鸿蒙应用中快速接入地图功能:从配置到实战案例全解析
  • ISO27001 高阶架构 之 支持 -2
  • PHP域名授权系统网站源码/授权管理工单系统/精美UI/附教程
  • 广东省省考备考(第七十八天8.16)——资料分析、判断推理(强化训练)
  • Spring AMQP如何通过配置文件避免硬编码实现解耦
  • Linux -- 文件【下】
  • 深度解析和鲸社区热门项目:电商双 11 美妆数据分析的细节与价值
  • 41 C++ STL模板库10-容器3-list
  • 正点原子【第四期】Linux之驱动开发篇学习笔记-1.1 Linux驱动开发与裸机开发的区别
  • docker-compose-mysql-定时备份数据库到其他服务器脚本
  • 【机器学习深度学习】OpenCompass:支持的开源评估数据集及使用差异
  • RemoteCtrl-初步的网络编程框架搭建
  • 安全审计-firewall防火墙
  • 算法训练营day52 图论③ 101.孤岛的总面积、102.沉没孤岛、103.水流问题、104.建造最大岛屿
  • 基于Uni-app+vue3实现微信小程序地图固定中心点范围内拖拽选择位置功能(分步骤详解)
  • MySQL 配置性能优化赛技术文章