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

很聪明的做法,时间缩短极多。

三、总结

怎么说呢,在上机时候肯定是能做出来就行,但是在实际应用的时候还需要动脑想一想这种效率高的方法。

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