声明:这只是一个题解,题目是LeetCode来的。著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目:
给定两个以字符串形式表示的非负整数 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)或直接将输入转换为整数来处理。
题解:
解法1 拆分相加
分析:
123 * 456 = 123 * 6 + 123 * 50 + 123 * 400;
因此可以通过拆分num1或num2来分别得到每一位的乘积,最后把他们加起来。
实现:(略)
解法2 模拟乘法运算
这也是我一开始思考这道题的时候想到的办法。我们首先来看一下我们小学的时候是怎么算乘法的:
首先看最后的结果,我们可以发现,结果的位数 <= num1.length + num2.length,因此我们可以使用一个length = num1.length + num2.length的数组来保存我们要的结果。
其次,最后的结果实际上是num1和num2的每一位相乘得到的结果再加和。
再次模拟一下过程,找找规律:
我们再次可以发现,当用两个指针分别指向num1和num2的末尾并且向前移动时,num1[i] * num2[j] 的值应该放在 index = i + j + 1的位置上。如果有进位的话,就放在前一个位置上。
那么当123 * 6计算完以后,我们还要计算123 * 5,这时候应该怎么办?
要知道每一次乘法得到的结果最后都是要相加的,那么我们只需要把这一次得到的结果累加在上一次的结果上就行了。有进位的就往前一个位置累加即可,i+j+1对应的位置应该只存放这次得到的个位数。
所以我们的result数组的填充方法应该是:
int val1 = num1.charAt(i) - '0';
int val2 = num2.charAt(j) - '0';
int temp = result[i + j + 1] + val1 * val2;//原来的数字+新乘积
result[i + j + 1] = temp % 10;//对应位置的数字
result[i + j] += temp/10; //进位
最后填充完数组,数组可能不满,也就是说结果的最高位之前可能会出现0,比如123 * 456的结果可能是这样[0,5,6,0,8,8]那我们构造结果的时候需要判断一下,遇到第一个是0我们就跳过。为什么只有第一个0跳过?因为结果的大小是在[长的num.length, num1.length + num2.length]之间,所以说最多也就只有1个0在首位。(可以自己写一写看看)
所以整个代码是这样的:
public String multiply(String num1, String num2){
int len1 = num1.length();
int len2 = num2.length();
if(len1 == 0 || len2 == 0 || num1.charAt(0) -'0' == 0 || num2.charAt(0) - '0' == 0) return "0";
int[] result = new int[len1 + len2];
for(int i = len1 - 1; i >= 0; i--){
int val1 = num1.charAt(i) - '0';
for(int j = len2 - 1; j >= 0; j--){
int val2 = num2.charAt(j) - '0';
int temp = result[i + j + 1] + val1 * val2;//原来的数字+新乘积
result[i + j + 1] = temp % 10;//对应位置的数字
result[i + j] += temp/10; //进位
}
}
//构造结果
StringBuilder res = new StringBuilder();
for(int i = 0; i < result.length; i++){
if(i == 0 && result[i] == 0) continue;
res.append(result[i]);
}
return res.toString();
}