一、示例
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
二、说明
- num1 和 num2 的长度小于110。
- num1 和 num2 只包含数字 0-9。
- num1 和 num2 均不以零开头,除非是数字 0 本身。
- 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
三、解题思路
对于比较小的数字,做运算可以直接使用编程语言提供的运算符,但是如果相乘的两个因数非常大,语言提供的数据类型可能就会溢出。一种替代方案就是,运算数以字符串的形式输入,然后模仿我们小学学习的乘法算术过程计算出结果,并且也用字符串表示。
需要注意的是,num1 和 num2 可以非常长,所以不可以把他们直接转成整型然后运算,唯一的思路就是模仿我们手算乘法。
比如说我们手算 123 × 45,应该会这样计算:
计算 123 × 5,再计算 123 × 4,最后错一位相加。这个流程恐怕小学生都可以熟练完成,但是你是否能「把这个运算过程进一步机械化」,写成一套算法指令让没有任何智商的计算机来执行呢?
你看这个简单过程,其中涉及乘法进位,涉及错位相加,还涉及加法进位;而且还有一些不易察觉的问题,比如说两位数乘以两位数,结果可能是四位数,也可能是三位数,你怎么想出一个标准化的处理方式?这就是算法的魅力,如果没有计算机思维,简单的问题可能都没办法自动化处理。
首先,我们这种手算方式还是太「高级」了,我们要再「低级」一点,123 × 5 和 123 × 4 的过程还可以进一步分解,最后再相加:
现在 123 并不大,如果是个很大的数字的话,是无法直接计算乘积的。我们可以用一个数组在底下接收相加结果:
整个计算过程大概是这样,有两个指针 i,j 在 num1 和 num2 上游走,计算乘积,同时将乘积叠加到 res 的正确位置:
现在还有一个关键问题,如何将乘积叠加到 res 的正确位置,或者说,如何通过 i,j 计算 res 的对应索引呢?
其实,细心观察之后就发现,num1[i] 和 num2[j] 的乘积对应的就是 res[i+j] 和 res[i+j+1] 这两个位置。
四、Demo
class Solution {
public static void main(String[] args) {
String s1 = "123";
String s2 = "45";
System.out.println(Solution.multiply(s1, s2));
System.out.println(Solution.multiply(s1, s2).getClass().getName());
}
static String multiply(String num1, String num2) {
// 参与乘法的一方有"0", 结果返回"0"
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
int length1 = num1.length();
int length2 = num2.length();
// 结果最多为 length1 + length2 位数, 即 0 至 length1 + length2 - 1
int[] res = new int[length1 + length2];
// 从个位数开始逐位相乘
for (int i = length1 - 1; i >= 0; i--) {
for (int j = length2 - 1; j >= 0; j--) {
// 取出String中的单个字符, 作乘法, 要减去字符'0'的ASCII码48
int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
// 乘积在 res 对应的索引位置
int index1 = i + j, index2 = i + j + 1;
// 把余数和进位叠加到res数组上
int sum = mul + res[index2];
// 求余数的时候需要在上一步把低位部分加上
res[index2] = sum % 10;
// 算进位, 不需要考虑当前循环新增的低位和高位部分
res[index1] += sum / 10;
}
}
// for循环结束以后的res数组结果前缀中有可能存在0(未使用的位)
int i = 0;
// 确认在前缀中有几位是0
while (i < res.length && res[i] == 0) {
i++;
}
// 将计算结果转化成字符串
StringBuffer str = new StringBuffer();
for (; i < res.length; i++) {
str.append("" + res[i]);
}
return str.toString();
}
}