Merge branch 'english' of https://github.com/labuladong/fucking-algorithm into english
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 414 KiB After Width: | Height: | Size: 414 KiB |
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
BIN
pictures/string_multiplication/title_en.jpg
Normal file
After Width: | Height: | Size: 26 KiB |
76
think_like_computer/string_multiplication.md
Normal file
@ -0,0 +1,76 @@
|
||||
# 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.
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
`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:
|
||||
|
||||

|
||||
|
||||
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`__:
|
||||
|
||||

|
||||
|
||||
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]`__.
|
||||
|
||||

|
||||
|
||||
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.
|
@ -1,76 +0,0 @@
|
||||
# 字符串乘法
|
||||
|
||||
对于比较小的数字,做运算可以直接使用编程语言提供的运算符,但是如果相乘的两个因数非常大,语言提供的数据类型可能就会溢出。一种替代方案就是,运算数以字符串的形式输入,然后模仿我们小学学习的乘法算术过程计算出结果,并且也用字符串表示。
|
||||
|
||||

|
||||
|
||||
需要注意的是,`num1` 和 `num2` 可以非常长,所以不可以把他们直接转成整型然后运算,唯一的思路就是模仿我们手算乘法。
|
||||
|
||||
比如说我们手算 `123 × 45`,应该会这样计算:
|
||||
|
||||

|
||||
|
||||
计算 `123 × 5`,再计算 `123 × 4`,最后错一位相加。这个流程恐怕小学生都可以熟练完成,但是你是否能**把这个运算过程进一步机械化**,写成一套算法指令让没有任何智商的计算机来执行呢?
|
||||
|
||||
你看这个简单过程,其中涉及乘法进位,涉及错位相加,还涉及加法进位;而且还有一些不易察觉的问题,比如说两位数乘以两位数,结果可能是四位数,也可能是三位数,你怎么想出一个标准化的处理方式?这就是算法的魅力,如果没有计算机思维,简单的问题可能都没办法自动化处理。
|
||||
|
||||
首先,我们这种手算方式还是太「高级」了,我们要再「低级」一点,`123 × 5` 和 `123 × 4` 的过程还可以进一步分解,最后再相加:
|
||||
|
||||

|
||||
|
||||
现在 `123` 并不大,如果是个很大的数字的话,是无法直接计算乘积的。我们可以用一个数组在底下接收相加结果:
|
||||
|
||||

|
||||
|
||||
整个计算过程大概是这样,**有两个指针 `i,j` 在 `num1` 和 `num2` 上游走,计算乘积,同时将乘积叠加到 `res` 的正确位置**:
|
||||
|
||||

|
||||
|
||||
现在还有一个关键问题,如何将乘积叠加到 `res` 的正确位置,或者说,如何通过 `i,j` 计算 `res` 的对应索引呢?
|
||||
|
||||
其实,细心观察之后就发现,**`num1[i]` 和 `num2[j]` 的乘积对应的就是 `res[i+j]` 和 `res[i+j+1]` 这两个位置**。
|
||||
|
||||

|
||||
|
||||
明白了这一点,就可以用代码模仿出这个计算过程了:
|
||||
|
||||
```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 获取最新文章:
|
||||
|
||||

|
30
translation_requirements.md
Normal file
@ -0,0 +1,30 @@
|
||||
Thank you all for your participation in the translation!
|
||||
|
||||
please clone newest `english` branch, please see [closed pull request](https://github.com/labuladong/fucking-algorithm/pulls?q=is%3Apr+is%3Aclosed) Make sure that the article you are translating is currently not available in English.
|
||||
|
||||
After the translation is completed, please delete the public account QR code at the end of the text. For the first translated version submitted, you can add authors and translators below the first level heading at the beginning of the article:
|
||||
|
||||
**Translator: [YourName](https://github.com/YourName)**
|
||||
|
||||
**Author: [labuladong](https://github.com/labuladong)**
|
||||
|
||||
Your link can point you wherever you want.
|
||||
### Translation convention
|
||||
|
||||
1、The translation must be smooth and consistent with the English grammar. Basic technical terms such as Queue, stack, binary tree, etc. should be used correctly. Misuse of such words can be confusing. For Chinese that is not easy to translate, you can modify it according to your understanding. **After translation, be sure to check the basic grammar with a tool, such as pasting your English text into Word to see if there are any basic grammatical errors **.
|
||||
|
||||
2、**All content should be subject to the `master` branch**, because the` english` branch is only for translation and will not update the article. So if you find that an article in the `master` does not exist or conflicts in the` english` branch, translate it based on the md file in the `master` branch. Do n’t forget to add the relevant picture folder to` english `Branch.
|
||||
|
||||
3、**Boldness and other information need to be retained, while encouraging the expansion of your own knowledge**, adding references, adding important knowledge points in bold or using English (or other languages) unique forms of expression to express certain ideas.
|
||||
|
||||
4. For pictures, Chinese characters are rarely included. If it does not affect understanding, such as the public number watermark in the lower right corner of the picture, you do not need to modify it.**If the Chinese character involves algorithmic understanding, you need to modify the picture together**, erase the Chinese character and replace it with English, or if there are few Chinese characters, add the corresponding English beside the Chinese characters. **For some pictures that describe the topic**, they are all the pictures I took on the Chinese version of LeetCode. You can go to the English version of LeetCode to find the corresponding topic screenshot replacement. If you do n’t know which question, you can leave a message in the issue and I will give You look for. The original Chinese md file needs to be deleted.
|
||||
|
||||
5. **Keep the original directory structure, but the names of files and folders should be changed to English**. The name of the md file should be modified to the appropriate English according to the content of the specific article (files should not include spaces), the pictures cited in the article The path sometimes also contains Chinese, you need to change the folder containing the picture to appropriate English. **After the translation is complete, you need to delete the md file in the original Chinese**. If you added an English version of the picture, you should also delete the original Chinese picture.
|
||||
|
||||
6. **Only process the articles (and related pictures) agreed in the issue, and do not move any other content**, otherwise conflicts will easily occur when you submit results to the main repository in the future. If there is a conflict, you need to find a way to use Git tools to resolve the version conflict between the local repository and the main repository before you can submit a pull request. It is very important to practice using Git.
|
||||
|
||||
In fact, none of the algorithmic questions we brush up have any special English words, and many of the crooked nuts are not necessarily English. Google Translator's translation of articles with a bit of terms (stack, queue, etc.) is very poor, and even the code translates for you, so don't be afraid to turn it bravely, we will gradually improve in iterations ~
|
||||
|
||||
PS: Again, don't modify the articles other than those agreed in the issue, so that your pr will not conflict. Committing your branch also requires committing to the `english` branch. Do not submit any changes to the` master` branch.
|
||||
|
||||
**Become a contributor!**
|