近日参加一个笔试,遇到大数乘法问题,这是一个经典的算法题。所谓大数乘法问题其实就是这样的:输入两个整数,要求输出这两个数的乘积。输入的数字可能超过计算机内任何数据的存储范围。这里主要需要注意的点就是需要使用字符串或者字符数组来存储这两个大数以及他们的结果,还有乘法计算过程中存在乘法进位和加法进位。
我先自己尝试写了一个答案,思路就是模拟手写竖式乘法。
static string MYMULTIPLY(const string &number1, const string &number2)
{
int length1 = number1.size();
int length2 = number2.size();
string result = "";
if (length1 == 0 || length2 == 0)
{
result = "error";
return result;
}
int *iresult;
iresult = (int*)malloc(sizeof(int) * (length1 + length2 + 1));
memset(iresult, 0, sizeof(int) * (length1 + length2 + 1));
for(int i = length1 - 1, x = 0; i >= 0; i--, x++)
{
int numA = number1[i] - 48;
int value1 = 0;
int value2 = 0;
int multiFlag = 0;//乘法进位数
int addFlag = 0;//加法进位数
for(int j = length2 - 1, y = 0; j >= 0; j--, y++)
{
int numB = number2[j] - 48;
value1 = numA * numB + multiFlag;
multiFlag = value1 / 10;
value1 = value1 % 10;
value2 = (iresult[x+y]) + value1 + addFlag;
addFlag = value2 / 10;
iresult[x+y] = (value2 % 10);
}
iresult[x + length2] += (multiFlag + addFlag);
}
//逆序
int i = 0;
for(i = length1 + length2 - 1; i >= 0; i--)
{
if(iresult[i] != 0)
break;
}
for(; i >= 0; i--)
{
result = result + (char)(iresult[i]+48);
}
free(iresult);
return result;
}
这个方法虽然能得出结果,但是太难看了,特别是计算每一位相乘的结果和进位的那一段代码。之后,我就把这段代码改进了一下,将每一位之间的乘法和进位计算分开来。
static string MULTIPLY(string number1, string number2)
{
int i, j;
int *iresult;
int length1 = number1.size();
int length2 = number2.size();
string result = "";
reverse(number1.begin(), number1.end());
reverse(number2.begin(), number2.end());
if (length1 == 0 || length2 == 0)
{
result = "error";
return result;
}
iresult = (int*)malloc(sizeof(int) * (length1 + length2 + 1));
memset(iresult, 0, sizeof(int) * (length1 + length2 + 1));
//每一位相乘
for(i = 0; i < length1; i++)
{
for(j = 0; j < length2; j++)
{
iresult[i+j] += ((number1[i] - 48) * (number2[j] - 48));
}
}
//进位运算
int carry = 0;
for(i = 0; i < length1 + length2; i++)
{
int value = iresult[i] + carry;
iresult[i] = value % 10;
carry = value / 10;
}
for(i = length1 + length2 - 1; i >= 0; i--)
{
if(iresult[i] != 0)
break;
}
for(; i >= 0; i--)
{
result = result + (char)(iresult[i]+48);
}
free(iresult);
if(result == "") result = "0";
return result;
}
当然这个问题还有分治乘法,快速傅里叶等算法,这个就不是在笔试或者面试的时候能快速写出来的了。有兴趣大家可以继续深入了解下。