1. 题目:模拟字符串相乘
2. 思路:
平时计算乘法列竖式有两种方式
第一种方式,比如123乘以456,可以是123的每一位依次乘以6,在乘以5,再乘以4。错位再相加
第二种方式,也可以是456的每一位依次乘以3,在乘以2,再乘以1。错位再相加
其实是可以模拟这种列竖式的计算。假如我们把进位放在最后处理。
模拟第一种方式列竖式:
模拟第二种方式列竖式:
而使用两层for循环就能很好的模拟这种情况
for(int i=a.size()-1;i>=0;i--)
{
for(int j=b.size()-1;j>=0;j--)
{
c[i+j]+=a[i]*b[j]; //必须为+=因为后续还有数据会加上来
}
}
举个例子:3固定不变,6,5,4依次去乘以3(从个位开始),得到18,15,12。放在c数组的下标为4,3,2处。
下面开始验证:
外层循环i对应的第一次循环结束
外层循环i对应的第二次循环结束
外层循环对应的第三次循环结束
最终c数组里就面就存储了,乘好的,但是没有进位的数据
接下来模拟进位:
原本想着全进位之后,在转成字符串,但是看到一种很巧妙的解法。
先定义一个空串,他保存最终转换的结果string ans;
定义进位符号 int flag=0;
for(int i=c.size()-1;i>=0;i++)
{
//原来的数据加上进位后的数据就是真正的数据了
a[i]+=flag;
//进位完之后的数据
char a=a[i]%10-'0';
//很巧妙,c就是进位完之后的数据,直接+到字符串后面,不用像我们之前那样全进位,在转成字符串
ans=a+ans;
//进位要用的数据,例如18的前一个数据就要+1,27的前一个数据+2
flag=a[i]/10;
}
假如c[0]位置算完之后也有进位,但由于循环走到c[0]退出,无法对它进行处理。
例如 9*9,按我们的玩法模拟出就是1,8还在flag里,结果循环退出了。
那么就对flag进行判断,把它加上去。
while(flag)
{
char a=flag-'0';
ans=a+ans;
}
还有一种情况,这种测试用例没考虑到
999*0 这时转换到字符串就会成"000",但是当多个0的时候我们只需要一个。所以再加一条语句
while(ans.size()>0 && ans[0]=='0')
{
ans.erase(ans.begin());
}
return ans;
3. 完整代码
class Solution {
public:
string multiply(string num1, string num2) {
vector<int> a(num1.size(), 0);
vector<int> b(num2.size(), 0);
vector<int> c(num1.size() + num2.size()-1, 0);
for(int i=0;i<num1.size();i++)
{
a[i]=num1[i]-'0';
}
for(int i=0;i<num2.size();i++)
{
b[i]=num2[i]-'0';
}
for(int i=a.size()-1;i>=0;i--)
{
for(int j=b.size()-1;j>=0;j--)
{
c[i+j]+=a[i]*b[j];
}
}
int flag = 0;
string ans;
for (int i = c.size() - 1; i >= 0; i--)
{
c[i] = c[i] + flag;
char a = c[i] % 10 + '0';
ans = a + ans;
flag = c[i] / 10;
}
while(flag)
{
char a=flag+'0';
ans=a+ans;
flag/=10;
}
while(ans.size()>1 && ans[0]=='0')
{
ans.erase(ans.begin());
}
return ans;
}
};