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

news2025/1/12 1:57:41

题目描述:

给定两个字符串形式的非负整数 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.coloradmin.cn/o/1109043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

XPS虽没流行,但还在使用!在Windows 10中打开XPS文件的最佳方法

当Windows Vista发布时&#xff0c;微软推出了XPS格式&#xff0c;这是PDF的替代品。XPS文件格式并不是什么新鲜事&#xff0c;但从未获得过多大的吸引力。 因此&#xff0c;XPS&#xff08;XML Paper Specification&#xff09;文件是微软对Adobe PDF文件的竞争对手。尽管XPS…

Kafka三种认证模式,Kafka 安全认证及权限控制详细配置与搭建

Kafka三种认证模式,Kafka 安全认证及权限控制详细配置与搭建。 Kafka三种认证模式 使用kerberos认证 bootstrap.servers=hadoop01.com:9092,hadoop02.com:9092,hadoop03.com:9092,hadoop04.com:9092 security.

分布式微服务技术栈-SpringCloud<Eureka,Ribbon,nacos>

微服务技术栈 一、微服务 介绍了解1 架构结构案例与 springboot 兼容关系拆分案例拆分服务拆分-服务远程调用 2 eureka注册中心Eureka-提供者与消费者Eureka-eureka原理分析Eureka-搭建eureka服务Eureka-服务注册Eureka-服务发现 3 Ribbon组件 负载均衡Ribbon-负载均衡原理Ribb…

深入探求:中国精益生产与管理实践的崭新视角

经过多方位的了解&#xff0c;比之制造行业上的精益管理上的表现情况&#xff0c;认为目前国内的精益生产精益管理实践仍处于自我认知的水平。目前很多的企业前进的步伐还是主要依据市场经济发展所衍生出来的较为先进的工具运用&#xff0c;其战略性的管理处于局部优化再而达到…

2.3 如何使用FlinkSQL读取写入到JDBC(MySQL)

1、JDBC SQL 连接器 FlinkSQL允许使用 JDBC连接器&#xff0c;向任意类型的关系型数据库读取或者写入数据 添加Maven依赖 <dependency><groupId>org.apache.flink</groupId><artifactId>flink-connector-jdbc</artifactId><version>3.1…

基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持自定义业务表单流程的集成方法与步骤(一)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 由于大家最自定义业务表单的整个集成方法还不熟悉&#xff0c;下面大概介绍一下这个流程与方法。 1、首先…

顿号在键盘上怎么打?教你4个输入方法!

“朋友们&#xff0c;我正在准备一篇期末论文&#xff0c;但是文章里的顿号我一直输入不了。顿号在键盘上应该怎么输入呀&#xff1f;谁能教教我呢&#xff1f;非常感谢&#xff01;” 在使用电脑编辑文档时&#xff0c;我们可能经常需要输入顿号。但有些朋友还不知道顿号在键盘…

Java 关键字:synchronized详解

synchronized详解 基本使用源码解析常见面试题好书推荐 基本使用 Java中的synchronized关键字用于在多线程环境下确保数据同步。它可以用来修饰方法和代码块 当一个线程访问一个对象的synchronized方法或代码块时&#xff0c;其他线程将无法访问该对象的其他synchronized方法或…

ppt录屏怎么导出来?学会这个,让分享更容易

ppt已经成为了日常工作与学习中必不可少的工具&#xff0c;而ppt屏幕录制功能&#xff0c;可以方便用户将他人的演讲或视频中的内容记录下来&#xff0c;以便进一步学习与研究。录制ppt演示并将其导出为视频文件&#xff0c;可以帮助我们进行分享&#xff0c;但是很多人不知道p…

el-upload实现上传文件夹

背景&#xff1a;如图一所示&#xff0c;最下面有一个黄色上传文件按钮&#xff0c;为手动上传而且上传区域有上传文件和上传文件夹的区分 所以需要在点击了上传文件夹做特殊处理使得el-upload可以上传文件夹 一、template区域 <el-uploadclass"upload-file"dra…

