一、概述
输入两个字符串类型的数字,输出字符串类型的两数字的积。
题目很容易理解,实际做起来我就是按平常做乘法的思路做的。
写了两个函数:字符串与一位数字相乘和两字符串相加,然后循环调用。
时空复杂度太垃圾了。
好的算法速度比我快四十倍不止。
二、分析
1、我的算法
以111*99来举例吧。我是将其分解为111*9和111*9然后后面加一个0两个部分做的。
首先是string乘以一位char,即111*9,返回string的999;
同理返回第二个111*9的999;
然后第二个999后面加0,变为9990;
第一个和第二个做加法999+9990=10989。
有一些细节要注意:
对于乘法函数,注意进位add应为tmp+add/10,而不是直接置1,不要和加法弄混了;另外每一位的计算上,要先让tmp与add相加,然后对10取余,不能直接tmp取余。
在num1都乘完之后还要判断add的值是否为0。
对于加法函数,第一件事是对齐,即短的前面加0;其余的参见乘法函数。
在主函数中,注意做完乘法后在后面加0,不要加错。如果结果全是0要输出0而不是0000000。
代码如下,很繁琐但是很清晰:
class Solution {
string Smulti(string num1, char num2)
{
string result = "";
int n = num2 - '0';
int add = 0;
for (int i = num1.size() - 1; i >= 0; i--)
{
int tmp;
tmp = (num1[i] - '0')*n;
result = char((tmp + add)%10 + '0') + result;
add = (tmp+add)/10;
}
if (add != 0)
result = char(add+'0') + result;
return result;
}
string Sadd(string num1, string num2)
{
int len1 = num1.size();
int len2 = num2.size();
if (len1<len2)
{
for (int i = 0; i<len2 - len1; i++)
num1 = '0' + num1;
}
else
{
for (int i = 0; i<len1 - len2; i++)
num2 = '0' + num2;
}
int len = num1.size();
string res = "";
int add = 0;
for (int i = len-1; i>=0; i--)
{
int tmp;
tmp = num1[i] - '0' + num2[i] - '0';
res = char((tmp+add) % 10 + '0')+res;
add = (tmp + add) / 10;
}
if (add != 0)
res = char(add + '0') + res;
return res;
}
public:
string multiply(string num1, string num2) {
string res = "";
int len1 = num1.size();
int len2 = num2.size();
if (len1<len2)
{
string tmp = num1;
num1 = num2;
num2 = tmp;
}
int len = num2.size();
for (int i = len - 1; i >= 0; i--)
{
string tmp = Smulti(num1, num2[i]);
for (int j = 0; j<len - i-1; j++)
tmp = tmp + '0';
res = Sadd(res, tmp);
}
for (int i = 0; i < res.size(); i++)
if (res[i] != '0')
return res;
return "0";
}
};
2、较好的算法
看上面这幅图,以123*456为例说明。注意到两个一位数相乘最多就是两位数,最终结果就是两位数中的一位叠加。
然后呢,18中,1在从左往右第4个,8在第5个;18是由3*6得到的,3在第2位,6也在第2位;继续验证其他,可得第i位和第j位相乘,结果在第i+j位和i+j+1位。像这样乘出所有的两位数。然后各位分别相加得到结果。这时我们没有处理进位。进位从最后一位统一处理。
代码如下:
class Solution {
public:
string multiply(string num1, string num2) {
int len1=num1.size();
int len2=num2.size();
int num[300]={0};
for(int i=len1-1;i>=0;--i)
for(int j=len2-1;j>=0;--j)
{
int tmp=(num1[i]-'0')*(num2[j]-'0');
num[i+j+1]+=(tmp)%10;
num[i+j]+=(tmp)/10;
}
for(int i=len1+len2-1;i>=0;--i)
{
num[i]=num[i]+num[i+1]/10;
num[i+1]=num[i+1]%10;
}
string res="";
int j=0;
while(num[j]==0&&j<len1+len2-1)
++j;
for(int i=len1+len2-1;i>=j;--i)
res=(char)(num[i]+'0')+res;
return res;
}
};
很聪明的做法,时间缩短极多。
三、总结
怎么说呢,在上机时候肯定是能做出来就行,但是在实际应用的时候还需要动脑想一想这种效率高的方法。