题目
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.
分析
这道题是2016年3月28日阿里内推笔试的第二题. 假设输入的字符串长度分别为 len1 和 len2, 那么两者之积所得字符串的长度不会超过 len1+len2. 因此分配长度为 len1+len2+1的字符数组存储最终计算结果.
令 num1 指向较长 (如果长度不等) 的字符串, num2 指向另一字符串.
注意 num1 和 num2 所代表的数字的最低位都是字符串的最后一个元素. 从num1所代表的数字的最低位开始依次向高位前进, 把每一位与 num2 所指代的数字的每一位 (从低到高) 相乘. 由于两位相乘可能产生进位carry
, 同时由于仅使用了一维数组, 因此结果数组中可能存在上一轮计算已有的结果upper
, 要把这两项加入乘积, 得到tmp
. 随后根据tmp
得出新的进位以及存入结果数组的数值.
计算结束后, 结果数组从后向前遍历, 找到第一个非0元素, 然后将字符串转置, 最终返回结果.
解答
char* multiply(char* num1, char* num2) {
int len1 = strlen(num1);
int len2 = strlen(num2);
// the length of the result is at most len1+len2
// +1 to store '\0'
char *result = malloc(sizeof(char) * (len1+len2+1));
memset(result, '0', sizeof(char) * (len1+len2+1));
result[len1+len2] = '\0';
if (len1 < len2) {
// make num1 point to the longer one
char *t;
int templen;
t = num1; num1 = num2; num2 = t;
templen = len1; len1 = len2; len2 = templen;
}
for (int i = len1 - 1; i >= 0; i--) {
// bdi means base digit index
// for each i, it is the index of the silo in `result`
// to which the lowest digit of the product is stored
int bdi = len1-1-i;
int a = num1[i] - '0';
int carry = 0;
int k = 0;
for (int j = len2 - 1; j >= 0; j--) {
int b = num2[j] - '0';
// k is the index of the silo in `result`
// to which the last digit of the
// current product is stored. It can also be
// used to access previous digit stored in this silo,
// i.e. `upper`
k = bdi + (len2-1-j);
int upper = result[k] - '0';
int tmp = a * b + upper + carry;
carry = tmp / 10;
result[k] = tmp % 10 + '0';
}
// if there is a carry, store it to the next digit
if (carry > 0) {
result[k+1] = carry + '0';
}
}
int i;
// skip leading zeros
for (i = len1+len2-1; i >= 0; i--) {
if (result[i] != '0') {
break;
}
}
if (i < 0) {
// didn't come here from break, so all digits
// are zero, thus the result is zero
result[1] = '\0';
return result;
}
result[i+1] = '\0'; // terminate the string
// reverse the string
for (int j = 0; j < (i + 1) / 2; j++) {
char tmp = result[j];
result[j] = result[i-j];
result[i-j] = tmp;
}
return result;
}