Leetcode-43.Multiply Strings

本次做的是大数相乘的题目。


1. 题目

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2.

Note:

    1. The length of both num1 and num2 is < 110.
    2. Both num1 and num2 contains only digits 0-9.
    3. Both num1 and num2 does not contain any leading zero.
    4. You must not use any built-in BigInteger library or convert the inputs to integer directly.



给出两个非负的数字num1和num2,用字符串string来表示,返回num1和num2相乘的结果。
注意:

    1. num1和num2的长度小于110;
    2. num1和num2都是只包含0-9的数字;
    3. num1和num2度的高位不是0;
    4. 不能使用已有的BigInteger 库或者直接将输入转化为整数。

2.思路
题目很容易理解,就是字符串的相乘,最简单的思路,就是按照手算时的
竖式乘法
来计算:较长的数字num1在上,较短的数字 num2在下,举个例子。num1乘以num2的每一位,得到的结果存储起来,再进行相加。按照这种思路,存储结果可以用字符串也可以用数组。我是采用数组的形式。数组r初始化为”num2.length x(num1.length()+num2.length())”的大小,且全为0.因为num2的长度决定了num1要乘几次,如下面例子,num1要乘4次,得到四行结果。最后相加的时候,结果的位数最多是num1.length() + num2.length()这么长。因此,得到这个全0矩阵后,每一列相加,就相当于竖式的加法计算。
          1 2 3 4 5
x                 2 2 2 4
———————————— 

000049380
000246900
002469000
024690000

————————————  
0 2 7 4 5 5 2 8 0
按照上面例子的算法,可以得到计算结果。在最高位时,判断如果是0,则舍弃该位,若是有进位,则需要保存。
注意的是,当num1或者num2其中一个是0时,不需要计算,直接返回字符串“0”;还有,num1始终是较长的字符串,num2是较短的字符串。
3.代码

string multiply(string num1, string num2) {
     //如果两个字符串有一个为0,那么相乘结果直接为0
      if (num1 == "0" || num2 == "0")
    	  return "0";

      //比较两个字符串的长度,长的作为num1
      if (num1.length() < num2.length())
      {
    	 string s;
    	 s = num1;
    	 num1 = num2;
    	 num2 = s;
      }

      int i,j;
      int k=0;
      int len = num1.length() + num2.length();
      //定义一个初始化为全0的矩阵来存放num1乘以num2每一位的计算结果,矩阵行数是num2的长度,矩阵列数是num1长度+num2长度
      int r[num2.length()][len];
      for(i = 0; i < num2.length(); i ++)
    	  for(j = 0; j < len; j ++)
    		  r[i][j] = 0;

      //c用于记录进位
      int c = 0;
      //num2的最后一位开始,num1也是从最后一位开始,依次按位相乘
      for(i = num2.length()-1; i >= 0; i --){
    	  for(j =  num1.length() - 1; j >=0 ; j --){
    		  int temp = (num1[j]-'0') * (num2[i]-'0') + c;
    		  c = temp / 10;
    		  //num1乘以num2的第i位存放在第k行,k从0开始
    		  r[k][i+j+1] = temp % 10;;
    	  }
    	  r[k][i+j+1] = c;
    	  k ++;
    	  c = 0;
      }
      //sum用于记录矩阵每一列数字加起来的结果,c记录进位
      int sum = 0;
      c = 0;

      string res = "";
      for(int col = len-1; col >= 0; col --){
       	  for(int row = 0; row < num2.length(); row ++){
    		  sum += r[row][col];
    	  }
       	  sum += c;
    	  c= sum / 10;
    	  //如果最高位这一列结果是0,则不需要加到res中
    	  if((col == 0) && (sum == 0))
    		 break;
          res += (sum%10)+'0';
    	  sum = 0;
      }
      //翻转字符串
      reverse(res.begin(), res.end());
      return res;
 }

4.优化的方法
字符串很长的时候,必然会有很多重复的数字,那么此时可以进行优化。定义一个int数组,记为h,大小为10,分别表示num2中数字0-9出现过没有,出现过,则将出现在第几位记录在数组h中。以上面例子来讲,当num1乘以num2中的4时,记录h[4]  = k, 表示在矩阵的第k行;当num1乘以num2中的第一个2时,记录h[2] ;那么当再次出num2中再出现2时,就可以直接从矩阵的r[h[2]]行取结果,放在当前行,并前移几个单位即可。
我认为这种做法在字符串长时会有一定的改进。代码添加修改部分如下:

     int h[10];
      for(i = 0; i < 10; i ++)
    	  h[i] = 0;
      //c用于记录进位
      int c = 0;
      //num2的最后一位开始,num1也是从最后一位开始,依次按位相乘
      for(i = num2.length()-1; i >= 0; i --){
    	  if (h[(num2[i]-'0')] != 0)
    	  {
    		  int d = k - h[(num2[i]-'0')];
    		  for(int l = len - 1; l >= d;l--)
    			  r[k][l-d] = r[h[(num2[i]-'0')]][l];
    	  }
    	  else{
    	  for(j =  num1.length() - 1; j >=0 ; j --){
    		  int temp = (num1[j]-'0') * (num2[i]-'0') + c;
    		  c = temp / 10;
    		  //num1乘以num2的第i位存放在第k行,k从0开始
    		  r[k][i+j+1] = temp % 10;;
    	  }
    	  h[(num2[i]-'0')] = k;
    	  r[k][i+j+1] = c;
    	  }
    	  k ++;
    	  c = 0;
      }

 

点赞