【C++】415.字符串相加

题目描述:

给定两个字符串形式的非负整数 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 都不包含任何前导零

思路分析

我们先假设给定的不是字符串形式的数字,而是正常的非负整数,那么两数相加就遵循正常的加法运算,即个位数与个位数相加,十位数与十位数相加,依此类推。如果该位计算结果大于9,则向前进位。那么对于字符串形式的数字,我们就需要先将字符数字转换为数值数字,而在转换之前,我们首先要做到能对字符串进行遍历,遍历字符串的方式有很多,这里我们选择比较简单的下标+方括号的形式来进行访问。由于数字相加是由末尾开始,所以在这里我们也一样先拿到字符串最后一个元素的下标:

int end1 = num1.size() - 1;
int end2 = num2.size() - 1;

拿到最后一个元素的下标后,就可以开始进行运算了。而在运算前,我们需要先将字符数字转换为数值数字。除此之外,在转换前,我们还需要先判断下标是否为0,如果为0则说明该字符串已经遍历完了,直接置零即可。所以我们可以这样写:

int val1 = 0;//默认给0
if (end1 >= 0)//如果字符串还没有遍历完,则进行转换val1 = num1[end1] - '0';
int val2 = 0;
if (end2 >= 0)val2 = num2[end2] - '0';

如果觉得这个地方写得有点啰嗦,那么我们也可以用三目运算符进行修改:

int val1 = end1 >= 0 ? num1[end1] - '0' : 0;
int val2 = end2 >= 0 ? num2[end2] - '0' : 0;

得到当前字符所代表的数值后,下面我们就可以对两个值进行相加。相加的时候,需要注意的是上一位的进位也要加进来,我们可以将进位初始化为0,这样末位相加的时候虽然没有进位但也可以用同一个表达式计算:

int next = 0;//进位
int ret = val1 + val2 + next;

加完之后,我们就需要对ret进行判断,如果ret大于9,则说明需要进位,注意这里不要忘记对ret小于9的情况进行处理,因为如果ret小于9的话next就需要置零,如果这里不进行处理,那么之前的进位就会一直得到保留并继续和高位相加导致运算结果出错:

if (ret > 9)//ret大于9的话next进位
{ret -= 10;next = 1;
}
else//否则next置零
{next = 0;
}

实际上,这个地方我们也可以进行简化:

next = ret / 10;//超过10的值除就是1,进位
ret = ret % 10;//模10留下余数

运算结束后,我们就可以将得到的值放回一个新的字符串中作为结果。这里需要注意的是,由于我们是从末位开始计算,因此每得到一位的值应该插入在上一个值的前面:

string strret;
strret.insert(0, 1, '0' + ret);//表示在字符串strret的首位插入1个'0' + ret所表示的字符

到这里,我们一位相加的过程就算结束了,继续往下进应该是高一位相加,直到字符串遍历完毕,因此,刚才的代码我们可以放在一个循环中:

while (end1 >= 0 || end2 >= 0)//end1和end2只要有一个不为0则说明字符串还没有遍历完,继续循环
{	int val1 = end1 >= 1 ? num1[end1] - '0' : 0;int val2 = end2 >= 1 ? num2[end2] - '0' : 0;int ret = val1 + val2 + next;next = ret / 10;ret = ret % 10;strret.insert(0, 1, '0' + ret);strret += ('0' + ret);--end1;--end2;
}

当循环结束时,我们可能会觉得这个时候strret中存放的字符串代表的就是相加后的值了,但是实际上,如果刚才的循环中最高位相加还产生了进位,由于此时字符串已经遍历到最高位,循环将不再进行,所以出了循环之后我们还需要再进行一次判断,如果有进位,就需要把进位插在首字符的位置:

if (next == 1)strret.insert(0, 1, '1');
return strret;

完整代码

string addStrings(string num1, string num2) 
{int end1 = num1.size() - 1;int end2 = num2.size() - 1;int next = 0;string strret;while (end1 >= 0 || end2 >= 0){int val1 = end1 >= 0 ? num1[end1] - '0' : 0;int val2 = end2 >= 0 ? num2[end2] - '0' : 0;int ret = val1 + val2 + next;next = ret / 10;ret = ret % 10;strret.insert(0, 1, '0' + ret);--end1;--end2;}if (next == 1)strret.insert(0, 1, '1');return strret;
}

运行结果:

在这里插入图片描述

从运行结果可以看到,当前我们的代码效率还是比较低的,那么有哪些地方可以优化呢?

后续优化

在刚才的代码中,最影响效率的其实是下面这段代码:

strret.insert(0, 1, '0' + ret);

其原因在于,每插入一个字符,都要将原来的字符向后移动一位,也就是说插入第一个值时会挪一下,插入第二个值会挪两下,依此类推,插入第n个值时会挪n下,可以看到挪动的次数会以一个等差数列的形式呈现,而由等差数列的求和公式可知这是一个n2的数量级,也就是说它的时间复杂度为n2

而如果我们采用尾部插入的形式,每次插入就不需要对原来的数据进行移动,只需要在插入完成后将字符串倒置一下即可;除此之外,由于每次插入都需要扩容,所以为了进一步提高效率,我们可以事先把需要的空间开辟出来,而这个空间刚好就是长的字符串加1。那么根据前面的分析,尾插我们可以用+=实现,而在标准库函数中,可以实现逆置的函数为reversestring类中有用来开辟空间的reserve,那么我们就可以对代码进行如下修改:

