Given two non-negative integers num1
and num2
represented as strings, return the product of num1
and num2
.
Note:
- The length of both
num1
andnum2
is < 110. - Both
num1
andnum2
contains only digits0-9
. - Both
num1
andnum2
does not contain any leading zero. - You must not use any built-in BigInteger library or convert the inputs to integer directly.
字符串相乘问题:博主比较垃圾,长时间不做算法了,抠抠摸摸一个小时写出来下述算法Accepted;
class Solution {
public String multiply(String num1, String num2) {
int carry = 0;
int i = num1.length() - 1;
int j = num2.length() - 1;
String result = "";
String zero = "";
for(int p = i;p >= 0;p --){
String tempResult1 = "";
for(int q = j;q >= 0;q --){
int temp = ((num1.charAt(p) - 48) * (num2.charAt(q) - 48)) + carry;
carry = temp / 10;
int tempResult2 = temp % 10;
tempResult1 = tempResult2 + tempResult1;
}
if(carry != 0)
tempResult1 = carry + tempResult1;
carry = 0;
tempResult1 += zero;
result = add(result,tempResult1);
zero += "0";
}
int count = result.length();
int cut = 0;
while(result.charAt(cut) == '0' && cut != count - 1)
cut ++;
return result.substring(cut);
}
public static String add(String num1,String num2){
String result = "";
int carry = 0;
int i = num1.length() - 1,j = num2.length() - 1;
if(i < j){
for(int p = i;p < j;p ++)
num1 = "0" + num1;
}
else{
for(int p = j;p < i;p ++)
num2 = "0" + num2;
}
int num = num1.length() - 1;
while(num >= 0 ){
int temp = 0;
temp = num1.charAt(num) - 48 + num2.charAt(num) - 48 + carry;
carry = temp / 10;
result = (temp % 10) + result;
num--;
}
if(carry == 1)
result = '1' + result;
return result;
}
}
跟手算乘法有些类似。。最后运行时间只有%4.33。。
先贴一种偷懒解法(非算法)
public class Solution
{
public String multiply(String num1, String num2)
{
BigInteger temp1 = new BigInteger(num1);
BigInteger temp2 = new BigInteger(num2);
BigInteger result = temp1.multiply(temp2);
return result.toString();
}
}
在网上看到一种很精巧的解法。贴在下面供学习:
1 num1 = new StringBuilder(num1).reverse().toString();
2 num2 = new StringBuilder(num2).reverse().toString();
3 // even 99 * 99 is < 10000, so maximaly 4 digits
4 int[] d = new int[num1.length() + num2.length()];
5 for (int i = 0; i < num1.length(); i++) {
6 int a = num1.charAt(i) - '0';
7 for (int j = 0; j < num2.length(); j++) {
8 int b = num2.charAt(j) - '0';
9 d[i + j] += a * b;
10 }
11 }
12 StringBuilder sb = new StringBuilder();
13 for (int i = 0; i < d.length; i++) {
14 int digit = d[i] % 10;
15 int carry = d[i] / 10;
16 sb.insert(0, digit);
17 if (i < d.length - 1)
18 d[i + 1] += carry;
19 }
20 //trim starting zeros
21 while (sb.length() > 0 && sb.charAt(0) == '0') {
22 sb.deleteCharAt(0);
23 }
24 return sb.length() == 0 ? "0" : sb.toString();
25 }
基本思路是将最终结果的每一位都存储到一个一维数组中(为方便起见可以先反转字符串),一维数组长度为m + n或m + n - 1,m和n是两个字符串的长度,所以一维数组长度定义成m + n就够用了。然后5到9行是最精巧的部分,通过双循环将一维数组的每一位都确定(不考虑进位),最后通过遍历数组整理进位(保证每个元素小于10)去除末尾0,合成字符串反转并结束。
这种方法比较容易理解,可是究其根本来说还是有重复的地方。比如一维数组第二位上的数字通过两次运算才得出,第三位大概要经过3次运算(如果m和n都大于3的话)
网上还有一种解法应该是跑的最快,但是不好理解。
public class Solution
{
public String multiply(String num1, String num2)
{
if(num1==null || num2==null)
return "";
if(num1.charAt(0)=='0')
return "0";
if(num2.charAt(0)=='0')
return "0";
int num1length=num1.length();
int num2length=num2.length();
//分别对两个开始字符串进行转置,便于后面的下标遍历
num1=new StringBuilder(num1).reverse().toString();
num2=new StringBuilder(num2).reverse().toString();
StringBuilder res=new StringBuilder();
int jinwei=0;
//从低位开始计算,最后乘积的位数为m+n-1,如果进位则是m+n
for(int i=0;i<num1length+num2length-1;i++)
{
int multi=jinwei;
for(int j=0;j<=i;j++)
{
if(j<num1length && (i-j)<num2length)
{
multi+=(num1.charAt(j)-'0')*(num2.charAt(i-j)-'0');
}
}
res.append(multi%10);
jinwei=multi/10;
}
//考虑最后一位是否有进位
if(jinwei!=0)
res.append(jinwei);
return res.reverse().toString();
}
}
基本思想:反转字符串后从0位到末位一一确定每个位置的值,并立刻处理进位。比如第二位由两个数的1,2位和2,1位相乘相加确定,第三位由两个数1,3位3,1位,2,2位决定。。以此类推,代码比较难理解,但是应该是效率最高的。