数据结构与算法之深入解析“字符串相乘”的求解思路与算法示例
Posted Serendipity·y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法之深入解析“字符串相乘”的求解思路与算法示例相关的知识,希望对你有一定的参考价值。
一、题目要求
- 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
- 注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
- 示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
- 示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
- 提示:
-
- 1 <= num1.length, num2.length <= 200;
-
- num1 和 num2 只能由数字组成;
-
- num1 和 num2 都不包含任何前导零,除了数字 0 本身。
二、求解算法
① 普通竖式
- 竖式运算思想,以 num1 为 123,num2 为 456 为例分析:
- 遍历 num2 每一位与 num1 进行相乘,将每一步的结果进行累加。
- 注意:
-
- num2 除了第一位的其他位与 num1 运算的结果需要补 0;
-
- 计算字符串数字累加,其实可以参考:数据结构与算法】之深入解析“字符串相加”的求解思路与算法示例。
- Java 示例:
class Solution
/**
* 计算形式
* num1
* x num2
* ------
* result
*/
public String multiply(String num1, String num2)
if (num1.equals("0") || num2.equals("0"))
return "0";
// 保存计算结果
String res = "0";
// num2 逐位与 num1 相乘
for (int i = num2.length() - 1; i >= 0; i--)
int carry = 0;
// 保存 num2 第i位数字与 num1 相乘的结果
StringBuilder temp = new StringBuilder();
// 补 0
for (int j = 0; j < num2.length() - 1 - i; j++)
temp.append(0);
int n2 = num2.charAt(i) - '0';
// num2 的第 i 位数字 n2 与 num1 相乘
for (int j = num1.length() - 1; j >= 0 || carry != 0; j--)
int n1 = j < 0 ? 0 : num1.charAt(j) - '0';
int product = (n1 * n2 + carry) % 10;
temp.append(product);
carry = (n1 * n2 + carry) / 10;
// 将当前结果与新计算的结果求和作为新的结果
res = addStrings(res, temp.reverse().toString());
return res;
/**
* 对两个字符串数字进行相加,返回字符串形式的和
*/
public String addStrings(String num1, String num2)
StringBuilder builder = new StringBuilder();
int carry = 0;
for (int i = num1.length() - 1, j = num2.length() - 1;
i >= 0 || j >= 0 || carry != 0;
i--, j--)
int x = i < 0 ? 0 : num1.charAt(i) - '0';
int y = j < 0 ? 0 : num2.charAt(j) - '0';
int sum = (x + y + carry) % 10;
builder.append(sum);
carry = (x + y + carry) / 10;
return builder.reverse().toString();
② 优化竖式
- 该算法是通过两数相乘时,乘数某位与被乘数某位相乘,与产生结果的位置的规律来完成。
- 具体规律如下:
-
- 乘数 num1 位数为 M,被乘数 num2 位数为 N, num1 x num2 结果 res 最大总位数为 M+N;
-
- num1[i] x num2[j] 的结果为 tmp(位数为两位,“0x”、"xy"的形式),其第一位位于 res[i+j],第二位位于 res[i+j+1]。
- Java 示例:
class Solution
public String multiply(String num1, String num2)
if (num1.equals("0") || num2.equals("0"))
return "0";
int[] res = new int[num1.length() + num2.length()];
for (int i = num1.length() - 1; i >= 0; i--)
int n1 = num1.charAt(i) - '0';
for (int j = num2.length() - 1; j >= 0; j--)
int n2 = num2.charAt(j) - '0';
int sum = (res[i + j + 1] + n1 * n2);
res[i + j + 1] = sum % 10;
res[i + j] += sum / 10;
StringBuilder result = new StringBuilder();
for (int i = 0; i < res.length; i++)
if (i == 0 && res[i] == 0) continue;
result.append(res[i]);
return result.toString();
③ 做乘法(LeetCode 官方解法)
- 加法做法是从右往左遍历乘数,将乘数的每一位与被乘数相乘得到对应的结果,再将每次得到的结果累加,整个过程中涉及到较多字符串相加的操作。如果使用数组代替字符串存储结果,则可以减少对字符串的操作。
- 令 m 和 n 分别表示 num1 和 num2 的长度,并且它们均不为 0,则 num1 和 num2 的乘积的长度为 m+n−1 或 m+n。简单证明如下:
-
- 如果 num1 和 num2 都取最小值,则 num1 = 10m−1,num2 = 10n−1,num1 × num2 = 10m+n−2,乘积的长度为 m+n−1;
-
- 如果 num1 和 num2 都取最大值,则 num1 =10m−1,num2 = 10n−1,num1 × num2 = 10m+n−10m−10n+1,乘积显然小于 10m+n 且大于 10m+n−1,因此乘积的长度为 m+n。
- 由于 num1 和 num2 的乘积的最大长度为 m+n,因此创建长度为 m+n 的数组 ansArr 用于存储乘积。对于任意 0≤i<m 和 0≤j<n,num1[i]×num2[j] 的结果位于 ansArr[i+j+1],如果 ansArr[i+j+1]≥10,则将进位部分加到 ansArr[i+j]。
- 最后,将数组 ansArr 转成字符串,如果最高位是 0 则舍弃最高位。
- Java 示例:
class Solution
public String multiply(String num1, String num2)
if (num1.equals("0") || num2.equals("0"))
return "0";
int m = num1.length(), n = num2.length();
int[] ansArr = new int[m + n];
for (int i = m - 1; i >= 0; i--)
int x = num1.charAt(i) - '0';
for (int j = n - 1; j >= 0; j--)
int y = num2.charAt(j) - '0';
ansArr[i + j + 1] += x * y;
for (int i = m + n - 1; i > 0; i--)
ansArr[i - 1] += ansArr[i] / 10;
ansArr[i] %= 10;
int index = ansArr[0] == 0 ? 1 : 0;
StringBuffer ans = new StringBuffer();
while (index < m + n)
ans.append(ansArr[index]);
index++;
return ans.toString();
- C++ 示例:
class Solution
public:
string multiply(string num1, string num2)
if (num1 == "0" || num2 == "0")
return "0";
int m = num1.size(), n = num2.size();
auto ansArr = vector<int>(m + n);
for (int i = m - 1; i >= 0; i--)
int x = num1.at(i) - '0';
for (int j = n - 1; j >= 0; j--)
int y = num2.at(j) - '0';
ansArr[i + j + 1] += x * y;
for (int i = m + n - 1; i > 0; i--)
ansArr[i - 1] += ansArr[i] / 10;
ansArr[i] %= 10;
int index = ansArr[0] == 0 ? 1 : 0;
string ans;
while (index < m + n)
ans.push_back(ansArr[index]);
index++;
for (auto &c: ans)
c += '0';
return ans;
;
以上是关于数据结构与算法之深入解析“字符串相乘”的求解思路与算法示例的主要内容,如果未能解决你的问题,请参考以下文章
数据结构与算法之深入解析“股票的最大利润”的求解思路与算法示例