Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

贪心算法,你入门了吗? #7035

Merged
merged 49 commits into from
May 13, 2020
Merged
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
afb007d
更新测试
chaingangway Mar 30, 2020
a261e82
Revert "更新测试"
chaingangway Mar 30, 2020
862cc57
8 个值得了解的树形数据结构 (#6804)
Amberlin1970 Mar 27, 2020
0632846
眼动跟踪和移动世界的最佳用户体验实践 (#6806)
Charlo-O Mar 27, 2020
a66e069
我并不讨厌箭头函数(#6610) (#6659)
TiaossuP Mar 27, 2020
28c79b4
掌握 JavaScript 面试:什么是纯函数? (#6828)
nia3y Mar 28, 2020
57bd9bd
fix:文章翻译问题 (#6833)
fireairforce Mar 28, 2020
95eec4a
用依赖注入来解耦你的代码 (#6823)
JalanJiang Mar 29, 2020
e4c0cac
Create generator-functions-in-javascript.md (#6841)
lsvih Mar 31, 2020
0465602
Create how-to-keep-your-dependencies-secure-and-up-to-date.md (#6843)
lsvih Mar 31, 2020
bc64328
Create deep-dive-into-react-fiber-internals.md (#6845)
lsvih Mar 31, 2020
e4759ff
Update deep-dive-into-react-fiber-internals.md
lsvih Mar 31, 2020
4e78a12
Create how-can-cloud-services-help-improve-your-businessess-efficienc…
lsvih Mar 31, 2020
ae7da28
Create should-you-learn-vim-as-a-developer-in-2020.md (#6849)
lsvih Mar 31, 2020
6738a6e
Go 发布新版 Protobuf API (#6827)
stuchilde Mar 31, 2020
d884798
JSON.stringify() 的 5 个秘密特性 (#6793)
fireairforce Mar 31, 2020
d04aff3
Create high-speed-inserts-with-mysql.md (#6853)
lsvih Apr 1, 2020
85cc9e1
组合软件:书 (#6832)
fireairforce Apr 2, 2020
d8fc4d3
Create 6-best-javascript-frameworks-in-2020.md (#6861)
lsvih Apr 3, 2020
a8c74da
2020 年用各大前端框架构建的 RealWorld 应用对比 (#6851)
snowyYU Apr 4, 2020
77f1fb3
Create the-importance-of-why-docs.md (#6868)
lsvih Apr 6, 2020
8260ddc
不变性之道 (#6857)
nia3y Apr 6, 2020
548dfe6
Create polymorphic-react-components.md (#6870)
lsvih Apr 6, 2020
b8ba5b2
Create active-learning-in-machine-learning.md (#6872)
lsvih Apr 6, 2020
509ad30
Create kafka-vs-rabbitmq-why-use-kafka.md (#6874)
lsvih Apr 6, 2020
bc01bdc
Create i-built-an-app-that-uses-all-7-new-features-in-javascript-es20…
lsvih Apr 6, 2020
d278484
云服务如何帮助你提高业务效率? (#6859)
QinRoc Apr 7, 2020
d250ddb
NestJS 实现基本用户认证和会话 (#6731)
eizyc Apr 7, 2020
b1a3030
作为 2020 年的开发者,你应该学习 VIM 吗? (#6856)
chaingangway Apr 7, 2020
da77d74
MySQL 最佳实践—— 高效插入数据 (#6863)
stuchilde Apr 8, 2020
5531303
Create combine-getting-started.md (#6883)
lsvih Apr 9, 2020
69ae6a6
Create how-to-be-a-good-remote-developer.md (#6885)
lsvih Apr 9, 2020
6c210ce
Create why-is-object-immutability-important.md (#6887)
lsvih Apr 9, 2020
e0b042e
Create what-on-earth-is-the-shadow-dom-and-why-it-matters.md
lsvih Apr 9, 2020
cc61cef
2020 年排名前 6 位的 JavaScript 框架 (#6867)
QinRoc Apr 9, 2020
53c6ba1
JavaScript 风格元素 (#6878)
febrainqu Apr 9, 2020
533bef9
怎样让依赖库保持安全和最新 (#6864)
chaingangway Apr 9, 2020
ff11c6e
Create 5-best-practices-to-prevent-git-leaks.md (#6894)
lsvih Apr 10, 2020
e3a066a
Create swiftui-3d-scroll-effect.md (#6896)
lsvih Apr 10, 2020
7153da6
Web 应用程序中的数据和 UI 分离 (#6794)
fireairforce Apr 10, 2020
e113faf
fix:typo (#6903)
fireairforce Apr 12, 2020
ce21ade
Merge remote-tracking branch 'upstream/master'
chaingangway Apr 15, 2020
2adbc9c
Merge remote-tracking branch 'upstream/master'
chaingangway Apr 22, 2020
b9ec935
Merge remote-tracking branch 'upstream/master'
chaingangway Apr 26, 2020
02177ea
Merge branch 'master' of https://github.com/xitu/gold-miner
chaingangway Apr 29, 2020
f16b66d
Merge remote-tracking branch 'upstream/master'
chaingangway May 2, 2020
a5be716
Merge remote-tracking branch 'upstream/master'
chaingangway May 6, 2020
fe5ce76
初译完成
chaingangway May 9, 2020
10281db
第一次校对
chaingangway May 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 38 additions & 38 deletions article/2020/greedy-algorithms-101.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@
> * 原文作者:[Mario Osorio](https://medium.com/@mario5o)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/article/2020/greedy-algorithms-101.md](https://github.com/xitu/gold-miner/blob/master/article/2020/greedy-algorithms-101.md)
> * 译者:
> * 校对者:
> * 译者:[chaingangway](https://github.com/chaingangway)
> * 校对者:[PingHGao](https://github.com/PingHGao)
chaingangway marked this conversation as resolved.
Show resolved Hide resolved

# Greedy Algorithms 101
# 贪心算法,你入门了吗?

![](https://cdn-images-1.medium.com/max/2000/0*udmPDWYUmHDNJX5D)
chaingangway marked this conversation as resolved.
Show resolved Hide resolved

Greedy algorithms are easy to implement in most cases, they are one of the most used programming schemas when it comes to solving optimization problems, they are also a very good option because of their low resource consumption.
贪心算法在大多数情况下都易于实现,在求解最优问题时,也是最常用的编码套路之一,而且它的资源消耗也比较低。

They have a little downside and it is that, they don’t always guarantee the optimal solution, they will get a close approach to the optimal but not always find it. Anyway in many cases, a close-to-optimal solution is more than enough.
不过这个算法也有缺点,它不能保证每次都能找到最优解,有时候只能找到接近最优解的方案。不管怎样,在很多情况下,能找到接近最优解的方案已经绰绰有余了。
chaingangway marked this conversation as resolved.
Show resolved Hide resolved
chaingangway marked this conversation as resolved.
Show resolved Hide resolved

When talking about complexity, they typically take “**n”** iterations for an “**n”** sized problem so their complexities vary from O(n), O(n × log(n)) or as much as O(n²)
这个算法一般是对规模为 “**n**” 的问题迭代 “**n**” 次,所以它的复杂度可能是 O(n)O(n × log(n)),但是不会超过 O(n²)
chaingangway marked this conversation as resolved.
Show resolved Hide resolved

Most problems for which they produce very good results share a couple of characteristics:
这个算法能解决的大多数问题都有以下两个特性:

1. **Greedy property**: It is based on taking in every iteration, the optimal local solution without thinking about future consequences. We trust in that taking the optimal local solution could lead to the optimal global solution, but as I said before, that not always happens. To demonstrate that in every iteration we are taking the most optimal solution we need to use the induction method (clearly not a trivial demonstration).
2. **An optimal** substructure****: I kind of mentioned it before. The problem must have the capability of been divided into subsets with each having an optimal solution.
1. **贪心属性**:它的意思是每次迭代时都采用局部最优解,而无需考虑对全局的影响。我们相信通过不断求解局部最优解终会得到全局最优解,但是正如我之前所说,这个结论不一定成立。为了证明在每次迭代中都求得了最优解,我们需要使用归纳法(显然不是简单的证明)。
chaingangway marked this conversation as resolved.
Show resolved Hide resolved
2. **最优子结构**: 我之前提到过一些。求解的问题必须能划分为子问题,每个子问题都有最优解。

Now let me show you how to write your own greedy algorithm and then we will look at a very well known problem and solve it using our new greedy superpower.
本文中,我们将学习如何编写自己的贪心算法,然后用这个算法解决一个非常著名的难题。
chaingangway marked this conversation as resolved.
Show resolved Hide resolved

## General Greedy schema (Java)
## 贪心算法通用模版 (Java)

```Java
public ArrayList greedy(ArrayList candidates) {
Expand All @@ -43,41 +43,41 @@ public ArrayList greedy(ArrayList candidates) {
}
```

Before I explain the code, let’s first define some of the terminology I used in the pseudocode
我首先给出一些在伪代码中用到的术语的定义。
chaingangway marked this conversation as resolved.
Show resolved Hide resolved

1. **Candidates:** List of possible solutions to the problem. This can be any kind of data type, but usually an iterable one. You will see it better when we get to the example problem, bear with me for now 😁.
2. **Candidate:** The selected possible current solution to our problem
3. **Solution:** The first instance of the solution variable should simply be a data structure in which we will store our current solution to the problem.
4. **isSolution, candidatesLeft, removeCandidate, addCandidate, isGoodCandidate:** These are functions that we will also build, some of them, depending on the problem we are approaching, don’t even need to be whole functions but, for the shake of summarizing the schema, I decided to put them as functions.
1. **Candidates:** 所有可能的解集。它可以是任意的数据类型,但通常是可迭代的。在我们处理示例问题时,会加深对它的理解。现在请先记住结论 😁。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

【所有可能的解集。它可以是任意的数据类型,但通常是可迭代的。在我们处理示例问题时,会加深对它的理解。现在请先记住结论 😁。】=> 【该问题的可能解决方案列表。它可以是任意的数据类型,但通常是可迭代的。在我们处理示例问题时,你们会看得更清楚,现在先忍耐一下 😁。】

2. **Candidate:** 在解集中,我们当前选中的一个解。
3. **Solution:** 解变量的第一个实例只需是一种数据结构,在这里我们将存储当前的解。
4. **isSolution, candidatesLeft, removeCandidate, addCandidate, isGoodCandidate:** 这些也是我们要创建的方法,其中的某些方法在一些实际问题中不必是完整的,但是为了总结代码模版,我把它们全部定义为方法。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

【这些也是我们要创建的方法,其中的某些方法在一些实际问题中不必是完整的,但是为了总结代码模版,我把它们全部定义为方法。】=> 【这些也是我们要构建的函数,其中一些函数,根据我们要解决的问题,甚至不需要是完整的函数,但是,为了总结模式,我决定将它们作为函数。】


First we initialize our solution data structure, this could be an array, a boolean, an int… we simply need to state it.
首先,我们初始化解的数据结构,它可以是数组,布尔值,整数…… 我们只需要声明一下。

```
solution
```

Then we see this main **while** loop with a couple of functions inside. Those functions must also be build but sometimes you don’t need a whole other function to see for example if you have left candidates to try.
然后,我们看一下这个 while 循环,它的循环条件中有两个方法。这些方法必须编写,但有时并不需要完整的方法体,例如,判断是否有剩余备选解的这个方法。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

【循环条件】 => 【循环】


```js
while (!isSolution(solution) && (candidatesLeft(candidates))
```

Once we have checked that we didn’t yet find a solution and that we still have candidates left to try, we select one candidate and immediately remove it from our list of candidates.
当我们发现当前尚未找到解,并且有剩余备选解可以尝试时,我们将选择一个备选解,并立即将其从我们的备选解集中删除。

```js
cadidate = selectCandidate(candidates);
removeCandidate(candidate, candidates);
```

The next step is pretty straight forward. If the candidate is suitable for our solution, then simply add it to the solution structure.
下一步很简单。如果候选解是正确的解,则只需将其添加到解结构中。

```js
if (isGoodCandidate(candidate, solution)) {
addCandidate(candidate, solution);
}
```

Then we simply check if we have reached the solution state and finally return it
然后,我们只需检查问题是否已达到解决的状态,然后将解返回。

```js
if (isSolution(solution)) {
Expand All @@ -87,29 +87,29 @@ if (isSolution(solution)) {
}
```

OK! so once we have seen the code and broadly explained it, I will give you a problem and you should try and solve it yourself. It is a very well known problem so you will easily find it on the internet but I recommend giving it a try.
至此我们已经看完了代码并对其进行了粗略的解释,现在我给您出道题,请您尝试自己解答。这是一个众所周知的问题,在网上很容易就能搜到答案,但我建议您还是尝试自己解决。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

【至此】 => 【至此,】


---

## Coin change problem
## 零钱兑换的问题

You have 6 types of coins, and the value of each type is given as {50, 20, 10, 5, 2, 1} respectively, they are passed as an argument already sorted in decreasing value. **Each of the possible coins would be our candidates.** You must find a way of giving away the optimal change (**least amount of coins and the exact amount of change**)
有6种硬币,每种硬币的值分别为 {50,20,10,5,2,1},它们按递减排序作为参数传递。 **每种硬币都可能成为我们的候选解**。您必须找到一种最佳的兑换方式。(**用最少的硬币找零**)

**Example input:** 15 (**We must return a sum of 15 with the least amount of coins possible**)
**示例输入:** 15(**我们必须以最少的硬币数量凑齐 15 并返回硬币集合**)

**Example output:** 10, 5 (**We gave back a sum of 15 with the least amount of coins possible**)
**示例输出:** 10、5(**我们返回了和为 15 的硬币集合,且硬币数量最少**)

For this exact monetary system {50, 20, 10, 5, 2, 1} the algorithm should find an optimal solution but it is worth mentioning that any change in the available candidates, can result in the algorithm not giving an optimal solution.
在这个确定的硬币系统 {50,20,10,5,2,1} 中,该算法能找到最优解,但是请注意,如果候选解发生改变,可能会导致该算法无法找到最优解。

#### Hint
#### 提示

If you didn’t try hard enough, you shouldn’t be reading this 🤨… Just kidding, go ahead, I’m sure I̶ ̶h̶o̶p̶e̶ you already learned something new 😄
如果您没有足够努力尝试,就不应该看这一段内容 🤨…… 开个玩笑,继续吧,我确信~~我希望~~您已经学到了一些新知识 😄。

* A good **selectCandidate()** function is to start choosing big coins, and then filling the remaining change with smaller coins. Always check you are not surpassing the remaining change.
* **selectCandidate()** 方法中,首先选择面额最大的硬币,然后用较小的硬币填充剩余的零钱。在这个过程中,您要一直检查是否超出剩余的零钱。
chaingangway marked this conversation as resolved.
Show resolved Hide resolved

#### Solution
#### 解法
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

【解法】 => 【解决方案】


I will provide my solution written in java, so I’m using OOP.
我提供的解法用 Java 编写的,其中用到了面向对象的知识。

```Java
public class Coin {
Expand Down Expand Up @@ -158,17 +158,17 @@ ArrayList < Coin > greedySchema(ArrayList < Integer > values, int quantity) {
}
```

#### Resources
#### 资源

If you did like how Greedy algorithms work and now feel the urge to go and investigate more about them, pages like [Hackerrank](https://www.hackerrank.com/) or [Hackerearth](https://www.hackerearth.com/practice/) provide a huge amount of problems to solve, I’m sure you already knew about them but it is always good to mention 😊.
如果您喜欢贪心算法的工作原理,并且想深入研究,请访问 [Hackerrank](https://www.hackerrank.com/) 或者 [Hackerearth](https://www.hackerearth.com/practice/),这里有有很多要解决的问题,我相信您已经对它们有一定了解 😊。
chaingangway marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

【如果您喜欢贪心算法的工作原理,并且想深入研究,请访问 Hackerrank 或者 Hackerearth,这里有有很多要解决的问题,我相信您已经对它们有一定了解 😊。】 => 【如果您确实喜欢贪心算法的工作原理,现在又想去研究一下它们,请访问 Hackerrank 或者 Hackerearth,这里有很多要解决的问题,我相信你已经知道了它们 😊。】


Sometimes what I personally do is use GitHub as a search engine and simply write the topic I’m looking for [[greedy algorithms](https://github.com/search?q=greedy+algorithm)].
有时,我个人也会把 GitHub 作为搜索引擎,并简单地写下我寻找的主题 [[贪心算法](https://github.com/search?q=greedy+algorithm)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

【有时,我个人也会把 GitHub 作为搜索引擎,并简单地写下我寻找的主题 [贪心算法]。】 => 【有时,我个人也会使用 GitHub 作为搜索引擎,并简单地写下我要找的主题 [贪心算法]。】


## Conclusion
## 结论

So to sum up, Greedy Algorithms are really good even for personal easy projects, they should not take to much to think and they consume little resources. If that wasn’t enough, a lot of interview questions might be easily solved using a good Greedy algorithm, most of the times the memory and complexity requirements are satisfied using either Greedy or Dynamic Programming, but that’s another story 😉.
综上所述,即使对于简单的个人项目,贪心算法也能表现优异,它不需要你花费太多时间去思考,并且只消耗很少的资源。而且,使用贪心算法可以轻松解决很多面试问题。大多数时候,使用贪心或动态规划都可以满足内存和复杂度方面的要求,但这就是另一个话题了 😉。

Thanks for reading and feel free to comment out anything 😄.
感谢您的阅读,请多多评论哦 😄。
chaingangway marked this conversation as resolved.
Show resolved Hide resolved

> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。

Expand Down