给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
测试用例
示例:
输入: num1 = “3”, num2 = “4”
输出: “12”
说明:
- num1 和 num2 的长度小于110。
- num1 和 num2 只包含数字 0-9。
- num1 和 num2 均不以零开头,除非是数字 0 本身。
- 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
解题思路
乘法
令 m 和 n 分别表示 num1 和num2 的长度,并且它们均不为 0,则 num1 和 num2 的乘积的长度为 m + n − 1 m+n−1 m+n−1 或 m + n m+n m+n。简单证明如下:
- 如果 n u m 1 num_1 num1 和 n u m 2 num_2 num2 都取最小值,则 n u m 1 = 1 0 m − 1 num_1 =10^{m-1} num1=10m−1, n u m 2 = 1 0 n − 1 num_2 =10^{n-1} num2=10n−1, n u m 1 ∗ n u m 2 = 1 0 m + n − 2 num_1*num_2=10^{m+n-2} num1∗num2=10m+n−2。乘积的长度为 m + n − 1 m + n −1 m+n−1;
- 如果 n u m 1 num1 num1 和 n u m 2 num2 num2 都取最大值,则 n u m 1 = 1 0 m − 1 num_1 =10^m-1 num1=10m−1, n u m 2 = 1 0 n − 1 num_2 =10^n-1 num2=10n−1, n u m 1 ∗ n u m 2 = 1 0 m + n − 1 0 m − 1 0 n + 1 num_1 *num_2=10^{m+n}-10^m-10^n+1 num1∗num2=10m+n−10m−10n+1。乘积显然小于 1 0 m + n 10^{m+n} 10m+n且大于 1 0 m + n − 1 10^{m+n-1} 10m+n−1,因此乘积的长度为 m + n m+n m+n。
由于 n u m 1 num1 num1 和 n u m 2 num2 num2 的乘积的最大长度为 m + n m+n m+n,因此创建长度为 m + n m+n m+n 的数组 a r r arr arr 用于存储乘积。对于任意 0 ≤ i < m 0≤i<m 0≤i<m 和 0 ≤ j < n 0≤j<n 0≤j<n, n u m 1 [ i ] ∗ n u m 2 [ j ] num_1[i]*num_2[j] num1[i]∗num2[j] 的结果位于 a r r [ i + j + 1 ] arr[i+j+1] arr[i+j+1],如果 a r r [ i + j + 1 ] ≥ 10 arr[i+j+1]≥10 arr[i+j+1]≥10,则将进位部分加到 a r r [ i + j ] arr[i+j] arr[i+j]。
最后,将数组 a r r arr arr 转成字符串,如果最高位是 0 则舍弃最高位。
Code
class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
int m = num1.length(), n = num2.length();
int[] arr = new int[m + n];
for (int i = m - 1; i >= 0 ; i--) {
int x = num1.charAt(i) - '0';
for (int j = n - 1; j >= 0; j--) {
int y = num2.charAt(j) - '0';
arr[i + j + 1] += x * y;
}
}
for (int i = m + n - 1; i > 0 ; i--) {
arr[i - 1] += arr[i] / 10;
arr[i] = arr[i] % 10;
}
int index = arr[0] == 0 ? 1 : 0;
StringBuffer str =new StringBuffer();
while (index < m + n){
str.append(arr[index]);
index++;
}
return str.toString();
}
}
复杂度分析
-
时间复杂度: O ( m n ) O(mn) O(mn),其中 m 和 n 分别是 n u m 1 num_1 num1 和 n u m 2 num_2 num2 的长度。需要计算 n u m 1 num_1 num1的每一位和 n u m 2 num_2 num2 的每一位的乘积。
-
空间复杂度: O ( m + n ) O(m+n) O(m+n),其中 m 和 n 分别是 n u m 1 num_1 num1 和 n u m 2 num_2 num2 的长度。需要创建一个长度为 m + n m+n m+n 的数组存储乘积。
解法2
模拟「竖式乘法」的方法计算乘积
class Solution {
//string multiply
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0"))
return "0";
String result = "0";
int m = num1.length(), n = num2.length();
for (int i = n - 1; i >= 0; i--) {
int e2 = num2.charAt(i) - '0';
StringBuffer str = new StringBuffer();
//补零
for (int p = 0; p < n - 1 - i; p++) {
str.append("0");
}
int carry = 0;
for (int j = m - 1; j >= 0 || carry != 0; j--) {
int e1 = j < 0 ? 0 : num1.charAt(j) - '0';
int temp = e1 * e2 + carry;
str.append(temp % 10);
carry = temp / 10;
}
result = addStrings(result, str.reverse().toString());
}
return result;
}
//string sum
public String addStrings(String num1, String num2) {
int m = num1.length(), n = num2.length(), carry = 0;
StringBuffer answer = new StringBuffer();
while (m > 0 || n > 0 || carry != 0) {
int x = m > 0 ? num1.charAt(m - 1) - '0' : 0;
int y = n > 0 ? num2.charAt(n - 1) - '0' : 0;
int temp = x + y + carry;
answer.append(temp % 10);
carry = temp / 10;
m--;
n--;
}
return answer.reverse().toString();
}
}