题目链接
题目描述:
给定两个以字符串形式表示的非负整数 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)或直接将输入转换为整数来处理。
解题思路
本题难点在于如何复原我们日常的思维方式,也就是从小就会的竖式相乘法。这里仅提供一个暴力法,上图~
由图可知,实际上就是遍历num2
数字,使之与num1
相乘,最后将结果累加。
在逐项相乘部分,要考虑一个问题——补0。而包括逐项相乘和逐项累加都是#415.字符串相加的延续,题解在此~
简单来说,无论乘法还是加法都要考虑三个问题:
- 进位问题,
carry = (n1 * n2 + carry) / 10
和carry = (n1 + n2 + carry) / 10
均表示当前位相乘或相加后的进位结果; - 最高位溢出问题,这里包含两部分。是如果最高位计算完成后也发生了进位情况应该怎么办?可以在for循环中添加
carry != 0
,那么这就会引发第二个问题,如果i
或j
已经遍历完毕了怎么办?这时可以用一个三目运算符解决问题n1 = j < 0 ? 0 : num1[j] - '0'
; - 当前位计算问题,当然是
product = (n1 * n2 + carry) % 10
并将结果添加到temp
末尾
另外要注意,循环结束后结果是倒叙的,需要先reverse
以下再进行计算~
代码
class Solution {
public:
string multiply(string num1, string num2) {
if(num1 == "0" || num2 == "0")
return "0";
string result = "";
for(int i = num2.size() - 1; i >= 0; i--){
int carry = 0;
string temp = "";
//补0
for(int j = 0; j < num2.size() - 1 - i; j++){
temp += '0';
}
int n2 = num2[i] - '0';
for(int j = num1.size() - 1; j >= 0 || carry != 0; j--){
int n1 = j < 0 ? 0 : num1[j] - '0';
int product = (n1 * n2 + carry) % 10;
temp += to_string(product);
carry = (n1 * n2 + carry) / 10;
}
reverse(temp.begin(), temp.end());
result = addString(result, temp);
}
return result;
}
string addString(string num1, string num2){
string result = "";
int carry = 0;
for(int i = num1.size() - 1, j = num2.size() - 1; i >= 0 || j >= 0 || carry != 0; i--, j--){
int n1 = i < 0 ? 0 : num1[i] - '0';
int n2 = j < 0 ? 0 : num2[j] - '0';
int temp = (n1 + n2 + carry) % 10;
result += to_string(temp);
carry = (n1 + n2 + carry) / 10;
}
reverse(result.begin(), result.end());
return result;
}
};
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。