未验证 提交 266e8bb4 编写于 作者: L labuladong 提交者: GitHub

Merge pull request #160 from youyun/english

issue 159 translation
# String Multiplication
**Translator: [youyun](https://github.com/youyun)**
**Author: [labuladong](https://github.com/labuladong)**
For relatively small numbers, you can calculate directly using the operators provided by a programming language. When the numbers become very big, the default data types might overflow. An alternative way is to use string to represent the numbers, perform the multiplication in the primary school way, and produce the result as string as well. Take [this question](https://leetcode.com/problems/multiply-strings/) as an example.
![](../pictures/string_multiplication/title_en.jpg)
Note that both `num1` and `num2` can be very long. We can't directly calculate by transforming them to integers. We can learn from the process multiplying by hand.
For example, when we multiply `123 × 45` by hand, the process is shown in the following diagram:
![](../pictures/string_multiplication/1.jpg)
Firstly, calculate `123 × 5`. Then calculate `123 × 4`. In the end, add them together by shifting one digit. We learned this method in primary school. Can we __generalize the steps in this process__, such that a computer can understand?
This simple process actually involves a lot of knowledge - carry of multiplication, carry of addition, and adding numbers by shifting digits. Another not so obvious issue is the number of digits of the final result. When two two-digit numbers multiply, the result can be either four-digit or three-digit. How to generalize this? Without the mindset of a computer, we can't even automate simple problems. This is the beauty of algorithms.
Well, this process is still too high-level. Let's try something at a lower level. The processes of `123 × 5` and `123 × 4` can be further broken into parts and add together:
![](../pictures/string_multiplication/2.jpg)
`123` is pretty small. If the number is large, we can't get the product directly. An array can help to store the result of addition:
![](../pictures/string_multiplication/3.jpg)
Here is the rough process of calculation. __Two pointers `i, j` moves at `num1` and `num2` to multiply, adding the products to the correct positions of `res`__:
![](../pictures/string_multiplication/4.gif)
There is a key question now. How to add products to the correct positions of `res`? In other words, how to use `i, j` to calculate the corresponding indices in `res`?
With careful observation, __the product of `num1[i]` and `num2[j]` corresponds to `res[i+j]` and `res[i+j+1]`__.
![](../pictures/string_multiplication/6.jpg)
If we understand the above, we should be able to translate the process into code:
```java
string multiply(string num1, string num2) {
int m = num1.size(), n = num2.size();
// the max number of digits in result is m + n
vector<int> res(m + n, 0);
// multiply from the rightmost digit
for (int i = m - 1; i >= 0; i--)
for (int j = n - 1; j >= 0; j--) {
int mul = (num1[i]-'0') * (num2[j]-'0');
// the corresponding index of product in res
int p1 = i + j, p2 = i + j + 1;
// add to res
int sum = mul + res[p2];
res[p2] = sum % 10;
res[p1] += sum / 10;
}
// the result may have prefix of 0 (which is unused)
int i = 0;
while (i < res.size() && res[i] == 0)
i++;
// transform the result into string
string str;
for (; i < res.size(); i++)
str.push_back('0' + res[i]);
return str.size() == 0 ? "0" : str;
}
```
We have just completed the string multiplication.
__In summary__, some of our common ways of think may be hard to achieve by computer. For instance, the process of our calculation is not that complicated. But it is not easy to translate this process into code. Our algorithm needs to simplify the calculation process, achieve the result by adding while multiplying at the same time.
People usually say that we need to think out of the box, be creative, and be different. But systematic thinking can be a good thing. It can improve the efficiency and reduce the error rate. Algorithms are based on systematic thinking, and can help us to resolve complex problems.
Maybe algorithms are a kind of __mindset to find a systematic thinking__. Hope this article helps.
# 字符串乘法
对于比较小的数字,做运算可以直接使用编程语言提供的运算符,但是如果相乘的两个因数非常大,语言提供的数据类型可能就会溢出。一种替代方案就是,运算数以字符串的形式输入,然后模仿我们小学学习的乘法算术过程计算出结果,并且也用字符串表示。
![](../pictures/%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/title.png)
需要注意的是,`num1``num2` 可以非常长,所以不可以把他们直接转成整型然后运算,唯一的思路就是模仿我们手算乘法。
比如说我们手算 `123 × 45`,应该会这样计算:
![](../pictures/%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/1.jpg)
计算 `123 × 5`,再计算 `123 × 4`,最后错一位相加。这个流程恐怕小学生都可以熟练完成,但是你是否能**把这个运算过程进一步机械化**,写成一套算法指令让没有任何智商的计算机来执行呢?
你看这个简单过程,其中涉及乘法进位,涉及错位相加,还涉及加法进位;而且还有一些不易察觉的问题,比如说两位数乘以两位数,结果可能是四位数,也可能是三位数,你怎么想出一个标准化的处理方式?这就是算法的魅力,如果没有计算机思维,简单的问题可能都没办法自动化处理。
首先,我们这种手算方式还是太「高级」了,我们要再「低级」一点,`123 × 5``123 × 4` 的过程还可以进一步分解,最后再相加:
![](../pictures/%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/2.jpg)
现在 `123` 并不大,如果是个很大的数字的话,是无法直接计算乘积的。我们可以用一个数组在底下接收相加结果:
![](../pictures/%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/3.jpg)
整个计算过程大概是这样,**有两个指针 `i,j` 在 `num1` 和 `num2` 上游走,计算乘积,同时将乘积叠加到 `res` 的正确位置**
![](../pictures/%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/4.gif)
现在还有一个关键问题,如何将乘积叠加到 `res` 的正确位置,或者说,如何通过 `i,j` 计算 `res` 的对应索引呢?
其实,细心观察之后就发现,**`num1[i]` 和 `num2[j]` 的乘积对应的就是 `res[i+j]` 和 `res[i+j+1]` 这两个位置**
![](../pictures/%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%98%E6%B3%95/6.jpg)
明白了这一点,就可以用代码模仿出这个计算过程了:
```java
string multiply(string num1, string num2) {
int m = num1.size(), n = num2.size();
// 结果最多为 m + n 位数
vector<int> res(m + n, 0);
// 从个位数开始逐位相乘
for (int i = m - 1; i >= 0; i--)
for (int j = n - 1; j >= 0; j--) {
int mul = (num1[i]-'0') * (num2[j]-'0');
// 乘积在 res 对应的索引位置
int p1 = i + j, p2 = i + j + 1;
// 叠加到 res 上
int sum = mul + res[p2];
res[p2] = sum % 10;
res[p1] += sum / 10;
}
// 结果前缀可能存的 0(未使用的位)
int i = 0;
while (i < res.size() && res[i] == 0)
i++;
// 将计算结果转化成字符串
string str;
for (; i < res.size(); i++)
str.push_back('0' + res[i]);
return str.size() == 0 ? "0" : str;
}
```
至此,字符串乘法算法就完成了。
**总结一下**,我们习以为常的一些思维方式,在计算机看来是非常难以做到的。比如说我们习惯的算术流程并不复杂,但是如果让你再进一步,翻译成代码逻辑,并不简单。算法需要将计算流程再简化,通过边算边叠加的方式来得到结果。
俗话教育我们,不要陷入思维定式,不要程序化,要发散思维,要创新。但我觉得程序化并不是坏事,可以大幅提高效率,减小失误率。算法不就是一套程序化的思维吗,只有程序化才能让计算机帮助我们解决复杂问题呀!
也许算法就是一种**寻找思维定式的思维**吧,希望本文对你有帮助。
坚持原创高质量文章,致力于把算法问题讲清楚,欢迎关注我的公众号 labuladong 获取最新文章:
![labuladong](../pictures/labuladong.jpg)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册