Prometheus metrics数据抓取解析

Prometheus node的监控数据如链接展示&#xff0c;我们希望能更加方便的看到监控数据&#xff0c;shodan对Prometheus metrics 的数据做了格式化处理。172.96.3.215:9100/metricshttp://172.96.3.215:9100/metrics 本文我自己实现了一个命令行工具&#xff0c;可以输出类shodan…

STR时,android发生了什么(一)

在QA的基线中&#xff0c;触发android进入STR流程的方式是向qvm注入power key 按下松开的操作(对于单android的基线&#xff0c;我的理解方式应该也是相同的&#xff0c;都是模拟了power key的按下松开操作&#xff09;。 这个按键操作会通过virtio上报到VHAL层&#xff08;下…

用CSS+SVG做一个优雅的环形进度条

开门见山 先上最终效果图&#xff1a;&#xff08;Demo 传送门&#xff09; 其中进度、尺寸、环宽和颜色都可以非常方便地进行控制。 核心原理&#xff1a; 利用两个重叠的圆环形&#xff0c;通过对上层圆环弧长的控制来表示进度&#xff0c;下层圆环则作为辅助&#xff0c;…

59 分割等和子集

分割等和子集 NP 完全问题&#xff08;01背包&#xff09;题解1 二维DP题解2 空间优化DP&#xff08;改为1D&#xff09; 给你一个只包含正整数的非空数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&a…

Ubuntu - 安装Java 11

在Ubuntu上安装Java 11的最简单方法是通过使用OpenJDK 11。以下是安装Java 11的步骤&#xff1a; 打开终端。 更新包列表&#xff0c;以确保获取最新的软件信息&#xff1a; sudo apt update 安装OpenJDK 11&#xff1a; sudo apt install openjdk-11-jdk 安装后&#xf…

独家原创,改进的智能优化算法

↖加关注这种话银家怎么好意思说出口嘛-- 声明&#xff1a;对于作者的原创代码&#xff0c;禁止转售倒卖&#xff0c;违者必究&#xff01; 以下代码均为作者独家原创&#xff0c;大家可以拿走去水水论文。 有一些质量较高的代码&#xff0c;可以发一些高质量的期刊&#xff0c…

LoogArch 指令集学习

1 SoC_Lite片上系统结构 mycpu和dram、confreg之间有一个“一分二”部件。这是因为在LoongArch指令系统架构下&#xff0c;所有I/O设备的寄存器都是采用memory mapped方式访问的。我们这里实现的confreg也不例外。Memory mapped的访问方式意味I/O设备中的寄存器各自都有一个唯一…

【大数据】Kafka 入门简介

Kafka 入门简介 1.什么是 Kafka2.Kafka 的基本概念3.Kafka 分布式架构4.配置单机版 Kafka4.1 下载并解压包4.2 启动 Kafka4.3 创建 Topic4.4 向 Topic 中发送消息4.5 从 Topic 中消费消息 5.实验5.1 实验一&#xff1a;Python 实现生产者消费者5.2 实验二&#xff1a;消费组实现…

防蓝光护眼灯有用吗?教你认识防蓝光护眼台灯

要不是亲眼所见&#xff0c;真的很难想象一个台灯用处如此大&#xff0c;护眼效果非常明显。说起来很久没有用过护眼灯具了&#xff0c;这次用过之后有着明显的反差&#xff0c;如果能给孩子用&#xff0c;那将大大保障了孩子的用眼、护眼问题。我自己是用来睡前看书的&#xf…

Hadoop集群资源管理器-YARN

1.YARN 简介 Apache YARN (Yet Another Resource Negotiator) 是 hadoop 2.0 引入的集群资源管理系统。用户可以将各种服务框架部署在 YARN 上,由 YARN 进行统一地管理和资源分配。 2.YARN架构