一、概述
輸入兩個字符串類型的數字,輸出字符串類型的兩數字的積。
題目很容易理解,實際做起來我就是按平常做乘法的思路做的。
寫了兩個函數:字符串與一位數字相乘和兩字符串相加,然後循環調用。
時空複雜度太垃圾了。
好的算法速度比我快四十倍不止。
二、分析
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;
}
};
很聰明的做法,時間縮短極多。
三、總結
怎麼說呢,在上機時候肯定是能做出來就行,但是在實際應用的時候還需要動腦想一想這種效率高的方法。