在实际编程中,我们常常会遇到需要处理大整数相加的情况。由于编程语言中基本数据类型所能表示的整数范围有限,当需要处理的整数超出这个范围时,我们就不能直接使用基本数据类型进行计算。 此时,我们可以将大整数以字符串的形式存储,通过逐位相加的方式来实现大整数的加法运算。 本文将围绕这个问题,详细介绍三种不同实现方式,从基础版逐步优化到性能更优的版本。
class Solution {
public:
string addStrings(string num1, string num2)
{
int end1 = num1.size() - 1;;//从字符串尾部遍历
int end2 = num2.size() - 1;
int next = 0;//进位
string s;
while (end1 >= 0 || end2 >= 0 )//两个字符串都遍历完成才结束
{
int n1 = end1 >= 0 ? num1[end1--] - '0' : 0;//先判断下标是否合法,防止越界
int n2 = end2 >= 0 ? num2[end2--] - '0' : 0;
int ret = n1 + n2 + next;
next = ret / 10;
ret = ret % 10;
s.insert(0, 1, ret + '0');
}
if (next == 1)
{
s.insert(0, 1, '1');
}
return s;
}
};
end1
和 end2
,从这里开始逐位相加。同时,我们还需要一个变量 next
来记录进位,初始值为 0。另外,我们创建一个空字符串 s
用于存储相加的结果。while
循环,只要两个字符串中有一个还未遍历完,就继续循环。在每次循环中,我们先判断当前下标是否合法,如果合法则取出对应位置的数字,否则将其视为 0。然后将这两个数字与进位 next
相加,得到当前位的和 ret
。接着,更新进位 next
为 ret
除以 10 的结果,ret
则取 ret
对 10 取模的结果。最后,将 ret
转换为字符并插入到字符串 s
的开头。s
的开头。这种实现方式的时间复杂度较高,主要是因为在字符串 s
的开头插入字符的操作会导致字符串元素的移动,时间复杂度为O(n) ,其中 n是字符串的长度。因此,总的时间复杂度为 O(n²)。
class Solution {
public:
string addStrings(string num1, string num2)
{
int end1 = num1.size() - 1;;//从字符串尾部遍历
int end2 = num2.size() - 1;
int next = 0;//进位
string s;
while (end1 >= 0 || end2 >= 0)//两个字符串都遍历完成才结束
{
int n1 = end1 >= 0 ? num1[end1--] - '0' : 0;//先判断下标是否合法,防止越界
int n2 = end2 >= 0 ? num2[end2--] - '0' : 0;
int ret = n1 + n2 + next;
next = ret / 10;
ret = ret % 10;
s += ret + '0';//先尾插
}
if (next!=0)//防止丢失最后进位的数
{
s += next + '0';
}
reverse(s.begin(), s.end());//再反转
return s;
}
};
为了避免在字符串开头插入字符带来的性能开销,我们可以采用尾插的方式:
在每次循环中,将当前位的结果字符直接添加到字符串 s
的末尾,这样时间复杂度为O(n) 。循环结束后,由于结果是从低位到高位添加到字符串中的,所以我们需要将字符串反转,得到正确的顺序。
这种实现方式的时间复杂度为 O(n),其中 是两个字符串中较长的那个的长度。因为我们只需要遍历一次字符串,并且尾插和反转操作的时间复杂度都是O(n) 。
class Solution {
public:
string addStrings(string num1, string num2)
{
int end1 = num1.size() - 1;;//从字符串尾部遍历
int end2 = num2.size() - 1;
int next = 0;//进位
string s;
s.reserve(max(num1.size(), num2.size()) + 1);//直接一次扩容完成
while (end1 >= 0 || end2 >= 0)//两个字符串都遍历完成才结束
{
int n1 = end1 >= 0 ? num1[end1--] - '0' : 0;//先判断下标是否合法,防止越界
int n2 = end2 >= 0 ? num2[end2--] - '0' : 0;
int ret = n1 + n2 + next;
next = ret / 10;
ret = ret % 10;
s += ret + '0';//先尾插
}
if (next!=0)//防止丢失最后进位的数
{
s += next + '0';
}
reverse(s.begin(), s.end());//再反转
return s;
}
};
在尾插优化版的基础上,我们进一步考虑字符串扩容的问题。
当我们使用 +=
操作向字符串中添加字符时,如果字符串的容量不足,会自动进行扩容操作,而扩容操作会涉及到内存的重新分配和数据的复制,这会带来一定的性能开销。
为了避免这种情况,我们可以在开始时就使用 reserve
方法为字符串预留足够的空间,这样就可以避免多次扩容。
这种实现方式的时间复杂度仍然为O(n) ,但由于减少了扩容操作,实际运行时间会更短,性能更优。
通过对大数相加问题的三种不同实现方式的分析,我们可以看到,从基础版到尾插优化版再到扩容优化版,性能逐步提升。在实际编程中,我们应该根据具体情况选择合适的实现方式,同时要注意代码的性能优化,避免不必要的开销。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有