题目描述

image.png

题目链接

https://leetcode.cn/problems/multiply-strings/

思路

1. 做加法

如果【43】字符串相乘 - 图2【43】字符串相乘 - 图3之一是【43】字符串相乘 - 图4,则直接将【43】字符串相乘 - 图5作为结果返回即可。如果【43】字符串相乘 - 图6【43】字符串相乘 - 图7都不是【43】字符串相乘 - 图8,则可以通过模拟「竖式乘法」的方法计算乘积,竖式乘法就是我们平常学习生活中常用的对两个整数相乘的方法,即从右往左遍历乘数,将乘数的每一位与被乘数相乘得到对应的结果,再将每次得到的结果累加。
image.png
这道题中,被乘数是【43】字符串相乘 - 图10,乘数是【43】字符串相乘 - 图11注意,【43】字符串相乘 - 图12除了最低位以外,其余的每一位的运算结果都需要在低位补【43】字符串相乘 - 图13

我们对每次得到的结果进行累加,可以使用「竖式加法」的方法。竖式加法就是模拟对两个整数相加的操作,思路如下图所示:首先将相同数位对齐,从低到高逐位相加,如果当前位和超过【43】字符串相乘 - 图14,则向高位进一位。
image.png
具体来说,我们定义两个指针【43】字符串相乘 - 图16【43】字符串相乘 - 图17分别指向【43】字符串相乘 - 图18【43】字符串相乘 - 图19的末尾,即最低位,同时定义一个变量【43】字符串相乘 - 图20维护当前是否有进位,然后从右向左逐位相加即可。如果两个数字的位数不同,我们统一在指针当前下标处于负数的时候返回【43】字符串相乘 - 图21,等价于对位数较短的数字进行了补零操作,这样就可以解决两个数字位数不同的情况。

具体代码实现如下:

  1. public String multiply(String num1, String num2) {
  2. if (num1.equals("0") || num2.equals("0")) {
  3. return "0";
  4. }
  5. String ans = "0";
  6. int m = num1.length(), n = num2.length();
  7. // 乘数从右向左遍历
  8. for (int i = n - 1; i >= 0; i--) {
  9. StringBuilder curr = new StringBuilder();
  10. // 是否进位
  11. int add = 0;
  12. // 低位补0
  13. for (int j = n - 1; j > i; j--) {
  14. curr.append(0);
  15. }
  16. int y = num2.charAt(i) - '0';
  17. for (int j = m - 1; j >= 0; j--) {
  18. int x = num1.charAt(j) - '0';
  19. int product = x * y + add;
  20. curr.append(product % 10);
  21. add = product / 10;
  22. }
  23. if (add != 0) {
  24. curr.append(add % 10);
  25. }
  26. ans = addStrings(ans, curr.reverse().toString());
  27. }
  28. return ans;
  29. }
  30. public String addStrings(String num1, String num2) {
  31. int i = num1.length() - 1, j = num2.length() - 1, add = 0;
  32. StringBuilder ans = new StringBuilder();
  33. while (i >= 0 || j >= 0 || add != 0) {
  34. int x = i < 0 ? 0 : num1.charAt(i--) - '0';
  35. int y = j < 0 ? 0 : num2.charAt(j--) - '0';
  36. int sum = add + x + y;
  37. ans.append(sum % 10);
  38. add = sum / 10;
  39. }
  40. return ans.reverse().toString();
  41. }
  • 时间复杂度:【43】字符串相乘 - 图22,其中【43】字符串相乘 - 图23【43】字符串相乘 - 图24分别是【43】字符串相乘 - 图25【43】字符串相乘 - 图26的长度。需要从右往左遍历【43】字符串相乘 - 图27,对于【43】字符串相乘 - 图28的每一位,都需要和【43】字符串相乘 - 图29的每一位计算乘积,因此计算乘积的总次数是【43】字符串相乘 - 图30。字符串相加操作共【43】字符串相乘 - 图31次,相加的字符串长度最长为【43】字符串相乘 - 图32,字符串相加的时间复杂度是【43】字符串相乘 - 图33。总时间复杂度是【43】字符串相乘 - 图34,即【43】字符串相乘 - 图35
  • 空间复杂度:【43】字符串相乘 - 图36,其中【43】字符串相乘 - 图37【43】字符串相乘 - 图38分别是【43】字符串相乘 - 图39【43】字符串相乘 - 图40的长度。空间复杂度取决于存储中间状态的字符串,由于乘积的最大长度为【43】字符串相乘 - 图41,因此存储中间状态的字符串长度不会超过【43】字符串相乘 - 图42

    2. 做乘法

    方法一中的做法是从右往左遍历乘数,将乘数的每一位与被乘数相乘得到对应的结果,再将每次得到的结果累加,整个过程中涉及到较多字符串相加的操作。如果使用数组代替字符串存储结果,则可以减少对字符串的操作。

