题目描述
有两个用字符串表示的非常大的大整数,算出他们的乘积,也是用字符串表示。不能用系统自带的大整数类型。
输入描述
空格分隔的两个字符串,代表输入的两个大整数
输出描述
输入的乘积,用字符串表示
示例
输入:
72106547548473106236 982161082972751393
输出:
70820244829634538040848656466105986748
解题思路
假设,两个字符串分别为str1,str2
。长度分别为len1,len2
。则相乘所得的数最长为len1+len2
位。
str2的最后一位(即str2[len2-1]
)与依次与str1的每一位数相乘。
当str2[len2-1]
与str1[len1-1]
相乘,即最后一位和最后一位相乘,所得的乘积加到数组的第0位。
当str2[len2-1]
与str1[len1-2]
相乘,即最后一位和倒数第二位相乘,所得的乘积在加入的时候应该往前移一位,所以应该存到数组的第1位。(因为我们的数组是倒着存结果,所以前移一位应该是加到数组的后一位中。)
因此,相乘和存数的关系是:当str2[i]
与str2[j]
相乘时,乘积存放在数组的第[len1-1-i]+[len2-1-j]
注意:这时得到的数组是倒的。因为我们把个位数的乘积放到了数组的第一位
计算加和时,根据判断乘积与10的大小,来确定是否需要进位。若进位,则将进位与前一位相加,加法如前面。这里的加法我采用的是递归
方法。
代码如下
#include<iostream>
#include<vector>
#include<string>
using std::vector;
using namespace std;
//加法算法,进位采用递归
vector<int> add(vector<int> result, int num, int res)
{
int sum;
sum = result[num] + res;
if (sum >= 10) //有进位
{
int odd = sum % 10;
int ten = sum / 10;
result[num] = odd;
result = add(result, num + 1, ten); //将进位加入下一位
}
else
result[num] = sum;
return result;
}
int main()
{
string str1;//乘数
string str2;//被乘数
cin >> str1 >> str2;
int len1 = str1.size();
int len2 = str2.size();
int n = len1 + len2; //最大可能位数
vector<int> result(n); // 创建空字符串,size为n
char res;
for (int i = len1-1; i >= 0; i--)
{
for (int j = len2-1; j >= 0; j--)
{
int num = (len1 - 1 - i) + (len2 - 1 - j); //下标
int num1 = str1[i] - '0'; //字符串中数组转化为整数
int num2 = str2[j] - '0';
int pro = num1 * num2; //乘积
result = add(result, num, pro); //结果加到数组相应的位置中
}
}
//将数组取出来到字符串里,此时数组是倒序的。
if (result[n - 1] == 0) //我们首先要判断,是不是n位(可能是n-1位)。数组的最后一位是乘积的最高位,看是否为0;
{
n--; //为0,则后续读数不能把最后一位读入。此处将n减1
}
for(int i=0;i<n;i++) //此时n的值可以确定为结果的位数,将数组中的数转化为字符串
{
res= result[n - i - 1] + '0';
cout << res;
}
return 0;
}
优秀算法
这是牛客网排名第一的算法。加法有所不同。他是将进位记下,然后将进位加到下一次的乘积上。但是在每次与被乘数所有的位数乘完一次后,要看看最后一次的乘法有没有进位,然后加到该加的地方,再将进位清零。因为如果再带入循环,移位会变为0,那进位所加的地方就错误了。
#include<iostream>
#include<string>
using namespace std;
//移位进位法
string Mul(string left, string right)
{
size_t Lsize = left.size(); //size_t = unsigned int
size_t Rsize = right.size();
size_t Size = Lsize + Rsize; //最长位数
string res(Size, '0');
int takevoer = 0;//进位
int offset = 0;//移位
size_t idx = 1, j = 1;
for (idx = 1; idx <= Rsize; ++idx)
{
takevoer = 0;
int rightnum = right[Rsize - idx] - '0';
//计算每一位与left相乘
for (j = 1; j <= Lsize; ++j)
{
char resBit = res[Size - j - offset] - '0'; //取res存储对应位的数字
int num = rightnum * (left[Lsize - j] - '0') + takevoer + resBit;//将两个数相乘,将进位和数组内存的数加入
takevoer = num / 10;
res[Size - j - offset] = num % 10 + '0'; //先把个位存进去
}
if (takevoer != 0)
res[Size - j - offset] = takevoer + '0';
offset++;
}
//如果没有进位的话,res最高位没有数字
if (res[0] == '0')
res.erase(0, 1);
return res;
}
int main()
{
string s1, s2;
cin >>s1 >> s2;
string str=Mul(s1,s2);
cout << str << endl;
}