首页 > 代码库 > 每日算法之三十四:Multiply Strings

每日算法之三十四:Multiply Strings

大数相乘,分别都是用字符串表示的两个大数,求相乘之后的结果表示。

首先我们应该考虑一下测试用例会有哪些,先准备测试用例对防御性编程会有比较大的帮助,能够考虑一些极端情况。有以下几种用例:

1)"0","0"  

2)"0","879127346783" 其中一个是零

3)"as234","123343"  存在非法字符

4)"000000000000001234","2546"  存在零前缀,有冗余计算

大概就这么多吧。

要想实现大数乘法,必然先实现大数相加和一个大数和一个数字相乘。这样大数相乘就可以分割迭代计算。

下面是算法,自己写的,可能存在冗余。

<span style="font-size:14px;">class Solution {
public:
    string subTwoString(string num1,string num2)  //大数相加
{
  string result = "";
  int i = num1.length()-1;
  int j = num2.length()-1;
  int plus = 0;//进位
  while(i>=0 && j>=0)
  {
    int temp = num1[i]-'0' + num2[j]-'0' + plus;//不能忘掉进位
    result =char(temp%10+'0')+ result;
    plus = temp/10;
    i--;j--;
  }
  if(i>=0)//一种一个没有加完,不全结果,当然还有进位
  {
    while(i>=0)
    {
      int temp = num1[i]-'0' + plus;
        result =char(temp%10+'0')+ result;
        plus = temp/10;
        i--;
    }
  }
  if(j>=0)
  {
    while(j>=0)
    {
      int temp = num2[j]-'0' + plus;
        result =char(temp%10+'0')+ result;
        plus = temp/10;
        j--;
    } 
  }
  if(plus != 0)//最后进位不为零是要在结果头部加上
    result = char(plus+'0')+result;
  return result;
}
string multi(string num1,int num)//大数和一位数字相乘
{
  int len = num1.length()-1;
  int plus = 0;
  string result = "";
  while(len>=0)
  {
    int temp = (num1[len] - '0') * num + plus;//plus刚开始是忘掉的,也不能写在括号内,跟加法不同
    result = char(temp%10+'0') + result;
    plus = temp/10;
    len--;
  }
  if(plus != 0)
    result = char(plus+'0') + result;
  return result;}
string multiply(string num1, string num2) {//大数相乘
	if(num1.length() == 0 || num2.length() ==0)
		return 0;
	if(num1 == "0"|| num2 == "0")
	    return "0";
	string result = "";
	int len1 = num1.length();
	int len2 = num2.length();
	for(int i = 0;i<len1;i++)
		if(!isdigit(num1[i]))//是否存在数字
			return 0;
	for(int j = 0;j<len2;j++)
		if(!isdigit(num2[j]))
			return 0;
	for(int k = len2-1;k>=0;k--)
	{
		string temp = multi(num1,num2[k]-'0');
		for(int l = len2-k-1;l>0;l--)
			temp = temp + "0";
		result = subTwoString(result,temp);
	}
	return result;
    }
};</span>

下面是另一种方法,不是按照手算乘法计算的,使用了辅助数组利用特点写的:

思路:如果两个大数分别为m和n位,那么结果最多为m+n位,或者为m+n-1位(最后不存在进位)。比如123和23相乘。

00369
02460
027129
02829
下面做一下解释,第一行是123和3相乘的结果,第二行是2和123相乘的结果。顺序前移了一位。第三行是把之前的计算结果相加,第四行是从后往前

求进位,知道最开始。最后,再把他们转化成字符串即可。

<span style="font-size:14px;">string multiply(string num1, string num2) {
		if(num1=="0" || num2=="0") return "0";
		int l1 = num1.length(), l2 = num2.length();
		int* n1 = new int[l1];
		int* n2 = new int[l2];
		int* res = new int[l1+l2];
		memset(res,0,sizeof(int)*(l1+l2));
		for(int i=0; i<l1; ++i)
			n1[i] = num1[i] - '0';
		for(int i=0; i<l2; ++i)
			n2[i] = num2[i] - '0';
		
		for(int i=0; i<l1; ++i)
			for (int j=0; j<l2; ++j)
				res[i+j+1] += n1[i]*n2[j];

		string ss = "";
		for (int k=l1+l2-1; k>=0; --k){
			if(k>0) res[k-1] += res[k]/10;
			res[k] %= 10;
			ss = char(res[k]+'0')+ss;
		}
		ss = ss[0]=='0'? ss.substr(1):ss;
		//return ss.empty()?"0":ss;
		return ss;
	}</span>