43. Multiply Strings
题目:
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.
链接: http://leetcode.com/problems/multiply-strings/
题解:
大数乘法,建立一个数组,保存每一位乘出来的数字,然后再保存成字符串就可以了。跟add two number一类的很像。
Time Complexity - O(m * n), Space Complexity - O(m + n)。
public class Solution { public String multiply(String num1, String num2) { //Big Integer multiplying if(num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0) return ""; int num1Len = num1.length(), num2Len = num2.length(); int[] resArr = new int[num1Len + num2Len]; for(int i = num1Len - 1; i >= 0; i--) { for(int j = num2Len - 1; j >= 0; j--) { int index = (num1Len - 1 - i) + (num2Len - 1 - j); //stored the data increasingly resArr[index] += (num1.charAt(i) - '0') * (num2.charAt(j) - '0'); resArr[index + 1] += resArr[index] / 10; resArr[index] %= 10; } } StringBuilder res = new StringBuilder(); for(int i = resArr.length - 1; i > 0; i--) { if(res.length() == 0 && resArr[i] == 0) continue; res.append(resArr[i]); } res.append(resArr[0]); return res.toString(); } }
二刷:
一刷的逻辑相当不清楚啊...当时怎么糊弄过去的...现在就好一些。主要思路是:
- 两数相乘,结果的长度不会大于两数长度和m + n,所以一开始我们开一个int[] res = new int[m + n]
- 接下来对num1和num2做一个双重循环从后向前遍历
- 当前的 digit1 = num1.charAt(i) - '0', digit2 = num2.charAt(j) - '0'
- 这时我们可以更新当前res[i + j + 1]的这个位置为原来存在这一位置上的值再加上新的值digits 1 * digit2,简略一下就是 res[i + j + 1] += digits 1 * digit2
- 接下来根据res[i + j + 1]的新值,我们可以更新高一位的res[i + j], res[i + j] += res[i + j + 1] / 10,就是本来的值加上进位
- 最后我们再用res[i + j + 1] %= 10求出这一位置进位后剩下的digit
- 求出res数组之后我们可以建立一个StringBuilder sb,来从头遍历数组,求出最终结果
- 要注意的是当sb.length() == 0并且res[i] = 0时,这时候是开头的0值,需要跳过
- 假如遍历完毕以后sb.length()依然等于0, 我们返回"0"
Java:
Time Complexity - O(mn), Space Complexity - O(m + n)
public class Solution { public String multiply(String num1, String num2) { if (num1 == null || num2 == null) { return ""; } int m = num1.length(), n = num2.length(); int[] res = new int[m + n]; for (int i = m - 1; i >= 0; i--) { int digit1 = num1.charAt(i) - '0'; for (int j = n - 1; j >= 0; j--) { int digit2 = num2.charAt(j) - '0'; res[i + j + 1] += digit1 * digit2; res[i + j] += res[i + j + 1] / 10; res[i + j + 1] %= 10; } } StringBuilder sb = new StringBuilder(); for (int i = 0; i < res.length; i++) { if (sb.length() == 0 && res[i] == 0) { continue; } sb.append(res[i]); } if (sb.length() == 0) { sb.append(0); } return sb.toString(); } }
题外话:
1/25/2016
NWK到JSQ的Path还没有修好,所以今天周一WFH。需要提高刷题速度了,不然难以按照进度完成。 周五晚海投了50份简历试试水,估计不内推还是很难拿到回应。
三刷:
方法和一刷二刷一样。就是先开一个数组,把num1和num2每个digit的乘积保存起来, 再进行进位操作。
要注意的是,在计算乘积的时候,num1的第i位和num2的第j位的乘积,要保存在数组的product[i + j + 1]这个位置里。用两个例子 "100 * 100"和"99 * 99"一计算就很容易能发现这个规律。 还有一点就是,最后乘积全为0的话要返回"0"。 去除乘积串前部的"0"可以用条件 if (digit != 0 || sb.length() > 0)。
更好的方法应该是Karatsuba multiply,利用Divide and Conquer将复杂度降低到nlog23 。留给以后了。
Java:
public class Solution { public String multiply(String num1, String num2) { if (num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0) return "0"; int len1 = num1.length(), len2 = num2.length(); int[] product = new int[len1 + len2]; for (int i = len1 - 1; i >= 0; i--) { int digit1 = num1.charAt(i) - '0'; for (int j = len2 - 1; j >= 0; j--) { int digit2 = num2.charAt(j) - '0'; product[i + j + 1] += digit1 * digit2; } } for (int i = product.length - 1; i >= 1; i--) { product[i - 1] += product[i] / 10; product[i] %= 10; } StringBuilder sb = new StringBuilder(); for (int digit : product) { if (digit != 0 || sb.length() > 0) sb.append(digit); } if (sb.length() == 0) sb.append(0); return sb.toString(); } }
Update: 也可以像二刷一样把进位操作写到一个循环体里
public class Solution { public String multiply(String num1, String num2) { if (num1 == null || num2 == null || num1.length() == 0 || num2.length() == 0) return "0"; int len1 = num1.length(), len2 = num2.length(); int[] product = new int[len1 + len2]; for (int i = len1 - 1; i >= 0; i--) { int digit1 = num1.charAt(i) - '0'; for (int j = len2 - 1; j >= 0; j--) { int digit2 = num2.charAt(j) - '0'; product[i + j + 1] += digit1 * digit2; product[i + j] += product[i + j + 1] / 10; product[i + j + 1] %= 10; } } StringBuilder sb = new StringBuilder(); for (int digit : product) { if (digit != 0 || sb.length() > 0) sb.append(digit); } if (sb.length() == 0) sb.append(0); return sb.toString(); } }
Reference:
http://www.cnblogs.com/springfor/p/3889706.html
https://leetcodenotes.wordpress.com/2013/10/20/leetcode-multiply-strings-%E5%A4%A7%E6%95%B4%E6%95%B0%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/
https://leetcode.com/discuss/71593/easiest-java-solution-with-graph-explanation
https://leetcode.com/discuss/26602/brief-c-solution-using-only-strings-and-without-reversal
https://leetcode.com/discuss/33951/ac-solution-in-java-with-explanation
https://leetcode.com/discuss/29364/clear-java-solution-without-reversal
http://introcs.cs.princeton.edu/java/99crypto/Karatsuba.java.html
https://d396qusza40orc.cloudfront.net/algo1/slides/algo1-intro3_typed.pdf