我们令【43】字符串相乘 - 图43【43】字符串相乘 - 图44分别表示【43】字符串相乘 - 图45【43】字符串相乘 - 图46的长度,并且它们均不为【43】字符串相乘 - 图47【43】字符串相乘 - 图48【43】字符串相乘 - 图49的乘积的长度肯定为【43】字符串相乘 - 图50【43】字符串相乘 - 图51证明如下:

  • 如果【43】字符串相乘 - 图52【43】字符串相乘 - 图53都取最小值(100…),则【43】字符串相乘 - 图54【43】字符串相乘 - 图55,相乘可得【43】字符串相乘 - 图56,此时乘积的长度为【43】字符串相乘 - 图57

  • 如果【43】字符串相乘 - 图58【43】字符串相乘 - 图59都取最大值(999…),则【43】字符串相乘 - 图60【43】字符串相乘 - 图61,相乘可得【43】字符串相乘 - 图62,乘积显然小于【43】字符串相乘 - 图63且大于【43】字符串相乘 - 图64,因此乘积的长度为【43】字符串相乘 - 图65

由于【43】字符串相乘 - 图66【43】字符串相乘 - 图67的乘积的最大长度为【43】字符串相乘 - 图68,因此创建长度为【43】字符串相乘 - 图69的数组【43】字符串相乘 - 图70用于存储乘积结果。对于任意【43】字符串相乘 - 图71【43】字符串相乘 - 图72【43】字符串相乘 - 图73的结果位于【43】字符串相乘 - 图74,如果【43】字符串相乘 - 图75,则将进位部分加到【43】字符串相乘 - 图76最后,将数组【43】字符串相乘 - 图77转成字符串,如果最高位是【43】字符串相乘 - 图78则舍弃最高位。 具体代码实现如下:

  1. public String multiply(String num1, String num2) {
  2. if ("0".equals(num1) || "0".equals(num2)) {
  3. return "0";
  4. }
  5. int m = num1.length(), n = num2.length();
  6. int[] ansArr = new int[m + n];
  7. // 从低位到高位遍历num1,对于num1中的每个位,分别与num2中的每个位相乘
  8. for (int i = m - 1; i >= 0; i--) {
  9. int x = num1.charAt(i) - '0';
  10. for (int j = n - 1; j >= 0; j--) {
  11. int y = num2.charAt(j) - '0';
  12. ansArr[i + j + 1] += x * y;
  13. }
  14. }
  15. // 从后往前解决进位问题
  16. for (int i = m + n - 1; i > 0; i--) {
  17. if (ansArr[i] >= 10) {
  18. ansArr[i -1] += ansArr[i] / 10;
  19. ansArr[i] = ansArr[i] % 10;
  20. }
  21. }
  22. // 组装结果
  23. StringBuilder ans = new StringBuilder();
  24. int start = ansArr[0] == 0 ? 1 : 0;
  25. for (int i = start; i < ansArr.length; i++) {
  26. ans.append(ansArr[i]);
  27. }
  28. return ans.toString();
  29. }
  • 时间复杂度:【43】字符串相乘 - 图79,其中【43】字符串相乘 - 图80【43】字符串相乘 - 图81分别是【43】字符串相乘 - 图82【43】字符串相乘 - 图83的长度。需要计算【43】字符串相乘 - 图84的每一位和【43】字符串相乘 - 图85的每一位的乘积。
  • 空间复杂度:【43】字符串相乘 - 图86,其中【43】字符串相乘 - 图87【43】字符串相乘 - 图88分别是【43】字符串相乘 - 图89【43】字符串相乘 - 图90的长度。需要创建一个长度为【43】字符串相乘 - 图91的数组存储乘积。