题目描述
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
说明:
1.num1 和 num2 的长度小于110。
2.num1 和 num2 只包含数字 0-9。
3.num1 和 num2 均不以零开头,除非是数字 0 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来
题目分析
跟“字符串相加”类似,这里我们要处理的,也是大整数的相乘问题。
思路也可以非常类似:我们借鉴数学中“竖式乘法”的规则,用num1分别去乘num2的每一位数字,最后再用AddStrings将乘出的结果全部叠加起来就可以了。
具体代码实现
public class MultiplyStrings {
public String multiply(String num1, String num2) {
if ( num1.equals("0") || num2.equals("0") ) return "0";
String result = "0";
// 遍历num2的每个数位,逐个与num1相乘
for ( int i = num2.length() - 1; i >= 0; i-- ){
int carry = 0;
StringBuffer curRes = new StringBuffer();
for ( int j = 0; j < num2.length() - 1 - i; j++ ){
curRes.append("0");
}
int y = num2.charAt(i) - '0';
// 遍历num1的每一位数,跟y相乘
for ( int j = num1.length() - 1; j >= 0; j-- ){
int x = num1.charAt(j) - '0';
int product = x * y + carry;
curRes.append(product % 10);
carry = product / 10;
}
if (carry != 0) curRes.append(carry);
AddStrings addStrs = new AddStrings();
result = addStrs.addStrings(result, curRes.reverse().toString());
}
return result;
}
}
时间复杂度
时间复杂度:O(mn+n^2),其中 m 和 n 分别是 num1 和 num2的长度。
做计算的时候,外层需要从右往左遍历num2,而对于num2的每一位,都需要和 num1的每一位计算乘积,因此计算乘积的总次数是 mn。字符串相加操作共有 n次,每次相加的字符串长度最长为 m+n,因此字符串相加的时间复杂度是 O(mn+n^2)。总时间复杂度是 O(mn+n^2)。
空间复杂度:O(m+n)。空间复杂度取决于存储中间状态的字符串,由于乘积的最大长度为 m+n,因此存储中间状态的字符串的长度不会超过 m+n。
算法优化
我们看到计算过程中,用到了太多的字符串相加操作,调用addStrings方法时又需要遍历字符串的每一位,这个过程显得有些繁琐。能不能用其它的方法进行简化呢?
我们发现,m位数乘以n位数,结果最多就是m+n位;所以我们可以用一个m+n长度的数组来保存计算结果。
而且,某两个数位相乘,num1[i] x num2[j] 的结果(定义为两位数,一位数的话前面补0),其第一位位于 result[i+j],第二位位于 result[i+j+1]。
根据上面的思路,我们可以遍历num1和num2中的每一位数,相乘后叠加到result的对应位上就可以了。
代码实现
public String multiply(String num1, String num2) {
if ( num1.equals("0") || num2.equals("0") ) return "0";
int[] resultArr = new int[num1.length() + num2.length()];
// 遍历num1和num2,逐位计算乘积,填入结果数组中
for ( int i = num1.length() - 1; i >= 0; i-- ){
int x = num1.charAt(i) - '0';
for ( int j = num2.length() - 1; j >= 0; j-- ){
int y = num2.charAt(j) - '0';
int product = x * y;
int temp = resultArr[i+j+1] + product;
resultArr[i+j+1] = temp % 10;
resultArr[i+j] += temp / 10;
}
}
StringBuffer result = new StringBuffer();
int start = resultArr[0] == 0 ? 1 : 0;
for ( int i = start; i < resultArr.length; i++ ){
result.append(resultArr[i]);
}
return result.toString();
}
复杂度分析
时间复杂度:O(mn),其中 m 和 n 分别是 num1 和 num2的长度。需要计算num1 的每一位和 num2的每一位的乘积。
空间复杂度:O(m+n),需要创建一个长度为 m+n 的数组存储乘积。