大数乘法是指对一些数值超出计算机的表示范围的数的计算,这时需要用到数据结构以及特殊的计算方法,来表示出计算结果。
下面就以leecode上的一个题为例,讲一下大数乘法的计算方法:
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
说明:
num1 和 num2 的长度小于110。
num1 和 num2 只包含数字 0-9。
num1 和 num2 均不以零开头,除非是数字 0 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/multiply-strings
计算方法有:竖式计算法(模拟手算)、先乘后加、分治-Karatsuba算法(高级)
其实前面两种算法原理大致相同,只是在进位时机上有所不同。
用到的数据结构:数组
下面是我自己的计算过程:用到的是先乘后累加的计算方式,
个人觉得思路还算比较清晰,用一个二进制数组分别表示num2中各位数与num1的乘积,接着将所有行对应相加,得到一个数组,最后计算进位,得到最终结果。时间复杂度为O(n^2)
代码如下
1 var multiply = function(num1, num2) { 2 if(parseInt(num1) == 0 || parseInt(num2) == 0){ 3 return "0"; 4 } 5 num1 = num1.split(""); 6 num2 = num2.split(""); 7 var re = []; //num1.length × num1.length+num2.length 8 // 初值 0 9 for (var i = 0; i < num2.length; i++) { 10 re[i] = []; 11 for (var j = 0; j < num1.length+num2.length; j++) { 12 re[i][j] = 0; 13 } 14 } 15 // console.log(re); 16 // 累乘 17 for (var i = 0; i < num1.length; i++) { 18 for (var j = 0; j < num2.length; j++) { 19 re[num2.length-j-1][i+j+1] = parseInt(num1[i])*parseInt(num2[j]); 20 } 21 } 22 // console.log(re); 23 24 var temp = []; //num1.length+num2.length 25 for (var i = 0; i < num1.length+num2.length; i++) { 26 temp[i] = 0; 27 } 28 // 累加 29 for (var i = 0; i < num1.length+num2.length; i++) { 30 for (var j = 0; j < num2.length; j++) { 31 temp[i]+= re[j][i]; 32 } 33 } 34 // console.log(temp); 35 36 //进位 37 var sur = 0; 38 for (var i = temp.length-1; i >= 0; i--) { 39 var s = temp[i]+sur; 40 temp[i] = s%10; 41 sur = Math.floor(s/10); 42 } 43 // console.log(temp); 44 if(temp[0] == 0){ 45 temp.splice(0,1); 46 } 47 return temp.join(""); 48 };
分治算法是比较复杂的一种算法,是将一个大数分成对应的两部分,然后分别计算乘积,有点化整为零的意思。时间复杂度O(nlog23)
实现方式:递归,代码略