【LeetCode】43. Multiply Strings 字符串乘法

一、概述

輸入兩個字符串類型的數字,輸出字符串類型的兩數字的積。

題目很容易理解,實際做起來我就是按平常做乘法的思路做的。

寫了兩個函數:字符串與一位數字相乘和兩字符串相加,然後循環調用。

時空複雜度太垃圾了。

好的算法速度比我快四十倍不止。

二、分析

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;
    }
};

很聰明的做法,時間縮短極多。

三、總結

怎麼說呢,在上機時候肯定是能做出來就行,但是在實際應用的時候還需要動腦想一想這種效率高的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章