题目:
Given two numbers represented as strings, return multiplication of the numbers as a string.
Note: The numbers can be arbitrarily large and are non-negative.
思路:非常tricky的一道题。
主要的思路是模拟一个手算乘法的过程,那么可以用一个二维矩阵去代替中间的步骤(即乘数的每一位与被乘数相乘所得的积)。第二步是错位相加,如果按照从上向下,从右向左来标记矩阵的index,可以发现相加的元素满足一个条件:行index和列index的和始终相等。于是想到,可以压缩到一个一维矩阵。在这个过程中,并不去处理进位的问题,每一个element可能是多位数。reverse的作用在于使得两个string的末尾对齐,不然对于index的操作会非常繁琐。
接下来就是如何从这个和的数组中取出所有的位。由于和只能从后往前取,最后的结果需要从前往后生成,当然从后向前生成,利用str.insert(0, digit)不断的插入,但是这样会造成内存的反复读写。于是想到用一个stack去读,之后还需要把carry生成的位全部读进去。
最后需要注意的是开头可能会有0,需要忽略掉,但是如果全是0,需要保留最后一个。
class Solution {
public:
string multiply(string num1, string num2) {
reverse(num1.begin(), num1.end());
reverse(num2.begin(), num2.end());
int len1 = (int)num1.size();
int len2 = (int)num2.size();
vector<int> temp(len1 + len2, 0);
for (int i = 0; i < len2; ++i) {
for (int j = 0; j < len1; ++j) {
temp[i+j] += (num2[i] - '0') * (num1[j] - '0');
}
}
int carry = 0;
stack<int> s_result;
// get all the digits from the temp array
for (int i = 0; i < (int)temp.size(); ++i) {
s_result.push((temp[i] + carry) % 10);
carry = (temp[i] + carry) / 10;
}
// get all the digits generated by the carry
while (carry > 0) {
s_result.push(carry % 10);
carry /= 10;
}
// discard all the '0's in the front, but should leave one
while (s_result.top() == 0 && s_result.size() > 1) s_result.pop();
string result = "";
while (!s_result.empty()) {
result.push_back(s_result.top() + '0');
s_result.pop();
}
return result;
}
};
总结:复杂度为O(nlogn).