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.
[分析] Naive的做法是模拟笔算乘法操作,从高位到低位的顺序将num2 上的每一位同num1 相乘,由于运算顺序从高到低,每次运算时将上一次运算结果后加0,(相当于*10)后同本次乘积结果加和。 高效做法(Method 2)思路:num1 * num2, num2上的每一位依次和num1中的每一位相乘,num2的个位同num1的个位相乘结果包含在最终乘积的个位上,同理num2的个位同num1的十位相乘结果包含在最终乘积的十位上,num2的十位同num1的个位相乘结果也包含在最终乘积的十位上,一般的,num2的第 i 位 同num1的第 j 位相乘结果包含在最终乘积的第 i + j 位,遍历两个数的每一位,可以得到最终乘积各位上的结果。这样得到的乘积各位上可能是两位数,因此还需要处理使得乘积结果各位上为单个数字,处理方式就是依次进位。Method 1有O(m * n)次 *、\、% 以及字符串append操作, O(m * (m + n))次 +, append操作,而Method 2仅有O(m * n)次 *、+ 以及O(m + n)次 \、%、append操作,我们知道除法和取模是最耗时的,所以前者超时也就不难怪了。
Note: The numbers can be arbitrarily large and are non-negative.
[分析] Naive的做法是模拟笔算乘法操作,从高位到低位的顺序将num2 上的每一位同num1 相乘,由于运算顺序从高到低,每次运算时将上一次运算结果后加0,(相当于*10)后同本次乘积结果加和。 高效做法(Method 2)思路:num1 * num2, num2上的每一位依次和num1中的每一位相乘,num2的个位同num1的个位相乘结果包含在最终乘积的个位上,同理num2的个位同num1的十位相乘结果包含在最终乘积的十位上,num2的十位同num1的个位相乘结果也包含在最终乘积的十位上,一般的,num2的第 i 位 同num1的第 j 位相乘结果包含在最终乘积的第 i + j 位,遍历两个数的每一位,可以得到最终乘积各位上的结果。这样得到的乘积各位上可能是两位数,因此还需要处理使得乘积结果各位上为单个数字,处理方式就是依次进位。Method 1有O(m * n)次 *、\、% 以及字符串append操作, O(m * (m + n))次 +, append操作,而Method 2仅有O(m * n)次 *、+ 以及O(m + n)次 \、%、append操作,我们知道除法和取模是最耗时的,所以前者超时也就不难怪了。
// method 2:
public String multiply(String num1, String num2) {
if (num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0)
return null;
if (num1.length() < num2.length())
return multiply(num2, num1);
if (num2.equals("0")) return "0";
if (num2.equals("1")) return num1;
int[] result = new int[num1.length() + num2.length() - 1];
for (int i = num2.length() - 1; i >= 0; i--) {
int digit1 = num2.charAt(i) - '0';
for (int j = num1.length() - 1; j >= 0; j--) {
result[i + j] += digit1 * (num1.charAt(j) - '0');
}
}
int carry = 0;
for (int i = result.length - 1; i >= 0; i--) {
result[i] += carry;
carry = result[i] / 10;
result[i] %= 10;
}
StringBuilder val = new StringBuilder();
if (carry > 0)
val.append(carry);
for (int i = 0; i < result.length; i++)
val.append(result[i]);
return val.toString();
}
// method 1 :
public String multiply1(String num1, String num2) {
if (num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0)
return null;
String result = "";
for (int i = 0; i < num2.length(); i++) {
result = add(result + '0', multiOneDigit(num1, num2.charAt(i) - '0'));
}
return result;
}
private String add(String num1, String num2) {
if (num1.length() < num2.length()) {
String tmp = num2;
num2 = num1;
num1 = tmp;
}
StringBuilder sum = new StringBuilder();
int carry = 0, val = 0;
int i = num1.length() - 1, j = num2.length() - 1;
while (j >= 0) {
val = (num1.charAt(i) - '0') + (num2.charAt(j) - '0');
sum.append(val - 10); // val % 10
carry = val >= 10 ? 1 : 0; // val / 10
i--; j--;
}
while (i >= 0) {
val = (num1.charAt(i--) - '0') + carry;
sum.append(val - 10);
carry = val >= 10 ? 1 : 0;
}
if (carry > 0) sum.append(carry);
return sum.reverse().toString();
}
private String multiOneDigit(String num1, int num2) {
StringBuilder result = new StringBuilder();
int carry = 0, val = 0;
for (int i = num1.length() - 1; i >= 0; i--) {
val = (num1.charAt(i) - '0') * num2 + carry;
result.append(val % 10);
carry = val / 10;
}
if (carry > 0)
result.append(carry);
return result.reverse().toString();
}