string addStrings(string num1, string num2)
{int end1 = num1.size() - 1;int end2 = num2.size() - 1;int next = 0;string strret;strret.reserve(num1.size() > num2.size() ? num1.size() + 1 : num2.size() + 1);//提前开辟空间while (end1 >= 0 || end2 >= 0){int val1 = end1 >= 0 ? num1[end1] - '0' : 0;int val2 = end2 >= 0 ? num2[end2] - '0' : 0;int ret = val1 + val2 + next;next = ret / 10;ret = ret % 10;strret += ('0' + ret);//尾插--end1;--end2;}if (next == 1)strret += '1';reverse(strret.begin(), strret.end());//倒置return strret;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以看到,优化过后的代码运行起来效率就很高了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/140449.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

除静电感测型离子风棒在无尘车间中的应用

除静电感测型离子风棒是一种能够检测静电并及时释放离子的离子风棒&#xff0c;在无尘车间中应用非常广泛。以下是除静电感测型离子风棒在无尘车间中的应用&#xff1a; 防止静电干扰&#xff1a;在无尘车间中&#xff0c;静电干扰会影响电子元器件和仪器设备的正常工作&#x…

最新Discuz3.5论坛多合一聚合支付接口插件源码/支持支付宝和微信支付功能

最新Discuz3.5论坛多合一聚合支付接口插件源码/支持支付宝和微信支付功能&#xff0c;这个插件直接替换了自带的支付接口功能&#xff0c;增强了支付的扩展性&#xff0c;它挺方便实用的&#xff0c;自带了支持支付宝、微信、QQ 钱包官方支付&#xff0c;以及彩虹易支付、虎皮椒…

基于VCO的OTA稳定性分析的零交叉时差模型研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Ai数字人直播系统SaaS源码大开源,源码独立部署助力中小企业发展!

源码独立部署ai数字人直播系统&#xff0c;如果放在上半年的话没有数百万投资几乎是天方夜谭&#xff0c;连想做个数字人代理商少则投资十万多则数十万才能进得了代理门槛。在此期间&#xff0c;数字人市场一度出现了大批不良企业利用网上下载的视频合成源码二次包装后打着数字…

JVS-rules中的基础与复合变量:规则引擎的心脏

JVS-rules中的“变量”概念与编程语言中的变量类似&#xff0c;但它们通常在规则系统中处理条件判断、业务结果复制场景&#xff0c;如下所示&#xff1a; 条件判断&#xff1a;在规则引擎中&#xff0c;规则通常由两个部分组成&#xff1a;条件和分支。变量用于描述条件部分中…

哪个牌子的护眼灯防蓝光效果好?2023防蓝光护眼灯推荐

可以肯定的是&#xff0c;护眼灯一般可以达到护眼的效果。 看书和写字时&#xff0c;光线应适度&#xff0c;不宜过强或过暗&#xff0c;护眼灯光线较柔和&#xff0c;通常并不刺眼&#xff0c;眼球容易适应&#xff0c;可以防止光线过强或过暗导致的用眼疲劳。如果平时生活中需…

“创新启变 聚焦增长”极狐(GitLab)媒体沟通会,共话智能时代软件开发新生态

10 月 18 日 北京 昨日&#xff0c;全球领先 AI 赋能 DevSecOps 一体化平台极狐(GitLab) 在北京举办了主题为“创新启变 聚焦增长”的媒体沟通会。极狐(GitLab) CEO 柳钢就“中国企业数字化转型、软件研发、技术自主可控等热点问题&#xff0c;以及 AI 大模型时代下&#xff0c…

16.SpringBoot前后端分离项目之简要配置一

SpringBoot前后端分离项目之简要配置一 前面对后端所需操作及前端页面进行了了解及操作&#xff0c;这一节开始前后端分离之简要配置 为什么要前后端分离 为了更低成本、更高效率的开发模式。 前端有一个独立的服务器。 后端有一个独立的服务器。两个服务器之间实时数据交换…

OceanBase自动安装部署演示环境demo

OceanBase自动安装部署 前提条件 官方给出硬件条件需要满足以下要求 本文操作系统为&#xff1a;Red Hat Enterprise Linux 8 64 位 下载链接&#xff1a;https://pan.baidu.com/s/1rZ39xJFhk0HdmC4wEJcxvg 提取码&#xff1a;c01x 下载并安装 all-in-one 安装包 执行如下…

程序员接单都在用这六大平台,你呢?

你还在一边熬夜敲代码&#xff0c;一边为自己的健康担忧吗&#xff1f; 你有被工位束缚&#xff0c;为缺乏自由闲暇的时间苦恼吗&#xff1f; 你有因工作交接不顺&#xff0c;给自己的“码农”生活雪上加霜吗&#xff1f; 你是否也在为自己这份“青春饭”&#xff0c;还能吃多久…

2023年中国脱硫石膏产量、均价、综合利用量及市场规模分析[图]

脱硫石膏主要成分和天然石膏一样&#xff0c;为二水硫酸钙CaSO42H2O&#xff0c;含量≥93%。脱硫石膏是FGD过程的副产品&#xff0c;FGD过程是一项采用石灰-石灰石回收燃煤或油的烟气中的二氧化硫的技术&#xff0c;其中2022年中国脱硫石膏产量同比增长2.0%&#xff1b;综合利用…

MATLAB中ss2tf函数用法

目录 语法 说明 示例 质点-弹簧系统 双体振荡器 ss2tf函数的功能是将状态空间表示形式转换为传递函数。 语法 [b,a] ss2tf(A,B,C,D) [b,a] ss2tf(A,B,C,D,ni) 说明 [b,a] ss2tf(A,B,C,D) 将方程组的状态空间表示形式转换为等同的传递函数。ss2tf 返回连续时间方程组…