43. 字符串相乘
这个题算法的思路其实很简单,就是小学就学过的方法。
对于num1=“123”、num2=“456”两个数来说,表示为如下
1 2 3
4 5 6
---------
7 3 8
6 1 5
4 9 2
---------
5 6 0 8 8
通过这个方法,我们就将乘法转换为了加法运算。那么怎么把这个计算过程用程序的方式表示出来呢?
设num1的长度为m,num2的长度为n。
(1)那么我们可以开辟一个O(nm)大小的空间,存储所有需要加起来的字符串,将它们逐个相加(即转换为字符串加法),时间复杂度为O(mn+m^2),显然是有点慢。
(2)将中间结果先累加到一个长度为m+n的数组中,最后对该数组逐位做进位处理。空间复杂度O(m+n),时间复杂度O(mn+m+n)。通过开辟了一个临时数组之后,进位处理不再需要使用一个临时变量来进行存储,而是直接存放在数组的下一位中,比较巧妙。
class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
char[] arr1 = num1.toCharArray();
char[] arr2 = num2.toCharArray();
int m = arr1.length;
int n = arr2.length;
// 计算中间结果
int[] mul = new int[m+n];
for (int i = m-1; i >= 0; i--) {
for (int j = n-1; j >= 0; j--) {
int val = (arr2[j]-'0') * (arr1[i]-'0');
// i+j+1非常取巧
mul[i+j+1] += val;
}
}
// 处理进位
for (int i = mul.length-1; i > 0; i--) {
// 直接将进位值存储到下一个位置
mul[i-1] += mul[i] / 10;
mul[i] %= 10;
}
// 输出
String result = "";
int index = mul[0] == 0 ? 1 : 0;
for (int i = index; i < mul.length; i++) {
result += mul[i];
}
return result;
}
}
(3)还能再进行一下优化,把累加与进位处理进行合并,时间复杂度降低到O(mn+n)
class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
char[] arr1 = num1.toCharArray();
char[] arr2 = num2.toCharArray();
int m = arr1.length;
int n = arr2.length;
int[] mul = new int[m+n];
for (int i = m-1; i >= 0; i--) {
for (int j = n-1; j >= 0; j--) {
int sum = mul[i+j+1] + (arr2[j]-'0') * (arr1[i]-'0');
mul[i+j+1] = sum % 10;
// 合并进位处理,减少一次for循环
mul[i+j] += sum / 10;
}
}
// 优化字符串拼接方式
StringBuilder result = new StringBuilder();
int index = mul[0] == 0 ? 1 : 0;
for (int i = index; i < mul.length; i++) {
result.append(mul[i]);
}
return result.toString();
}
}