1. 大数相加
题目描述:以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。
思路:从后往前依次加两个字符串的数字,保留其进位,与下次相加结果再进行相加,直到两个都计算完。最后判断进位是否1(如果有进位的话,一定是1),若有进位,加上去即可。
string solve(string s, string t) {
// write code here
int carry = 0, tmp1 = 0, tmp2 = 0;
int n1 = s.size() - 1, n2 = t.size() - 1;
string res;
while(n1 >= 0 || n2 >= 0){
if(n1 >= 0)
tmp1 = s[n1] - '0'; // 保留第一个字符串的第一个数字
else
tmp1 = 0;
if(n2 >= 0)
tmp2 = t[n2] - '0'; // 保留第二个字符串的第一个数字
else
tmp2 = 0;
int sum = tmp1 + tmp2 + carry; // 将其相加
carry = sum / 10; // 保留进位
res = to_string(sum % 10) + res; // 保留相加后的低位数字
n1--; n2--;
}
if(carry) // 判断是否有进位,若有进位,直接加上即可。
res = '1' + res;
return res;
}
2. 大数相乘
题目描述:给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
思路:
- 两个数字相乘之后的长度最多是两个数字长度之和,即 len(res) <= len(num1) + len(num2);
- 模拟竖式乘法即可,将num1的第i位(高位从0开始)和num2的第j位相乘的结果在乘积中的位置是[i+j, i+j+1],并在每次计算时都要加上上次计算后的 进位,具体看代码与示例。
- 注意去掉前导0,因为申请字符串长度时候是len(num1) + len(num2),但结果长度可能大于这个数,所以会导致前面有若干个0,我们需要将其去掉。
示例:53 * 54
- 申请一个大小为4的字符串s
- 计算3 * 4 = 12,将2保存到 s最后一位,并将进位 1 保存到前一位;
- 计算3 * 5 = 15,将此结果加上上一步的进位1,得16,将6保存到上一位的进位处,并将此步骤的进位1放在6的前一位;
- 计算 5 * 4 = 20, 加上上一步的进位,低位与进位与上一步位置一样
- 计算 5 * 5 = 25 ,加上上一步进位,低位是上一步的进位位置,进位是上一步进位的前一个位置。
- 最后去掉前导0
string multiply(string num1, string num2) {
// 两数相乘的最大位数 就是 sizeof(num1) + sizeof(num2);
// num1的第i位(高位从0开始)和num2的第j位相乘的结果在乘积中的位置是[i+j, i+j+1]
int l1 = num1.size() - 1, l2 = num2.size() - 1;
string res(l1 + l2 + 2, '0');
for(int i = l1; i >= 0; --i){
for(int j = l2; j >= 0; --j){
int tmp = res[i + j + 1] - '0' + (num1[i] - '0') * (num2[j] - '0');
res[i + j + 1] = tmp % 10 + '0'; // 保存低位
res[i + j] += tmp / 10; // 保存进位
}
}
// 删除前导 0
for(int i = 0; i < l1 + l2 + 2; ++i){
if(res[i] != '0')
return res.substr(i);
}
return "0";
}