题目来源于leetcode,解法和思路仅代表个人观点。传送门。
难度:中等
用时:02:00:00 (想法有点多,矛盾了好久)
题目
给定两个以字符串形式表示的非负整数 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)采用正常做乘法的逻辑。一个数的每位,乘上另一个数,然后相加。
(2)把【一个数】加上 自己 的【另一个数】次。
不管哪种算法,大数相加,这个方法,一定要有。
虽然先是想到了(1),但是一开始觉得(1)有点慢。然后就往(2)想了。那就先说说(2)。
那么,如果考虑(2)的话,可以利用【求幂】的思想。
d
p
[
i
]
=
d
p
[
i
/
2
]
+
d
p
[
i
/
2
]
dp[i] = dp[i/2] + dp[i/2]
dp[i]=dp[i/2]+dp[i/2]
类似这种。
但是这种方法尝试了一下过后发现有几个问题。
(1)这个数组,需要很大。可能需要log(10110)(题目条件)。实在太大。
(2)字符串比较难进行 除2 操作。
经过一番尝试,最终还是回到了(1)
那么,如果考虑(1)。任选一个数为乘数,或被乘数。
- 可以先计算出0~9 * num1(或num2)的值(字符串)存到一个数组中。这里就可以采用(2)的思想了。
- 接着,把num2的每位乘上num1后(从上面的数组取值)的结果存起来,在结果后面加上"0"(依次递增)(StringBuilder.append)。
- 把这些结果相加(大数相加)
代码
class Solution {
String[] record = new String[10];
public String multiply(String num1, String num2) {
if(num1.length()==1 || num2.length()==1){
if(num1.charAt(0)=='0' || num2.charAt(0)=='0'){
return "0";
}
}
//给record赋值,时间复杂度是O(n/2)=O(n)
record[0] = "0";
record[1] = num1;
//时间复杂度是O(10)=O(1)
for(int i=2;i<record.length;i++){
if(i%2 == 1){
record[i] = add(add(record[i/2],record[i/2]),num1);
}else{
record[i] = add(record[i/2],record[i/2]);
}
}
StringBuilder[] sum = new StringBuilder[num2.length()];
//时间复杂度是O(m*n)
for(int i=0,j=num2.length()-1;j>=0;i++,j--){
//bit在0~9之间
int bit = num2.charAt(j) - '0';
sum[j] = new StringBuilder();
sum[j].append(record[bit]);
for(int k=0;k<i;k++){
sum[j].append("0");
}
}
//时间复杂度是O(m*(m+n))
String ans = "0";
for(int i=0;i<sum.length;i++){
ans = add(sum[i].toString(),ans);
}
return ans;
}
//两个数相加,时间复杂度是O(Max{n,m})
public String add(String num1,String num2){
StringBuilder ans = new StringBuilder();
int carry = 0;
int bitSumNum = 0;
char bitSumChar = '0';
for(int i=num1.length()-1,j=num2.length()-1 ;i>=0||j>=0 ;i--,j--){
//取出一位
int n1 = i>=0?num1.charAt(i)-'0' : 0;
int n2 = j>=0?num2.charAt(j)-'0' : 0;
//本位和
bitSumNum = n1 + n2 + carry;
//进位
if(bitSumNum >= 10){
carry = 1;
bitSumNum %= 10;
}else{
carry = 0;
}
bitSumChar = (char)(bitSumNum + '0');
ans.append(bitSumChar);
}
//最后一个进位
if(carry==0){
return ans.reverse().toString();
}
return ans.append('1').reverse().toString();
}
}
算法复杂度
时间复杂度: O(n*m + m2 + n)。其中n,m为字符串长度。(大概) 计算num1与0~9相乘需要O(n)。计算两个相加需要O(max{n,m})。计算num1乘num2需要O(n*m)。计算每次乘积的和需要O(m* (n + m) ) 。
空间复杂度: O(n+(m+n)*m)。其中n,m为字符串长度。存放num1与0~9相乘的结果需要O(n)。存放num1乘num2的和需要长度为m的数组,数组每项长度为m+n。