解法 1:
class Solution {
public:
string multiply(string num1, string num2)
{
string res = "0";
for (int i = 0; i < num2.size(); ++i) {
string str = multiplyOneNum(num1, num2[num2.size() - 1 - i], i);
res = add(res, str);
}
return res;
}
private :
string add(const string & num1, const string & num2)
{
string res;
res.reserve(max(num1.size(), num2.size()) + 1);
int idx1 = num1.size() - 1;
int idx2 = num2.size() - 1;
int carry = 0;
while (idx1 >= 0 || idx2 >= 0 || carry > 0) {
int num = 0;
if (idx1 >= 0) {
num += static_cast<int>(num1[idx1--] - '0');
}
if (idx2 >= 0) {
num += static_cast<int>(num2[idx2--] - '0');
}
if (carry > 0) {
num += carry;
}
carry = num / 10;
num = num % 10;
res.push_back(static_cast<char>(num + static_cast<int>('0')));
}
reverse(res.begin(), res.end());
res.shrink_to_fit();
return res;
}
string multiplyOneNum(const string & num1, const char & one_num , int times = 0)
{
if (one_num == '0' || num1 == "0") {
return "0";
}
string res;
res.reserve(num1.size() + 1 + times);
int carry = 0;
for (int i = num1.size() - 1; i >= 0; --i) {
int num = static_cast<int>(num1[i] - '0') * static_cast<int>(one_num - '0');
if (carry > 0) {
num += carry;
}
carry = num / 10;
num = num % 10;
res.push_back(static_cast<char>(num + static_cast<int>('0')));
}
if (carry) {
res.push_back(static_cast<char>(carry + static_cast<int>('0')));
}
reverse(res.begin(), res.end());
if (times > 0) {
res.append(times, '0');
}
res.shrink_to_fit();
return res;
}
};
总结:
设num1的长度是m,num2的长度是n,multiplyOneNum函数的时间复杂度是O(m), 由于result的长度是m + n,所以add函数的时间复杂度是O(m+n),外面又一层循环n,所以时间的计算复杂度是O(mn) + O(mn + n2),即O(mn + n2)。无论是 multiplyOneNum函数还是add函数最长使用的字符串长度是m+n,所以空间复杂度是O(m+n)。
解法 2:
class Solution {
public:
string multiply(string num1, string num2)
{
if (num1 == "0" || num2 == "0") {
return "0";
}
vector<int> num_restore(num1.size() + num2.size(), 0);
for (int i = num1.size() - 1; i >= 0; --i) {
for (int j = num2.size() - 1; j >= 0; --j) {
num_restore[(num1.size() - 1 - i) + (num2.size() - 1 - j)] += static_cast<int>((num1[i] - '0')) * static_cast<int>((num2[j] - '0'));
}
}
int add = 0;
for (int i = 0; i < num_restore.size(); ++i) {
num_restore[i] = num_restore[i] + add;
add = num_restore[i] / 10;
num_restore[i] = num_restore[i] % 10;
}
string res;
if (num_restore.back() > 0) {
res.reserve(num1.size() + num2.size());
res.push_back(static_cast<char>(static_cast<int>('0') + num_restore.back()));
}else {
res.reserve(num1.size() + num2.size() - 1);
}
for (int i = num_restore.size() - 2; i >= 0; --i) {
res.push_back(static_cast<char>(static_cast<int>('0') + num_restore[i]));
}
return res;
}
};
总结:
如果num1的长度为m,num2的长度为n,则num1和num2乘积的长度为m+n或者m+n-1,证明如下:
如代码所示,时间计算复杂度是O(mn),空间上需要一个数组num_restore,其长度为O(m+n),和解法1相比,因为计算量更少(计算量上2mn + n2 VS mn),且省去了字符串来回转换的计算,在运算效率上,解法2比解法1要快至少5倍以上(leetcode上的运行结果来看),不得不说这就是算法的厉害!