Interview100-87.1 大数相乘问题

题目

两个位数很多的数相乘,相乘的结果超出了基本数据类型的存储范围,如何使用算法计算出这两个大数的乘积。例如:求 1234567891011121314151617181920 * 2019181716151413121110987654321 的乘积结果。

解法

思路1:模拟手算乘法的步骤,先将乘数与被乘数逐位相乘,然后将逐位相乘的结果对应位进行累加求和。这种思路虽然简单,但实现起来还是有些复杂。

思路2:考虑另一种思路,将乘数与被乘数进行逐位相乘,但暂时不考虑进位问题,相乘后的结果依然进行逐位相加,对应位的累加的和保存在相应的位置,最后处理进位的问题。

        9  8
×       2  1
-------------
       (9)(8)  <---- 第1趟: 98×1的每一位结果 
  (18)(16)     <---- 第2趟: 98×2的每一位结果 
-------------
  (18)(25)(8)  <---- 这里就是相对位的和,还没有累加进位 

在处理进位的问题时,我们从右到左依次累加,如果和>=10时,对该累加值取商加入到前一位中,然后多累加值取余,即为该数位自己的值,直至处理完所有的累加位。但这种处理进位的方式,由于是自右向左进行,而对每位进行记录时是从左往右的,所有在对进位进行处理时,可能会导致数组的左边界越界。解决这个问题的方式是在进行从左至右累加时,在数组的左侧空余一个位置,以处理后面进位越界的问题。

BIG-NUMBER-MULTIPLY(int[] num1, int[] num2):
    int[] result = new int[num1.length+num2.length];
    for i = 0 to num1.length:
        for j = 0 to num2.lenngth:
            result[i+j+1] += num1[i] * num2[j];

    for k = result.length - 1 to 0:
        if result[k] >= 0:
            result[k-1] += result[k] / 10;
            result[k] = result[k] % 10;
    return result;

这种方法中没有处理负号的问题,对于负值的问题,需要统计一下两个乘数中的负号的个数。

其他方法

关于该问题还有很多优秀的求解方法并且时间复杂度有降低,以上的两个思路的时间复杂度都是O(n*n)。

  • 分治乘法:最简单的是Karatsuba乘法,一般化以后有Toom-Cook乘法;
  • 快速傅里叶变换FFT:(为了避免精度问题,可以改用快速数论变换FNTT),时间复杂度O(N lgN lglgN)。
  • 中国剩余定理:把每个数分解到一些互素的模上,然后每个同余方程对应乘起来就行;
  • Furer’s algorithm:在渐进意义上FNTT还快的算法。

参考:https://blog.csdn.net/u010983881/article/details/77503519

你可能感兴趣的:(面试算法100题)