From abace6072301a3f31037b266b879e0bc8eb3c557 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Wed, 8 May 2019 01:12:36 +0800 Subject: [PATCH 01/25] correct typos --- thinkings/basic-data-structure.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/thinkings/basic-data-structure.md b/thinkings/basic-data-structure.md index 0c4724a95..b7f277bbe 100644 --- a/thinkings/basic-data-structure.md +++ b/thinkings/basic-data-structure.md @@ -6,7 +6,8 @@ 本篇文章的定位是侧重于前端的,通过学习前端中实际场景的数据结构,从而加深大家对数据结构的理解和认识。 ## 线性结构 -数据结构我们可以从逻辑上分为线性结构和非线性结果。线性结构有 + +数据结构我们可以从逻辑上分为线性结构和非线性结构。线性结构有 数组,栈,链表等, 非线性结构有树,图等。 > 其实我们可以称树为一种半线性结构。 From f62deb81753e25c0a615152d7f55c441b76387b7 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Wed, 8 May 2019 01:12:45 +0800 Subject: [PATCH 02/25] Add translations --- thinkings/basic-data-structure-en.md | 320 +++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 thinkings/basic-data-structure-en.md diff --git a/thinkings/basic-data-structure-en.md b/thinkings/basic-data-structure-en.md new file mode 100644 index 000000000..54d9176cf --- /dev/null +++ b/thinkings/basic-data-structure-en.md @@ -0,0 +1,320 @@ +# Fundamental data structure + +This article is not going to intepret data structures, but help you to `review and understand` data structures and algorithms with real scenes. So, if you have a poor data structure foundation, you'd better to read some basic courses about data structures before reading this. + +This article is focused on frontend. We are expected to enhance your understanding to data structures from how data structures are implemented in frontend. + +## Linear structure + +Data structures can be divided into linear and non-linear structures logically. +The linear structure contains array, stack, linked list and so on. +The non-linear structure contains tree, graph and so on. + +> In fact, tree can be taken for a half-linear structure. + +It should be noted that, the linear and non-linear date structures do NOT mean that the data in those structure are stored in a linear or non-linear on the hard disk. It is just a logic partition. For example, binary tree can be stored in array. + +### Array + +Array is the simplest data structure and is used in so many places. For example, array is perfectly appropriate to store a data list. And in fact, you can find array behind many other data structures. + +The stack and queue structures which will be mentioned later can be regarded as a kind of BLOCKED array. You can find the detials in the corresponding sections. + +Now, let's have a look at some interesting examples. + +#### React Hooks + +`hooks` is essentially an array. + +![basic-data-structure-hooks.png](../assets/thinkings/basic-data-structure-hooks.png) + +So, why `hooks` uses array? Maybe we can find the answer from the other side. What if not array? + +```js + +function Form() { + // 1. Use the name state variable + const [name, setName] = useState('Mary'); + + // 2. Use an effect for persisting the form + useEffect(function persistForm() { + localStorage.setItem('formData', name); + }); + + // 3. Use the surname state variable + const [surname, setSurname] = useState('Poppins'); + + // 4. Use an effect for updating the title + useEffect(function updateTitle() { + document.title = name + ' ' + surname; + }); + + // ... +} +``` + +基于数组的方式,`Form`的hooks就是 [hook1, hook2, hook3, hook4], +我们可以得出这样的关系, hook1就是[name, setName] 这一对, +hook2就是persistForm这个。 + +如果不用数组实现,比如对象,Form的hooks就是 +```js +{ + 'key1': hook1, + 'key2': hook2, + 'key3': hook3, + 'key4': hook4, +} +``` +那么问题是key1,key2,key3,key4怎么取呢? + +关于React hooks 的本质研究,更多请查看[React hooks: not magic, just arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e) + +React 将`如何确保组件内部hooks保存的状态之间的对应关系`这个工作交给了 +开发人员去保证,即你必须保证HOOKS的顺序严格一致,具体可以看React 官网关于 Hooks Rule 部分。 + +### Queue + +Queue is a confining sequence. The elements in queue can only be removed from the head and only be added from the tail. + +> accoding to FIFO(fisrt-in-first-out) principle + +Queue is also a very common data structure with widely using. Like message queue. + +> The queue in data structure is just like the queue in daily life. + +In IT area, a queue is a specific ADT(abstract data type) or set. The entities in the set are stored in a certain sequence. + +There are twe basic operations of queue: + +- Adding entity to the tail, which is called enqueue. +- Removing entity from the head, which is called dequeue. + + +Explaining of FIFO: + +![basic-data-structure-queue](../assets/thinkings/basic-data-structure-queue.svg) + +(picture source: https://github.com/trekhleb/javascript-algorithms/blob/master/src/data-structures/queue/README.zh-CN.md) + +There is a problem, Head of Line Block (HOL), in HTTP/1.1. What is that? And how HTTP/2 solves the problem? + +In fact, the HOL are not only appearing in HTTP/1.1, but also in switcher. The key to this problem is queue structure. + +For the same TCP connection, all HTTP/1.0 requests will be add into a queue. Which means, the next request can be sent until the previous respond has been received. This block happens at the client side mostly. + +Just like waiting the traffic lights, +这就好像我们在等红绿灯,即使旁边绿灯亮了,你的这个车道是红灯,你还是不能走,还是要等着。 + +![basic-data-structure-queue-1](../assets/thinkings/basic-data-structure-queue-1.png) + +对于同一个tcp连接,http1.1允许一次发送多个http1.1请求,也就是说,不必等前一个响应收到,就可以发送下一个请求,这样就解决了http1.0的客户端的队头阻塞。 +但是,`http1.1规定,服务器端的响应的发送要根据请求被接收的顺序排队`,也就是说, +先接收到的请求的响应也要先发送。这样造成的问题是,如果最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队头阻塞。 +可见,http1.1的队首阻塞发生在服务器端。 + +如果用图来表示的话,过程大概是: + +![basic-data-structure-queue-2](../assets/thinkings/basic-data-structure-queue-2.png) + +### 栈 +栈也是一种受限的序列,它只能够操作栈顶,不管入栈还是出栈,都是在栈顶操作。 + +在计算机科学中, 一个 栈(stack) 是一种抽象数据类型,用作表示元素的集合,具有两种主要操作: + +push, 添加元素到栈的顶端(末尾); +pop, 移除栈最顶端(末尾)的元素. +以上两种操作可以简单概括为“后进先出(LIFO = last in, first out)”。 + +此外,应有一个 peek 操作用于访问栈当前顶端(末尾)的元素。(只返回不弹出) + +> "栈"这个名称,可类比于一组物体的堆叠(一摞书,一摞盘子之类的)。 + +栈的 push 和 pop 操作的示意: + +![basic-data-structure-stack](../assets/thinkings/basic-data-structure-stack.png) + +(图片来自 https://github.com/trekhleb/javascript-algorithms/blob/master/src/data-structures/stack/README.zh-CN.md) + + +栈在很多地方都有着应用,比如大家熟悉的浏览器就有很多栈,其实浏览器的执行栈就是一个基本的栈结构,从数据结构上说,它就是一个栈。 +这也就解释了,我们用递归的解法和用循环+栈的解法本质上是差不多。 + + + +比如如下JS代码: + +```js +function bar() { + const a = 1 + const b = 2; + console.log(a, b) +} +function foo() { + const a = 1; + bar(); +} + +foo(); + + +``` + +真正执行的时候,内部大概是这样的: + +![basic-data-structure-call-stack](../assets/thinkings/basic-data-structure-call-stack.png) + +> 我画的图没有画出执行上下文中其他部分(this和scope等), 这部分是闭包的关键,而我这里不是将闭包的,是为了讲解栈的。 + +> 社区中有很多“执行上下文中的scope指的是执行栈中父级声明的变量”说法,这是完全错误的, JS是词法作用域,scope指的是函数定义时候的父级,和执行没关系 + + +栈常见的应用有进制转换,括号匹配,栈混洗,中缀表达式(用的很少),后缀表达式(逆波兰表达式)等。 + +> 合法的栈混洗操作,其实和合法的括号匹配表达式之间存在着一一对应的关系, +也就是说n个元素的栈混洗有多少种,n对括号的合法表达式就有多少种。感兴趣的可以查找相关资料 +### 链表 + +链表是一种最基本数据结构,熟练掌握链表的结构和常见操作是基础中的基础。 + +![basic-data-structure-link-list](../assets/thinkings/basic-data-structure-link-list.svg) + +(图片来自: https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/linked-list/traversal) + +#### React Fiber + +很多人都说 fiber 是基于链表实现的,但是为什么要基于链表呢,可能很多人并没有答案,那么我觉得可以把这两个点(fiber 和链表)放到一起来讲下。 + +fiber 出现的目的其实是为了解决 react 在执行的时候是无法停下来的,需要一口气执行完的问题的。 + +![fiber-intro](../assets/thinkings/basic-data-structure-fiber-intro.png) + +图片来自 Lin Clark 在 ReactConf 2017 分享 + +上面已经指出了引入 fiber 之前的问题,就是 react 会阻止优先级高的代码(比如用户输入)执行。因此 fiber +打算自己自建一个`虚拟执行栈`来解决这个问题,这个虚拟执行栈的实现是链表。 + +Fiber 的基本原理是将协调过程分成小块,一次执行一块,然乎将运算结果保存起来,并判断是否有时间(react 自己实现了一个类似 requestIdleCallback 的功能)继续执行下一块。 +如果有时间,则继续。 否则跳出,让浏览器主线程歇一会,执行别的优先级高的代码。 + +当协调过程完成(所有的小块都运算完毕), 那么就会进入提交阶段, 真正的进行副作用(side effect)操作,比如更新DOM,这个过程是没有办法取消的,原因就是这部分有副作用。 + +问题的关键就是将协调的过程划分为一块块的,最后还可以合并到一起,有点像Map/Reduce。 + +React 必须重新实现遍历树的算法,从依赖于`内置堆栈的同步递归模型`,变为`具有链表和指针的异步模型`。 + +> Andrew 是这么说的: 如果你只依赖于[内置]调用堆栈,它将继续工作直到堆栈为空。。。 + +如果我们可以随意中断调用堆栈并手动操作堆栈帧,那不是很好吗? +这就是 React Fiber 的目的。 `Fiber 是堆栈的重新实现,专门用于 React 组件`。 你可以将单个 Fiber 视为一个`虚拟堆栈帧`。 + +react fiber 大概是这样的: + +```js +let fiber = { + tag: HOST_COMPONENT, + type: "div", + return: parentFiber, + children: childFiber, + sibling: childFiber, + alternate: currentFiber, + stateNode: document.createElement("div"), + props: { children: [], className: "foo"}, + partialState: null, + effectTag: PLACEMENT, + effects: [] +}; + +``` + +从这里可以看出fiber本质上是个对象,使用parent,child,sibling属性去构建fiber树来表示组件的结构树, +return, children, sibling也都是一个fiber,因此fiber看起来就是一个链表。 + +> 细心的朋友可能已经发现了, alternate也是一个fiber, 那么它是用来做什么的呢? +它其实原理有点像git, 可以用来执行git revert ,git commit等操作,这部分挺有意思,我会在我的《从零开发git》中讲解 + +想要了解更多的朋友可以看[这个文章](https://github.com/dawn-plex/translate/blob/master/articles/the-how-and-why-on-reacts-usage-of-linked-list-in-fiber-to-walk-the-components-tree.md) + +如果可以翻墙, 可以看[英文原文](https://medium.com/react-in-depth/the-how-and-why-on-reacts-usage-of-linked-list-in-fiber-67f1014d0eb7) + +[这篇文章](https://engineering.hexacta.com/didact-fiber-incremental-reconciliation-b2fe028dcaec)也是早期讲述fiber架构的优秀文章 + +我目前也在写关于《从零开发react系列教程》中关于fiber架构的部分,如果你对具体实现感兴趣,欢迎关注。 +### 非线性结构 + +那么有了线性结果,我们为什么还需要非线性结果呢? 答案是为了高效地兼顾静态操作和动态操作。 +大家可以对照各种数据结构的各种操作的复杂度来直观感受一下。 +## 树 +树的应用同样非常广泛,小到文件系统,大到因特网,组织架构等都可以表示为树结构, +而在我们前端眼中比较熟悉的DOM树也是一种树结构,而HTML作为一种DSL去描述这种树结构的具体表现形式。 + +树其实是一种特殊的`图`,是一种无环连通图,是一种极大无环图,也是一种极小连通图。 + +从另一个角度看,树是一种递归的数据结构。而且树的不同表示方法,比如不常用的`长子 + 兄弟`法,对于 +你理解树这种数据结构有着很大用处, 说是一种对树的本质的更深刻的理解也不为过。 + +树的基本算法有前中后序遍历和层次遍历,有的同学对前中后这三个分别具体表现的访问顺序比较模糊, +其实当初我也是一样的,后面我学到了一点,你只需要记住:`所谓的前中后指的是根节点的位置,其他位置按照先左后右排列即可`。 +比如前序遍历就是`根左右`, 中序就是`左根右`,后序就是`左右根`, 很简单吧? + +我刚才提到了树是一种递归的数据结构,因此树的遍历算法使用递归去完成非常简单, +幸运的是树的算法基本上都要依赖于树的遍历。 但是递归在计算机中的性能一直都有问题, +因此掌握不那么容易理解的"命令式地迭代"遍历算法在某些情况下是有用的。 + +如果你使用迭代式方式去遍历的话,可以借助上面提到的`栈`来进行,可以极大减少代码量。 + +> 如果使用栈来简化运算,由于栈是FILO的,因此一定要注意左右子树的推入顺序。 + +树的重要性质: + +- 如果树有n个顶点,那么其就有n - 1条边,这说明了树的顶点数和边数是同阶的。 +- 任何一个节点到根节点存在`唯一`路径, 路径的长度为节点所处的深度 + + + +### 二叉树 + +二叉树是节点度数不超过二的树,是树的一种特殊子集,有趣的是二叉树这种被限制的树结构却能够表示和实现所有的树, +它背后的原理正是`长子 + 兄弟`法,用邓老师的话说就是`二叉树是多叉树的特例,但在有根且有序时,其描述能力却足以覆盖后者`。 + +> 实际上, 在你使用`长子 + 兄弟`法表示树的同时,进行45度角旋转即可。 + +相关算法: + +- [94.binary-tree-inorder-traversal](../problems/94.binary-tree-inorder-traversal.md) +- [102.binary-tree-level-order-traversal](../problems/102.binary-tree-level-order-traversal.md) +- [103.binary-tree-zigzag-level-order-traversal](../problems/103.binary-tree-zigzag-level-order-traversal.md) +- [144.binary-tree-preorder-traversal](../problems/144.binary-tree-preorder-traversal.md) +- [145.binary-tree-postorder-traversal](../problems/145.binary-tree-postorder-traversal.md) +- [199.binary-tree-right-side-view](../problems/199.binary-tree-right-side-view.md) + +相关概念: + +- 真二叉树 (所有节点的度数只能是偶数,即只能为0或者2) + + +另外我也专门开设了[二叉树的遍历](./binary-tree-traversal.md)章节, 具体细节和算法可以去那里查看。 +#### 堆 + +堆其实是一种优先级队列,在很多语言都有对应的内置数据结构,很遗憾javascript没有这种原生的数据结构。 +不过这对我们理解和运用不会有影响。 + +相关算法: + +- [295.find-median-from-data-stream](../problems/295.find-median-from-data-stream.md) +#### 二叉查找树 + +### 平衡树 + +database engine + +#### AVL + +#### 红黑树 + +### 字典树(前缀树) + +相关算法: + +- [208.implement-trie-prefix-tree](../problems/208.implement-trie-prefix-tree.md) +## 图 From 7d5f538d2f9882399d9ab7440a06bf2ce3a5d8c5 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Fri, 10 May 2019 17:28:48 +0800 Subject: [PATCH 03/25] =?UTF-8?q?=E6=96=B0=E5=A2=9EHTTP/1.0,=20HTTP/1.1?= =?UTF-8?q?=EF=BC=8C=20HTTP/2=E7=9A=84=E5=AF=B9=E6=AF=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- thinkings/basic-data-structure.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/thinkings/basic-data-structure.md b/thinkings/basic-data-structure.md index b7f277bbe..53a6d10cd 100644 --- a/thinkings/basic-data-structure.md +++ b/thinkings/basic-data-structure.md @@ -104,16 +104,24 @@ React 将`如何确保组件内部hooks保存的状态之间的对应关系`这 ![basic-data-structure-queue-1](../assets/thinkings/basic-data-structure-queue-1.png) -对于同一个tcp连接,http1.1允许一次发送多个http1.1请求,也就是说,不必等前一个响应收到,就可以发送下一个请求,这样就解决了http1.0的客户端的队头阻塞。 -但是,`http1.1规定,服务器端的响应的发送要根据请求被接收的顺序排队`,也就是说, -先接收到的请求的响应也要先发送。这样造成的问题是,如果最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队头阻塞。 +`HTTP/1.0` 和 `HTTP/1.1`: +在`HTTP/1.0` 中每一次请求都需要建立一个TCP连接,请求结束后立即断开连接。而且下一个包必须在收到前一个包的ACK之后才能发送。 +在`HTTP/1.1` 中,每一个连接都默认是长连接(persistent connection)。对于同一个tcp连接,允许一次发送多个http1.1请求,也就是说,不必等前一个响应收到,就可以发送下一个请求。这样就解决了http1.0的客户端的队头阻塞,而这也就是`HTTP/1.1`中`管道(Pipeline)`的概念了。 +但是,`http1.1规定,服务器端的响应的发送要根据请求被接收的顺序排队`,也就是说,先接收到的请求的响应也要先发送。这样造成的问题是,如果最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队头阻塞。 可见,http1.1的队首阻塞发生在服务器端。 如果用图来表示的话,过程大概是: ![basic-data-structure-queue-2](../assets/thinkings/basic-data-structure-queue-2.png) +`HTTP/2` 和 `HTTP/1.1`: + +为了解决`HTTP/1.1`中的服务端队首阻塞,`HTTP/2`采用了`二进制分帧` 和 `多路复用` 等方法。 +`二进制分帧`中,帧是`HTTP/2`数据通信的最小单位。在`HTTP/1.1`数据包是文本格式,而`HTTP/2`的数据包是二进制格式的,也就是二进制帧。采用帧可以将请求和响应的数据分割得更小,且二进制协议可以更高效解析。`HTTP/2`中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。 +`多路复用`用以替代原来的序列和拥塞机制。在`HTTP/1.1`中,并发多个请求需要多个TCP链接,且单个域名有6-8个TCP链接请求限制。在`HHTP/2`中,同一域名下的所有通信在单个链接完成,仅占用一个TCP链接,且在这一个链接上可以并行请求和响应,互不干扰。 + ### 栈 + 栈也是一种受限的序列,它只能够操作栈顶,不管入栈还是出栈,都是在栈顶操作。 在计算机科学中, 一个 栈(stack) 是一种抽象数据类型,用作表示元素的集合,具有两种主要操作: @@ -236,11 +244,11 @@ return, children, sibling也都是一个fiber,因此fiber看起来就是一个 [这篇文章](https://engineering.hexacta.com/didact-fiber-incremental-reconciliation-b2fe028dcaec)也是早期讲述fiber架构的优秀文章 我目前也在写关于《从零开发react系列教程》中关于fiber架构的部分,如果你对具体实现感兴趣,欢迎关注。 -### 非线性结构 +## 非线性结构 -那么有了线性结果,我们为什么还需要非线性结果呢? 答案是为了高效地兼顾静态操作和动态操作。 +那么有了线性结构,我们为什么还需要非线性结构呢? 答案是为了高效地兼顾静态操作和动态操作。 大家可以对照各种数据结构的各种操作的复杂度来直观感受一下。 -## 树 +### 树 树的应用同样非常广泛,小到文件系统,大到因特网,组织架构等都可以表示为树结构, 而在我们前端眼中比较熟悉的DOM树也是一种树结构,而HTML作为一种DSL去描述这种树结构的具体表现形式。 From 978f0e62b3be3bbde782de9839df1223fc2b1e2d Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Fri, 10 May 2019 17:37:47 +0800 Subject: [PATCH 04/25] =?UTF-8?q?=E5=A2=9E=E5=8A=A0HTTP/1.1=E5=92=8CHTTP/2?= =?UTF-8?q?=E7=9A=84=E6=80=A7=E8=83=BD=E5=AF=B9=E6=AF=94=E7=9A=84Demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- thinkings/basic-data-structure.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/thinkings/basic-data-structure.md b/thinkings/basic-data-structure.md index 53a6d10cd..8f7ed5972 100644 --- a/thinkings/basic-data-structure.md +++ b/thinkings/basic-data-structure.md @@ -120,6 +120,8 @@ React 将`如何确保组件内部hooks保存的状态之间的对应关系`这 `二进制分帧`中,帧是`HTTP/2`数据通信的最小单位。在`HTTP/1.1`数据包是文本格式,而`HTTP/2`的数据包是二进制格式的,也就是二进制帧。采用帧可以将请求和响应的数据分割得更小,且二进制协议可以更高效解析。`HTTP/2`中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。 `多路复用`用以替代原来的序列和拥塞机制。在`HTTP/1.1`中,并发多个请求需要多个TCP链接,且单个域名有6-8个TCP链接请求限制。在`HHTP/2`中,同一域名下的所有通信在单个链接完成,仅占用一个TCP链接,且在这一个链接上可以并行请求和响应,互不干扰。 +> [此网站](https://http2.akamai.com/demo)可以直观感受`HTTP/1.1`和`HTTP/2`的性能对比。 + ### 栈 栈也是一种受限的序列,它只能够操作栈顶,不管入栈还是出栈,都是在栈顶操作。 From badd1b14c89f36a1a5159b50a350691bb9765877 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Fri, 10 May 2019 19:35:38 +0800 Subject: [PATCH 05/25] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E5=A4=A7=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=9F=BA=E7=A1=80=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84?= =?UTF-8?q?=EF=BC=8C=E4=BD=86=E6=98=AFREACT=E9=83=A8=E5=88=86=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- thinkings/basic-data-structure-en.md | 152 ++++++++++++++------------- 1 file changed, 80 insertions(+), 72 deletions(-) diff --git a/thinkings/basic-data-structure-en.md b/thinkings/basic-data-structure-en.md index 54d9176cf..74bca234d 100644 --- a/thinkings/basic-data-structure-en.md +++ b/thinkings/basic-data-structure-en.md @@ -90,7 +90,6 @@ There are twe basic operations of queue: - Adding entity to the tail, which is called enqueue. - Removing entity from the head, which is called dequeue. - Explaining of FIFO: ![basic-data-structure-queue](../assets/thinkings/basic-data-structure-queue.svg) @@ -103,46 +102,47 @@ In fact, the HOL are not only appearing in HTTP/1.1, but also in switcher. The k For the same TCP connection, all HTTP/1.0 requests will be add into a queue. Which means, the next request can be sent until the previous respond has been received. This block happens at the client side mostly. -Just like waiting the traffic lights, -这就好像我们在等红绿灯,即使旁边绿灯亮了,你的这个车道是红灯,你还是不能走,还是要等着。 +Just like waiting the traffic lights, if you are on the left-turn or right-turning lane, you cannot move even if the straight lane is good to go when the left/right turning light is still red. ![basic-data-structure-queue-1](../assets/thinkings/basic-data-structure-queue-1.png) -对于同一个tcp连接,http1.1允许一次发送多个http1.1请求,也就是说,不必等前一个响应收到,就可以发送下一个请求,这样就解决了http1.0的客户端的队头阻塞。 -但是,`http1.1规定,服务器端的响应的发送要根据请求被接收的顺序排队`,也就是说, -先接收到的请求的响应也要先发送。这样造成的问题是,如果最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队头阻塞。 -可见,http1.1的队首阻塞发生在服务器端。 +Talking about the difference or the same TCP connection, HTTP/1.1 allows send multiple HTTP/1.1 requests at the same time. In another word, +`HTTP/1.0` and `HTTP/1.1`: +Accoding to `HTTP/1.0` protocal, one TCP connect will be established for each request and be terminated immediately after receiving the corresponding response. And the next HTTP request cannot be sent until the response of previous request has been received. +According to `HTTP/1.1`, each connection is persistent connection by default. For the same TCP connection, it is allowed to send multiple `HTTP/1.1` request at the same time. In other words, it is unnecessary to send the next request after receiving the response of the previous one. This is the solution to the HOL bloking of `HTTP/1.0`. And, this is called `pipeline` in `HTTP/1.1`. +However, according to `HTTP/1.1`, all the responses are reqired to be sent back to client or brower in the sequence of that being received. In other words, one request received in front should be responded in front. The HOL blocking will happend when one request in front takes a long processing time. All later request have to wait for it. So, the HOL blocking of `HTTP/1.1` happends at the server side. -如果用图来表示的话,过程大概是: +The process can be represented as follow: ![basic-data-structure-queue-2](../assets/thinkings/basic-data-structure-queue-2.png) -### 栈 -栈也是一种受限的序列,它只能够操作栈顶,不管入栈还是出栈,都是在栈顶操作。 +### Stack -在计算机科学中, 一个 栈(stack) 是一种抽象数据类型,用作表示元素的集合,具有两种主要操作: +Stack is a kind of blocked sequence. It only supports to add or remove element at the **top** of stack. -push, 添加元素到栈的顶端(末尾); -pop, 移除栈最顶端(末尾)的元素. -以上两种操作可以简单概括为“后进先出(LIFO = last in, first out)”。 +In IT area, a stack is an ADT (abstract data type) for representing a set of elements. -此外,应有一个 peek 操作用于访问栈当前顶端(末尾)的元素。(只返回不弹出) +There are basic operations of stack: -> "栈"这个名称,可类比于一组物体的堆叠(一摞书,一摞盘子之类的)。 +- Adding element at the top (tail), which called `push` +- Removing the element at the top (tail), which called `pop` -栈的 push 和 pop 操作的示意: +The two operations can be summarized as LIFO (last-in-first-out) or FILO (first-in-last-out) -![basic-data-structure-stack](../assets/thinkings/basic-data-structure-stack.png) +Besides, there is usually an operation called `peek` which is used to retrieve the first element of the stack or the element present at the top of the stack. Compared with `pop`, the `peek` operation won't remove the retrieved element from the stack. -(图片来自 https://github.com/trekhleb/javascript-algorithms/blob/master/src/data-structures/stack/README.zh-CN.md) +> Stack can be regarded as a pile of books or dishes. +Explaining of `push` and `pop` operations: -栈在很多地方都有着应用,比如大家熟悉的浏览器就有很多栈,其实浏览器的执行栈就是一个基本的栈结构,从数据结构上说,它就是一个栈。 -这也就解释了,我们用递归的解法和用循环+栈的解法本质上是差不多。 +![basic-data-structure-stack](../assets/thinkings/basic-data-structure-stack.png) +(Picture from: https://github.com/trekhleb/javascript-algorithms/blob/master/src/data-structures/stack/README.zh-CN.md) +Stack has been used in many places and areas. For example, in browser, the Execution Stack is a basic stack structure. +So, the recursion and loop+stack are essentially the same thing. -比如如下JS代码: +For example: ```js function bar() { @@ -160,31 +160,31 @@ foo(); ``` -真正执行的时候,内部大概是这样的: +It may look like this inside the program during executing: ![basic-data-structure-call-stack](../assets/thinkings/basic-data-structure-call-stack.png) -> 我画的图没有画出执行上下文中其他部分(this和scope等), 这部分是闭包的关键,而我这里不是将闭包的,是为了讲解栈的。 - -> 社区中有很多“执行上下文中的scope指的是执行栈中父级声明的变量”说法,这是完全错误的, JS是词法作用域,scope指的是函数定义时候的父级,和执行没关系 +> The figure above does not contains the other parts of the execution context, like `this` and `scope` which are the key to closure. Here is not going to talk about the closure but to explain the stack structure. +> Some statements in community like *the `scope` of execution context is the variables which declared by the super class in execution stack* which are completely wrong. JS uses Lexical Scoping. And `scope` is the parent object of function when it is defined. There is nothing to do with the execution. +The common use of stack including Base Conversion, bracket matching, stack shuffling, Infix Expression and Postfix Expression, etc. -栈常见的应用有进制转换,括号匹配,栈混洗,中缀表达式(用的很少),后缀表达式(逆波兰表达式)等。 +> There is a correspongding relationship between legal stack shuffling operations and legal bracket matching expressions. +> In another word, the number of conditions of Stack Shuffling with `n` elements equals the number of conditions of legal expressions of `n` pairs of brackets. -> 合法的栈混洗操作,其实和合法的括号匹配表达式之间存在着一一对应的关系, -也就是说n个元素的栈混洗有多少种,n对括号的合法表达式就有多少种。感兴趣的可以查找相关资料 -### 链表 +### Linked List -链表是一种最基本数据结构,熟练掌握链表的结构和常见操作是基础中的基础。 +Linked List is the most basic data structure. So, it is quit important to make yourself master of understanding and using Linked List. ![basic-data-structure-link-list](../assets/thinkings/basic-data-structure-link-list.svg) -(图片来自: https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/linked-list/traversal) +(Picture from: https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/linked-list/traversal) #### React Fiber -很多人都说 fiber 是基于链表实现的,但是为什么要基于链表呢,可能很多人并没有答案,那么我觉得可以把这两个点(fiber 和链表)放到一起来讲下。 +Many people know that `fiber` is implemented on Linked List. But not many of them know the reason. So, let's have a look at the relationship between `fiber` and Linked list. +The appearance of `fiber` solves the problem that `react` must fiber 出现的目的其实是为了解决 react 在执行的时候是无法停下来的,需要一口气执行完的问题的。 ![fiber-intro](../assets/thinkings/basic-data-structure-fiber-intro.png) @@ -240,46 +240,53 @@ return, children, sibling也都是一个fiber,因此fiber看起来就是一个 [这篇文章](https://engineering.hexacta.com/didact-fiber-incremental-reconciliation-b2fe028dcaec)也是早期讲述fiber架构的优秀文章 我目前也在写关于《从零开发react系列教程》中关于fiber架构的部分,如果你对具体实现感兴趣,欢迎关注。 -### 非线性结构 -那么有了线性结果,我们为什么还需要非线性结果呢? 答案是为了高效地兼顾静态操作和动态操作。 -大家可以对照各种数据结构的各种操作的复杂度来直观感受一下。 -## 树 -树的应用同样非常广泛,小到文件系统,大到因特网,组织架构等都可以表示为树结构, -而在我们前端眼中比较熟悉的DOM树也是一种树结构,而HTML作为一种DSL去描述这种树结构的具体表现形式。 +## Non-linear Structure -树其实是一种特殊的`图`,是一种无环连通图,是一种极大无环图,也是一种极小连通图。 +The reason that we need non-linear structures is satisfying both of static operations and dynamic operations. -从另一个角度看,树是一种递归的数据结构。而且树的不同表示方法,比如不常用的`长子 + 兄弟`法,对于 -你理解树这种数据结构有着很大用处, 说是一种对树的本质的更深刻的理解也不为过。 +### Tree -树的基本算法有前中后序遍历和层次遍历,有的同学对前中后这三个分别具体表现的访问顺序比较模糊, -其实当初我也是一样的,后面我学到了一点,你只需要记住:`所谓的前中后指的是根节点的位置,其他位置按照先左后右排列即可`。 -比如前序遍历就是`根左右`, 中序就是`左根右`,后序就是`左右根`, 很简单吧? +The Tree structure is also used widely. From file system to the Internet, the organizational structure of many of them can be represented as tree structure. +The DOM (document object model) in frontend is also a tree structure. And `HTML` is a implementation of DSL (domain specific language) to describe this tree structure. -我刚才提到了树是一种递归的数据结构,因此树的遍历算法使用递归去完成非常简单, -幸运的是树的算法基本上都要依赖于树的遍历。 但是递归在计算机中的性能一直都有问题, -因此掌握不那么容易理解的"命令式地迭代"遍历算法在某些情况下是有用的。 +In fact, Tree is one kind of graph. It is an acyclic connected graph, a maximal acyclic graph and a minimal connected graph. -如果你使用迭代式方式去遍历的话,可以借助上面提到的`栈`来进行,可以极大减少代码量。 +From another prespective, Tree is a recursive data structure. [Left-Child Right-Sibling Representation of Tree](https://www.geeksforgeeks.org/left-child-right-sibling-representation-tree/) can be used to help to understand the structure of Tree. -> 如果使用栈来简化运算,由于栈是FILO的,因此一定要注意左右子树的推入顺序。 +The basic operations of Tree including preoder, inorder, postoder and hierarchical traversals. +It is very easy to distinguish preorder, inorder and postorder traversals: + +- the preorder, inorder and postorder refer to the position of root during traversal. +- the two children nodes are always traversed from left to right. +- preorder: `root` -> `left child` -> `right child` (recursive). +- inorder: `left child` -> `root` -> `right child` (recursive). +- postorder: `left child` -> `right child` -> `root` (recursive) -树的重要性质: +Because Tree is a recursive data structure, it is very easy to complete tree traversal using recursion. +Basically, the algorithms of Tree are all based on the tree traversal. But the performance of recursion is always a problem. +So, it may be helpful with understanding and using *imperative iteration* traversal algorithms. -- 如果树有n个顶点,那么其就有n - 1条边,这说明了树的顶点数和边数是同阶的。 -- 任何一个节点到根节点存在`唯一`路径, 路径的长度为节点所处的深度 +Stack can be used to implement the iterative traversal with using less code. +> If stack is used, make sure that the left and right children are pushed into stack in correct sequence. +Important properties of Tree: -### 二叉树 +- If a tree has `n` vertex, then it has `n-1` edges. +- There is only one path between any node and the root node. The length of this path is called the depth of the node. -二叉树是节点度数不超过二的树,是树的一种特殊子集,有趣的是二叉树这种被限制的树结构却能够表示和实现所有的树, -它背后的原理正是`长子 + 兄弟`法,用邓老师的话说就是`二叉树是多叉树的特例,但在有根且有序时,其描述能力却足以覆盖后者`。 +### Binary Tree -> 实际上, 在你使用`长子 + 兄弟`法表示树的同时,进行45度角旋转即可。 +Binary tree is the tree that the degree of each node is not more than 2. It is a special subset of tree. +It is interesting that the binary tree which is a kind of limited tree can be used to represent and implemented all tree structures. +The principle behind Binary Tree is the `Left-Child Right-Sibling Representation of Tree`. -相关算法: +> Binary Tree is a paticular case of multiple-way tree. But when Binary Tree has root and is ordered, it can be used to describe the latter. +> +> In fact, just rotating the tree 45 degrees, you can get a tree represented by `Left-Child Right-Sibling` + +Related algorithms: - [94.binary-tree-inorder-traversal](../problems/94.binary-tree-inorder-traversal.md) - [102.binary-tree-level-order-traversal](../problems/102.binary-tree-level-order-traversal.md) @@ -288,33 +295,34 @@ return, children, sibling也都是一个fiber,因此fiber看起来就是一个 - [145.binary-tree-postorder-traversal](../problems/145.binary-tree-postorder-traversal.md) - [199.binary-tree-right-side-view](../problems/199.binary-tree-right-side-view.md) -相关概念: +Related concepts: -- 真二叉树 (所有节点的度数只能是偶数,即只能为0或者2) +- Proper Binary Tree (all node degrees can only be even, that is 0 or 2) +BTW, you can find more details and algorithms in the charpter [binary tree traversal](./binary-tree-traversal.md) -另外我也专门开设了[二叉树的遍历](./binary-tree-traversal.md)章节, 具体细节和算法可以去那里查看。 -#### 堆 +#### Heap -堆其实是一种优先级队列,在很多语言都有对应的内置数据结构,很遗憾javascript没有这种原生的数据结构。 -不过这对我们理解和运用不会有影响。 +Heap is a kind of priority queue which is built in many data structure. But unfortunately, JS does not have a native implementation of this data structure. However, it won't be a problem for understanding and using this structure. -相关算法: +Related algorithm: - [295.find-median-from-data-stream](../problems/295.find-median-from-data-stream.md) -#### 二叉查找树 -### 平衡树 +#### Binary Search Tree + +### Balanced Tree database engine -#### AVL +#### AVL Tree -#### 红黑树 +#### Red-Black Tree -### 字典树(前缀树) +### Trie(Prefix Tree) -相关算法: +Related algorithm: - [208.implement-trie-prefix-tree](../problems/208.implement-trie-prefix-tree.md) -## 图 + +### Graph From 45c53b5d115b34013e7fed8869fe5d46b515fec4 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Wed, 29 May 2019 14:09:05 +0800 Subject: [PATCH 06/25] update description of `HTTP/1.0` --- thinkings/basic-data-structure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thinkings/basic-data-structure.md b/thinkings/basic-data-structure.md index 8f7ed5972..748bd76fa 100644 --- a/thinkings/basic-data-structure.md +++ b/thinkings/basic-data-structure.md @@ -105,7 +105,7 @@ React 将`如何确保组件内部hooks保存的状态之间的对应关系`这 ![basic-data-structure-queue-1](../assets/thinkings/basic-data-structure-queue-1.png) `HTTP/1.0` 和 `HTTP/1.1`: -在`HTTP/1.0` 中每一次请求都需要建立一个TCP连接,请求结束后立即断开连接。而且下一个包必须在收到前一个包的ACK之后才能发送。 +在`HTTP/1.0` 中每一次请求都需要建立一个TCP连接,请求结束后立即断开连接。而且下一个包必须在收到前一个包的响应之后才能发送。 在`HTTP/1.1` 中,每一个连接都默认是长连接(persistent connection)。对于同一个tcp连接,允许一次发送多个http1.1请求,也就是说,不必等前一个响应收到,就可以发送下一个请求。这样就解决了http1.0的客户端的队头阻塞,而这也就是`HTTP/1.1`中`管道(Pipeline)`的概念了。 但是,`http1.1规定,服务器端的响应的发送要根据请求被接收的顺序排队`,也就是说,先接收到的请求的响应也要先发送。这样造成的问题是,如果最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队头阻塞。 可见,http1.1的队首阻塞发生在服务器端。 From 53bd464ce38c7e191b55834eb81489a5109cfa13 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Wed, 29 May 2019 14:14:35 +0800 Subject: [PATCH 07/25] add WIP tag, update some translation details --- thinkings/basic-data-structure-en.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/thinkings/basic-data-structure-en.md b/thinkings/basic-data-structure-en.md index 74bca234d..a619629e1 100644 --- a/thinkings/basic-data-structure-en.md +++ b/thinkings/basic-data-structure-en.md @@ -1,5 +1,7 @@ # Fundamental data structure +> WIP: the translation of `fundamental data structure` is on the way. + This article is not going to intepret data structures, but help you to `review and understand` data structures and algorithms with real scenes. So, if you have a poor data structure foundation, you'd better to read some basic courses about data structures before reading this. This article is focused on frontend. We are expected to enhance your understanding to data structures from how data structures are implemented in frontend. @@ -18,7 +20,7 @@ It should be noted that, the linear and non-linear date structures do NOT mean t Array is the simplest data structure and is used in so many places. For example, array is perfectly appropriate to store a data list. And in fact, you can find array behind many other data structures. -The stack and queue structures which will be mentioned later can be regarded as a kind of BLOCKED array. You can find the detials in the corresponding sections. +The stack and queue structures which will be mentioned later can be regarded as a kind of LIMITED array. You can find the detials in the corresponding sections. Now, let's have a look at some interesting examples. @@ -75,11 +77,11 @@ React 将`如何确保组件内部hooks保存的状态之间的对应关系`这 ### Queue -Queue is a confining sequence. The elements in queue can only be removed from the head and only be added from the tail. +Queue is a limited sequence. The elements in queue can only be removed from the head and only be added from the tail. > accoding to FIFO(fisrt-in-first-out) principle -Queue is also a very common data structure with widely using. Like message queue. +Queue is also a very common data structure with widespread application. Like message queue. > The queue in data structure is just like the queue in daily life. @@ -106,7 +108,6 @@ Just like waiting the traffic lights, if you are on the left-turn or right-turni ![basic-data-structure-queue-1](../assets/thinkings/basic-data-structure-queue-1.png) -Talking about the difference or the same TCP connection, HTTP/1.1 allows send multiple HTTP/1.1 requests at the same time. In another word, `HTTP/1.0` and `HTTP/1.1`: Accoding to `HTTP/1.0` protocal, one TCP connect will be established for each request and be terminated immediately after receiving the corresponding response. And the next HTTP request cannot be sent until the response of previous request has been received. According to `HTTP/1.1`, each connection is persistent connection by default. For the same TCP connection, it is allowed to send multiple `HTTP/1.1` request at the same time. In other words, it is unnecessary to send the next request after receiving the response of the previous one. This is the solution to the HOL bloking of `HTTP/1.0`. And, this is called `pipeline` in `HTTP/1.1`. @@ -118,7 +119,7 @@ The process can be represented as follow: ### Stack -Stack is a kind of blocked sequence. It only supports to add or remove element at the **top** of stack. +Stack is a kind of limited sequence. It only supports to add or remove element at the **top** of stack. In IT area, a stack is an ADT (abstract data type) for representing a set of elements. From a888630564dcb604546f621cef72f499f38b0ad3 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Wed, 5 Jun 2019 11:27:22 +0800 Subject: [PATCH 08/25] change 'fundamental' to 'basic' --- thinkings/basic-data-structure-en.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/thinkings/basic-data-structure-en.md b/thinkings/basic-data-structure-en.md index a619629e1..f08777a72 100644 --- a/thinkings/basic-data-structure-en.md +++ b/thinkings/basic-data-structure-en.md @@ -1,6 +1,6 @@ -# Fundamental data structure +# Basic data structure -> WIP: the translation of `fundamental data structure` is on the way. +> WIP: the translation of `basic data structure` is on the way. This article is not going to intepret data structures, but help you to `review and understand` data structures and algorithms with real scenes. So, if you have a poor data structure foundation, you'd better to read some basic courses about data structures before reading this. From 76689b71143561630e25e03dc1cc5a1bb08d1e5a Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Wed, 5 Jun 2019 13:48:44 +0800 Subject: [PATCH 09/25] remove some trivial details about HTTP/1.0 --- thinkings/basic-data-structure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thinkings/basic-data-structure.md b/thinkings/basic-data-structure.md index ff122adf2..07642b71d 100644 --- a/thinkings/basic-data-structure.md +++ b/thinkings/basic-data-structure.md @@ -105,7 +105,7 @@ React 将`如何确保组件内部hooks保存的状态之间的对应关系`这 ![basic-data-structure-queue-1](../assets/thinkings/basic-data-structure-queue-1.png) `HTTP/1.0` 和 `HTTP/1.1`: -在`HTTP/1.0` 中每一次请求都需要建立一个TCP连接,请求结束后立即断开连接。而且下一个包必须在收到前一个包的响应之后才能发送。 +在`HTTP/1.0` 中每一次请求都需要建立一个TCP连接,请求结束后立即断开连接。 在`HTTP/1.1` 中,每一个连接都默认是长连接(persistent connection)。对于同一个tcp连接,允许一次发送多个http1.1请求,也就是说,不必等前一个响应收到,就可以发送下一个请求。这样就解决了http1.0的客户端的队头阻塞,而这也就是`HTTP/1.1`中`管道(Pipeline)`的概念了。 但是,`http1.1规定,服务器端的响应的发送要根据请求被接收的顺序排队`,也就是说,先接收到的请求的响应也要先发送。这样造成的问题是,如果最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队头阻塞。 可见,http1.1的队首阻塞发生在服务器端。 From 1cb943e5a9d2cdb80d6780aec46988ab6ceab91a Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Fri, 21 Jun 2019 09:41:03 +0800 Subject: [PATCH 10/25] error correction --- thinkings/dynamic-programming.md | 1 - 1 file changed, 1 deletion(-) diff --git a/thinkings/dynamic-programming.md b/thinkings/dynamic-programming.md index c0af9d820..57d87adf1 100644 --- a/thinkings/dynamic-programming.md +++ b/thinkings/dynamic-programming.md @@ -119,7 +119,6 @@ function climbStairs(n) { > 爬楼梯我们并没有使用一维数组,而是借助两个变量来实现的,空间复杂度是 O(1). > 之所以能这么做,是因为爬楼梯问题的状态转移方程只和前两个有关,因此只需要存储这两个即可。 动态规划问题有时候有很多这种讨巧的方式,但并不是所有的 -> 动态规划都可以这么讨巧,比如背包问题。 ### 动态规划的两个要素 From 2871ad1fc65b2e2b3ab7ce3b16eb5f419a83b78a Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Fri, 21 Jun 2019 11:27:57 +0800 Subject: [PATCH 11/25] translation for DP --- thinkings/dynamic-programming-en.md | 159 ++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 thinkings/dynamic-programming-en.md diff --git a/thinkings/dynamic-programming-en.md b/thinkings/dynamic-programming-en.md new file mode 100644 index 000000000..a81e19c26 --- /dev/null +++ b/thinkings/dynamic-programming-en.md @@ -0,0 +1,159 @@ +# Recursion and Dynamic Programming + +> WIP: the translation of `Recursive and Dynamic Programming` is on the way. + +Dynamic Programming (DP) can be interpreted as the recursion of table look-up. Then, what is recursion? + +## Recursion + +Definition: The process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called as recursive function. + +In some algorithms, recursion can help to implement loop functions very easily. For example, the traverse of Binary Tree. Recursion is widely used in algorithms, including the increasingly popular Functional programming. + +> In pure functional programming, there is no loops, but only recursion. + +Now, let's going to talk about recursion. In layman's terms, A recursive solution solves a problem by solving a smaller instance of the same problem. It solves this new problem by solving an even smaller instance of the same problem. Eventually, the new problem will be so small that its solution will either be obvious or known. This solution will lead to the solution of the original problem. + +### Three Key Factors of Recursion + +1. Each recursive call should be on a smaller instance of the same problem, that is, a smaller subproblem. +2. The recursive calls must eventually reach a base case, which is solved without further recursion. + +There are several questions which can be solved by using recursion easily: + +- [sum by recursion](https://www.geeksforgeeks.org/sum-of-natural-numbers-using-recursion/) +- [Traverse Binary Tree](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/) +- [climbing stairs](https://leetcode.com/problems/climbing-stairs/) +- [tower of Hanoi](https://www.geeksforgeeks.org/c-program-for-tower-of-hanoi/) + +## Dynamic Programming (DP) + +> If we say, recursion is a detivation from the solution to the problem which trying to shrinkthe problem and solve it. Then DP solves probems by starting from a small condition and extending it to the optimal substructure. + +The thinking of recursion is intuitive. And it is easy to be implemented. But sometimes, with drawing a recursion tree to help analyse, we can find that recursion may bring extra computation during shriking the scale of the problem. +We are going to use recursion to solve [279.perfect-squares](../problems/279.perfect-squares.md) with using a buffer to store the intermediate result for reducing some computation. In fact, this is also the key idea in DP. + +Here is an example of calculate the sum of all items in the given array. + +code: + +```js +function sum(nums) { + if (nums.length === 0) return 0; + if (nums.length === 1) return nums[0]; + + return nums[0] + sum(nums.slice(1)); +} +``` + +Let's review this problem intuitively with a recursion tree. + +![dynamic-programming-1](../assets/thinkings/dynamic-programming-1.png) + +This method works, but not quit good. Because there are certain costs in executing functions. Let's take JS as example. +For each time a function executed, it requires stack push operations, pre-processing and executing processes. So, recurse a function is easy to cause stack overflow. + +> In browser, the JS exgine has limit to the length of code execution stack. The stack overflow exeption happens when the length of execution stack exceeds the limit. + +Another example for recursion: + +You are climbing a stair case. It takes n steps to reach to the top. +Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? + +code: + +```js +function climbStairs(n) { + if (n === 1) return 1; + if (n === 2) return 2; + return climbStairs(n - 1) + climbStairs(n - 2); +} +``` + +This question is just like the `fibnacci` series. Let's have a look at the recursion tree of `fibnacci` question again. + +![dynamic-programming-2](../assets/thinkings/dynamic-programming-2.png) + +Some results are calculated repeatedly. Just like the red nodes showing. If a structure like `hashtable` is used to store the intermedia results, the reduplicative calculations can be avoided. +Similarly, DP also uses "table look-up" to solve the problem of reduplicative calculation. + +Now let's talk more about the DP. + +How to start from a small condition to achieve the optimal substructure. + +This is the solution to the previous question with using DP: + +```js +function climbStairs(n) { + if (n === 1) return 1; + if (n === 2) return 2; + + let a = 1; + let b = 2; + let temp; + + for (let i = 3; i <= n; i++) { + temp = a + b; + a = b; + b = temp; + } + + return temp; +} +``` + +Here is the process of "table look-up" in DP: + +![dynamic-programming-3](../assets/thinkings/dynamic-programming-3.png) + +> dotted box is the "table look-up" + +This question is the most simplest one in DP, bacause it only contains a single factor. If it comes down to multiple factors, the question will be much more complex, such as knapsack problem. + +For one factor, we only need a one-dimentional array at most. But for knapsack problem, we may need two-dimentional or even higher dimentional array. + +Sometimes, we don't even need a one-dimentional array, just like the climbing stairs question. Bacause, in this question, only the past two states are required. That's why two varibles are enough. But not all DP questions have the shortcut like this. + +### Two Key Factors in DP + +1. state transfer function +2. critical condition + +In the previous question: + +``` +f(1) and f(2) are the critical conditions +f(n) = f(n-1) + f(n-2) is the state transfer function +``` + +### Why it is necessary to draw a table for solving DP questions + +Drawing a table to solve DP questions is a effective and efficient way. + +Essentially, DP breaks a problem into similar subproblems and solve the problem by solving its all subproblems. + +It is similar to recursion. But DP can reduce the time and space compexity by a way like table look-up. + +Drawing a table can help to complete the state transfer function. Each cell in the table is a subproblem. The process of filling the table, is the way to solve all subproblems. After solving all subproblems, it is easy to find the solution to the original problem. + +First, we solve the simplest subproblem which can be worked out directly. Then, with state transfer function, the adjacent cells can be worked out. Finnally, the last cell, generally at the low right corner of the table, is the solution to the problem. + +For example, using DP to solve Backpack problem, it makes decision that which cell should be selected with considering the previous subproblems `A[i-1][j] A[i-1][w-wj]`. The question needs the max value. So, we can work out the value respectively for the two different condition and choose the larger one and update the new cell. + +### Related Questions + +- [0091.decode-ways](../problems/91.decode-ways.md) +- [0139.word-break](../problems/139.word-break.md) +- [0198.house-robber](../problems/0198.house-robber.md) +- [0309.best-time-to-buy-and-sell-stock-with-cooldown](../problems/309.best-time-to-buy-and-sell-stock-with-cooldown.md) +- [0322.coin-change](../problems/322.coin-change.md) +- [0416.partition-equal-subset-sum](../problems/416.partition-equal-subset-sum.md) +- [0518.coin-change-2](../problems/518.coin-change-2.md) + +> there are much more related questions not presented. + +## Summary + +There are two important algorithms in this article: recursion and dynamic programming. + +If recursion is a bottom-top process, then DP is a top-bottom process. From 987d03b5700bdbc17af9fdea93eb972d0ccd9975 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Fri, 21 Jun 2019 15:32:52 +0800 Subject: [PATCH 12/25] translation for string problems --- thinkings/string-problems-en.md | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 thinkings/string-problems-en.md diff --git a/thinkings/string-problems-en.md b/thinkings/string-problems-en.md new file mode 100644 index 000000000..5cf6ca770 --- /dev/null +++ b/thinkings/string-problems-en.md @@ -0,0 +1,44 @@ +# Problems about String + +There are many problems about string, including `substr` implementation, validating palindrome and common substring and so on. Essentially, a string is also an array of characters. So, many ideas of array can be used to solve the problems of string. + +There are many algorithms which specifically used for handle strings. Such as `trie`, `huffman tree`, `Manacher` and so on. + +## Problems about Implementing Build-in Functions of String + +This kind of questions are the most direct ones with less ambiguous meanings and less challenging. So, it is always be used in the phone interviews. + +- [28.implement-str-str](https://leetcode.com/problems/implement-strstr/) +- [344.reverse-string](../backlog/344.reverse-string.js) + +## Palindrome + +A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward. Like "level" and "noon". + +There is universal method to check whether a string is palindrome or not which uses two pointers, one at the begining and the other at the end, to move to the middle together step by step. You can check the following question `125`for more detials. +For finding the longest palindrome, it is possible to reduce many meaningless algorithms if we take full advantage of the feature of palindrome. Manacher's algorithm is a typical example. + +### Related Questions + +- [5.longest-palindromic-substring](../problems/5.longest-palindromic-substring.md) + +- [125.valid-palindrome](../problems/125.valid-palindrome.md) + +- [131.palindrome-partitioning](../problems/131.palindrome-partitioning.md) + +- [shortest-palindrome](https://leetcode.com/problems/shortest-palindrome/) + +- [516.longest-palindromic-subsequence](../problems/516.longest-palindromic-subsequence.md) + +## Prefix Questions + +It is intuitive to use prefix tree to handle this kind of questions. But it also has some disadvantages. For example, if there are less common prefix, using prefix tree may cost more RAMs. + +### Related Questions + +-[14.longest-common-prefix](../14.longest-common-prefix.js) +-[208.implement-trie-prefix-tree](../problems/208.implement-trie-prefix-tree.md) + +## Other Questions + +- [139.word-break](../problems/139.word-break.md) From da211322c23ba4717cc7657891b6ff4f34259511 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Thu, 11 Jul 2019 20:01:37 +0800 Subject: [PATCH 13/25] error correction --- daily/2019-06-04.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily/2019-06-04.md b/daily/2019-06-04.md index 758ced5b0..875093eb8 100644 --- a/daily/2019-06-04.md +++ b/daily/2019-06-04.md @@ -52,7 +52,7 @@ let start = 0; for(let i = 0; i < n; i++){ total += gas[i]; - total += cost[i] + total -= cost[i] remain += gas[i]; remain -= cost[i]; From 7a66d89f8f9f16d706df2e4892e7ce1aebd27eba Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Mon, 12 Aug 2019 14:07:38 +0800 Subject: [PATCH 14/25] correct wrongly typed --- problems/301.remove-invalid-parentheses.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/301.remove-invalid-parentheses.md b/problems/301.remove-invalid-parentheses.md index be3118431..9e308507e 100644 --- a/problems/301.remove-invalid-parentheses.md +++ b/problems/301.remove-invalid-parentheses.md @@ -38,7 +38,7 @@ Output: [""] ## 关键点解析 -- 广度有限遍历 +- 广度优先遍历 - 使用队列简化操作 From 922dca86cc9657992a2be85962a816b5b4e2a9ba Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Mon, 12 Aug 2019 16:21:51 +0800 Subject: [PATCH 15/25] translation for binary-tree-traversal.md --- thinkings/binary-tree-traversal-en.md | 115 ++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 thinkings/binary-tree-traversal-en.md diff --git a/thinkings/binary-tree-traversal-en.md b/thinkings/binary-tree-traversal-en.md new file mode 100644 index 000000000..686235e2f --- /dev/null +++ b/thinkings/binary-tree-traversal-en.md @@ -0,0 +1,115 @@ +# Binary Tree Traversal + +## Overview + +Binary tree is a fundamental data structure. Traversal is a fundamental algorithm. Implementing traversal on binary tree makes a classical solution to problems. Many problems can be solved by trversaling binary tree, directly or indirectly. + +> If you have a good understanding of binary tree, it is not hard for you to understand other trees more complicated. + +The traversal of binary tree is basically comprised of in-order, pre-order, post-order and level-order traversals. + +A tree is typically traversed in two ways: + +- BFS (Breadth First Search, or Level Order Search) +- DFS (Depth First Search) + - In-order (Left-Root-Right) + - Pre-order (Root-Left-Right) + - Post-order (Left-Right-Root) + +Some problems can be solved with BFS and DFS, such as [301](../problems\301.remove-invalid-parentheses.md) and [609](../problems\609.find-duplicate-file-in-system.md) + +DFS simplifies operations with stack. Meanwhile, a tree is a recursive data structure. It is important to grasp recursion and stack for understanding DFS. + +Diagrammatic graph of DFS: + +![binary-tree-traversal-dfs](../assets/thinkings/binary-tree-traversal-dfs.gif) + +(source: https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search) + +The key point of BFS is whether the travesals of each level are completed or not. An identifier bit can be used to represent that. + +Then, let's talk about the in-order, pre-oder and post-order traversals. + +## Pre-order + +example: [144.binary-tree-preorder-traversal](../problems/144.binary-tree-preorder-traversal.md) + +order of traversal: `root-left-right` + +Algorithm Preorder(tree): + +1. visit the root. + +2. traverse the left subtree, i.e., call Preorder(left-subtree) + +3. traverse the right subtree, i.e., call Preorder(right-subtree) + +Summary: + +- typically recursive data structure. +- typycally algorithm which simplifies operations by stack. + +Actually, at the macro level, it can be described as `visit all left-side chain in sequence from top to bottom, and then, visit all right-side chain from bottom to top` + +If we think from this point of view, the algorithm can be different. All nodes in the left-side chain can be visited recursively from top to bottom directly. And all nodes in the right-side chain can be visited with the help of stack. + +The whole process is like this: + +![binary-tree-traversal-preorder](../assets/thinkings/binary-tree-traversal-preorder.png) + +This idea is something like the `backtrack`. It is important, because this idea can help us to `unify the understanding of three traversal methods`. + +## In-order + +example: [94.binary-tree-inorder-traversal](../problems/94.binary-tree-inorder-traversal.md) + +Order of In-order traversal: `Left-Root-Right` + +Algorithm Inorder(tree): + +1. Traverse the left subtree, i.e., call Inorder(left-subtree) + +2. Visit the root + +3. Traverse the right subtree, i.e., call Inorder(right-subtree) + +It is worth noting that, the result of traversing a BST (Binary Search Tree) is an ordered array. With this property, some problems can be simplified, such as: [230.kth-smallest-element-in-a-bst](../problems/230.kth-smallest-element-in-a-bst.md) and [98.validate-binary-search-tree](../problems/98.validate-binary-search-tree.md) + +## Post-order + +example: [145.binary-tree-postorder-traversal](../problems/145.binary-tree-postorder-traversal.md) + +Order of Post-order: `Left-Right-Root` + +This one is a liitle difficult to understand. + +But there is a clever trick to post-order traversal which is recording the trversal status of current node. +If + +1. current node is leaf node or +2. both left and right subtrees have been traversed + +the node can be popped out the stack. + +For condition 1, a leaf node is the node with no children (both left and right children are null); +For condition 2, variables are required for recording the traversal status for each node. Due to the stack, only one variable is indispensable bacause this variable can be used. + +## Level-order + +The key point of level-order is recording the traversal status of each level. An identifier bit can be used to represent the status of current level. + +![binary-tree-traversal-bfs](../assets/thinkings/binary-tree-traversal-bfs.gif) + +(source: https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/breadth-first-search) + +Algorithm Level-order(tree): + +1. push root into a queue. And put an identifier node into the queue which is null here. + +2. pop out one node from the queue. + +3. If the popped out node is not null, which means the traversal of current level is not finished, push the left and right node into the queue orderly. + +4. If the popped out node is null, which means the traversal of current level is finished. Now if the queue is null, the traversal is done. If the queue is not null, push a null node into the queue. + +example: [102.binary-tree-level-order-traversal](../problems/102.binary-tree-level-order-traversal.md) \ No newline at end of file From 33a2ee50a166bd8d2f95df292b587264599cbe89 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Mon, 12 Aug 2019 17:59:07 +0800 Subject: [PATCH 16/25] correct wrongly typed --- thinkings/run-length-encode-and-huffman-encode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thinkings/run-length-encode-and-huffman-encode.md b/thinkings/run-length-encode-and-huffman-encode.md index ef630638b..350ae4cbe 100644 --- a/thinkings/run-length-encode-and-huffman-encode.md +++ b/thinkings/run-length-encode-and-huffman-encode.md @@ -66,7 +66,7 @@ AAAAABBBBCCC 5A表示这个地方有5个连续的A,同理4B表示有4个连续的B,3C表示有3个连续的C,其它情况以此类推。 -但是实际上情况可能会非常复杂, 如何提取自序列有时候没有看的那么简单,还是上面的例子,我们 +但是实际上情况可能会非常复杂, 如何提取子序列有时候没有看的那么简单,还是上面的例子,我们 有时候可以把`AAAAABBBBCCC`整体看成一个子序列, 更复杂的情况还有很多,这里不做扩展。 From e0136d00451769c7e44b89d939fe9499f0bb20d8 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Mon, 12 Aug 2019 22:01:11 +0800 Subject: [PATCH 17/25] update README.en.md --- README.en.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.en.md b/README.en.md index 20b083be2..846627b3c 100644 --- a/README.en.md +++ b/README.en.md @@ -4,6 +4,13 @@ --- +![leetcode.jpeg](./assets/leetcode.jpeg) + +This essay records the course of and my emotion to this project from initialisation to 10,000 stars. +[Milestone for 10,000+ stars](./thanksGiving.md) + +If you are interested in this project, do not mean your star. This project will be supported for a long enough time by the comminity. Thanks for every audience and contributor. + ## Introduction ![leetcode.jpeg](./assets/leetcode.jpeg) @@ -24,7 +31,13 @@ This repository is divided into five parts for now: > Only when having mastered the basic data structures and algorithms can you solve complex problems easily. +## About me + +I, a programmer, am all passionate about technology. + +Used to write `.net` and `Java`, I am a frontend engineer and focused on the engineering, optimization and standardlization for frontend. +If you want to do some contributions or collaborations, just feel free to contact me via [azl397985856@gmail.com]. ## Usage Instructions From 49affbd09dc1fd5e91276be0e46990944dcaba1e Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Tue, 13 Aug 2019 10:58:23 +0800 Subject: [PATCH 18/25] update description of Huffman encoding --- .../run-length-encode-and-huffman-encode.md | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/thinkings/run-length-encode-and-huffman-encode.md b/thinkings/run-length-encode-and-huffman-encode.md index 350ae4cbe..a555f949b 100644 --- a/thinkings/run-length-encode-and-huffman-encode.md +++ b/thinkings/run-length-encode-and-huffman-encode.md @@ -1,75 +1,75 @@ -## 游程编码和哈夫曼编码 +# 游程编码和哈夫曼编码 -### huffman encode(哈夫曼编码) +## Huffman encode(哈夫曼编码) -huffman 编码的基本思想就是用短的编码表示长的字符序列,用长的编码来表示短的字符序列,从而实现压缩的目的。 -因此huffman编码被广泛地应用于无损压缩领域。 +Huffman 编码的基本思想就是用短的编码表示出现频率高的字符,用长的编码来表示出现频率低的字符,这使得编码之后的字符串的平均长度、长度的期望值降低,从而实现压缩的目的。 +因此 Huffman 编码被广泛地应用于无损压缩领域。 -上面提到了他的基本原理就是`用短的编码表示长的字符序列,用长的编码来表示短的字符序列`, -因此首先要做的就是统一字符序列的出现频率,然后根据统计的频率来构建huffman树(又叫最优二叉树)。 +Huffman 编码的过程包含两个主要部分: -![huffman-tree](../assets/thinkings/huffman-tree.webp) +- 根据输入字符构建 Huffman 树 +- 遍历 Huffman 树,并将树的节点分配给字符 -huffman 树就像是一个堆。 真正执行编码的时候,类似字典树,节点不用来编码,节点的路径用来编码 +上面提到了他的基本原理就是`用短的编码表示出现频率高的字符,用长的编码来表示出现频率低的字符`, +因此首先要做的就是统计字符的出现频率,然后根据统计的频率来构建 Huffman 树(又叫最优二叉树)。 -> 节点的值只是用来构建huffman 树 +![Huffman-tree](../assets/thinkings/huffman-tree.webp) + +Huffman 树就像是一个堆。真正执行编码的时候,类似字典树,节点不用来编码,节点的路径用来编码. + +> 节点的值只是用来构建 Huffman 树 eg: 我们统计的结果如下: -``` -character frequency - a 5 - b 9 - c 12 - d 13 - e 16 - f 45 - -``` +|character|frequency| +|:--:|:--:| +|a|5| +|b|9| +|c|12| +|d|13| +|e|16| +|f|45| - 将每个元素构造成一个节点,即只有一个元素的树。并构建一个最小堆,包含所有的节点,该算法用了最小堆来作为优先队列。 -- `选取两个权值最小的节点`,并添加一个权值为5+9=14的节点,作为他们的父节点。并`更新最小堆`, -现在最小堆包含5个节点,其中4个树还是原来的节点,权值为5和9的节点合并为一个。 +- `选取两个权值最小的节点`,并添加一个权值为5+9=14的节点,作为他们的父节点。并`更新最小堆`,现在最小堆包含5个节点,其中4个树还是原来的节点,权值为5和9的节点合并为一个。 结果是这样的: ![huffman-example](../assets/thinkings/huffman-example.png) -``` -character frequency encodeing - a 5 1100 - b 9 1110 - c 12 100 - d 13 101 - e 16 111 - f 45 0 - -``` +|character|frequency|encoding| +|:-:|:-:|:-:| +|a|5|1100| +|b|9|1110| +|c|12|100| +|d|13|101| +|e|16|111| +|f|45|0| +## run-length encode(游程编码) -### run-length encode(游程编码) 游程编码是一种比较简单的压缩算法,其基本思想是将重复且连续出现多次的字符使用(连续出现次数,某个字符)来描述。 比如一个字符串: -``` +```text AAAAABBBBCCC ``` + 使用游程编码可以将其描述为: -``` +```text 5A4B3C ``` -5A表示这个地方有5个连续的A,同理4B表示有4个连续的B,3C表示有3个连续的C,其它情况以此类推。 +5A表示这个地方有5个连续的A,同理4B表示有4个连续的B,3C表示有3个连续的C,其它情况以此类推。 但是实际上情况可能会非常复杂, 如何提取子序列有时候没有看的那么简单,还是上面的例子,我们 有时候可以把`AAAAABBBBCCC`整体看成一个子序列, 更复杂的情况还有很多,这里不做扩展。 - 对文件进行压缩比较适合的情况是文件内的二进制有大量的连续重复, 一个经典的例子就是具有大面积色块的BMP图像,BMP因为没有压缩, 所以看到的是什么样子存储的时候二进制就是什么样子 @@ -79,10 +79,10 @@ AAAAABBBBCCC > 思考一个问题, 如果我们在CDN上存储两个图片,这两个图片几乎完全一样,我们是否可以进行优化呢? 这虽然是CDN厂商更应该关心的问题,但是这个问题对我们影响依然很大,值得思考 -### 总结 +## 总结 -实际情况,我们先用游程编码一遍,然后再用huffman 再次编码一次。 +实际情况,我们先用游程编码一遍,然后再用 Huffman 再次编码一次。 -### 相关题目 +## 相关题目 [900.rle-iterator](../problems/900.rle-iterator.md) \ No newline at end of file From 8db781f5a3cc996373cdcc1a400012c4419044ab Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Tue, 13 Aug 2019 11:05:38 +0800 Subject: [PATCH 19/25] update file path of Binary-tree-traversal-en.md. --- README.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.en.md b/README.en.md index 846627b3c..410972c8b 100644 --- a/README.en.md +++ b/README.en.md @@ -231,7 +231,7 @@ The data structures mainly includes: - [Data Structure](./thinkings/basic-data-structure-en.md) (Drafts) - [Basic Algorithm](./thinkings/basic-algorithm.md)Drafts -- [Binary Tree Traversal](./thinkings/binary-tree-traversal.md) +- [Binary Tree Traversal](./thinkings/binary-tree-traversal-en.md) - [Dynamic Programming](./thinkings/dynamic-programming-en.md) - [Huffman Encode and Run Length Encode](./thinkings/run-length-encode-and-huffman-encode.md) - [Bloom Filter](./thinkings/bloom-filter.md) From 83acb43db1abdaad3fbd5731fa10241ac93f5443 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Tue, 13 Aug 2019 11:42:57 +0800 Subject: [PATCH 20/25] correct wrongly typed --- thinkings/basic-algorithm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thinkings/basic-algorithm.md b/thinkings/basic-algorithm.md index dd08c3deb..5c2f9609a 100644 --- a/thinkings/basic-algorithm.md +++ b/thinkings/basic-algorithm.md @@ -23,7 +23,7 @@ - 插入排序 - 选择排序 - 希尔排序 --冒泡排序 +- 冒泡排序 #### O(nlogn) From 2806f2dcaade50cbe5052d65b16ec4a719e04a4a Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Tue, 13 Aug 2019 11:43:27 +0800 Subject: [PATCH 21/25] update paths of thinkings --- README.en.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.en.md b/README.en.md index 410972c8b..69c5cec31 100644 --- a/README.en.md +++ b/README.en.md @@ -230,11 +230,11 @@ The data structures mainly includes: ### Summary of Data Structures and Algorithms - [Data Structure](./thinkings/basic-data-structure-en.md) (Drafts) -- [Basic Algorithm](./thinkings/basic-algorithm.md)Drafts +- [Basic Algorithm](./thinkings/basic-algorithm-en.md)Drafts - [Binary Tree Traversal](./thinkings/binary-tree-traversal-en.md) - [Dynamic Programming](./thinkings/dynamic-programming-en.md) -- [Huffman Encode and Run Length Encode](./thinkings/run-length-encode-and-huffman-encode.md) -- [Bloom Filter](./thinkings/bloom-filter.md) +- [Huffman Encode and Run Length Encode](./thinkings/run-length-encode-and-huffman-encode-en.md) +- [Bloom Filter](./thinkings/bloom-filter-en.md) - [String Problems](./thinkings/string-problems-en.md) From 0903e5253f27a0b33a2f89e3ad40fc7ac9d9559a Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Tue, 13 Aug 2019 11:44:00 +0800 Subject: [PATCH 22/25] translation for basic-algorithm.md (Draft) --- thinkings/basic-algorithm-en.md | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 thinkings/basic-algorithm-en.md diff --git a/thinkings/basic-algorithm-en.md b/thinkings/basic-algorithm-en.md new file mode 100644 index 000000000..f9ddef84b --- /dev/null +++ b/thinkings/basic-algorithm-en.md @@ -0,0 +1,61 @@ +# Basic Algorithms + +## Analysis of Time Complexity + +## Algorithm Thoughts + +### Greedy Algorithms + +### Divide-and-Conquer + +### Dynamic Programming + +### Backtracking + +### Enumeration + +## Meta Algorithm + +### Sorting Algorithms + +Sorting algorithms are meta algorithm. Although they are not tested quit often, the core ideas are very useful. + +#### O(n^2) + +- Insertion Sort +- Selection Sort +- Shell's Sort (aka Diminishing Increment Sort) +- Bubble Sort + +#### O(nlogn) + +- Quick Sort +- Merge Sort +- Heap Sort + +#### O(n) + +- Bucket Sort +- Counting Sort +- Radix Sort + +### Searching Algorithm + +- BFPRT Algorithm +- Search Trees +- Search by Hashing + +## Algorithms for String + +- 朴素 +- KMP +- RK +- BM +- trie + +## Other + +- Number Theory +- Probability Theory +- Union-find Algorithm +- Matrix Algorithms \ No newline at end of file From 5c77911de958d231caaaa027198e1891b57232a7 Mon Sep 17 00:00:00 2001 From: STONE <1037311800@qq.com> Date: Tue, 13 Aug 2019 14:51:19 +0800 Subject: [PATCH 23/25] translation for bloom-filter.md --- thinkings/bloom-filter-en.md | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 thinkings/bloom-filter-en.md diff --git a/thinkings/bloom-filter-en.md b/thinkings/bloom-filter-en.md new file mode 100644 index 000000000..5d5ce202f --- /dev/null +++ b/thinkings/bloom-filter-en.md @@ -0,0 +1,65 @@ +# Bloom-filter + +## Scenes + +Assume that you have a website which has so many audiences, what will you do if you want to know whether an IP address of a visitor is the first time to access your server or not. + +### Can hashtable do this? + +Of course yes. +Obviously, a hashtable with storing all IP addresses can tell us whether we have known one IP already. But, imagine that, if there are more than 1 billion IP addresses have been recorded, at least `4 Byte * 1,000,000,000 = 4,000,000,000 Byte = 4 GB` RAM is required. If it is not IP, but URL, the RAM required will be much larger. + +### Bit + +Another solution is using 1 bit to represent the access status of 1 IP, accessed or not. +For the same 1 billion IP addresses, now only `1 * 1,000,000,000 = 128 MB` RAM is required. If it is URL, this method uses much less spaces. + +With this method, only two operations are needed: `set(ip)` and `has(IP)`. + +However, this method has two fatal weakness: + +1. If elements are not distributed uniformly, a lot of spaces will not be used which is inefficient in space. + + > A good Hash function can be used to overcome this weakness. + +2. If the elements are not integer (e.g. URL), `BitSet` is inapplicable. + + > one or more Hash functions can also solve this. + +### Bloom Filter + +A Bloom filter is a space-efficient probabilistic data structure that is used to test whether an element is a member of a set. + +Actually, Bloom Filter is the second method with multiple hash functions. + +Here are four interesting properties of Bloom filter: + +- Unlike a standard hash table, a Bloom filter of a fixed size can represent a set with an arbitrarily large number of elements. + +- Adding an element never fails. However, the false positive rate increases steadily as elements are added until all bits in the filter are set to 1, at which point all queries yield a positive result. + +- Bloom filters never generate false negative result, i.e., telling you that a username doesn’t exist when it actually exists. + +- Deleting elements from filter is not possible because, if we delete a single element by clearing bits at indices generated by k hash functions, it might cause deletion of few other elements. + +![bloom-filter-url](../assets/thinkings/bloom-filter-url.png) + +### Application of Bloom Filter + +1. Network crawler + +whether an URL has been crawled or not. + +2. `key-value` database + +Whether a Key exists in this database or not. + +Example: +Each region of HBase has a Bloom Filter, which can be used to find whether a key exists in this region or not quickly. + +3. Phishing websites detection + +Sometimes browsers may alert that a website you are accessing is a phishing website. +Browsers use Bloom Filter to find wheter URL of one website exists in the phishing website database. + +> Hope this Algorithm can help you have a better understanding to `TRADEOFF`. From 366b72ca5d1b3273490d78ea6820e0ee7f61dbaa Mon Sep 17 00:00:00 2001 From: stonelyu Date: Tue, 24 Dec 2019 14:37:27 +0800 Subject: [PATCH 24/25] add java solution with inorder traversing --- problems/230.kth-smallest-element-in-a-bst.md | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/problems/230.kth-smallest-element-in-a-bst.md b/problems/230.kth-smallest-element-in-a-bst.md index 566405c90..1c2c78eba 100644 --- a/problems/230.kth-smallest-element-in-a-bst.md +++ b/problems/230.kth-smallest-element-in-a-bst.md @@ -107,6 +107,39 @@ var kthSmallest = function(root, k) { }; ``` +Java Solution: + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +private int count = 1; +private int res; + +public int KthSmallest (TreeNode root, int k) { + inorder(root, k); + return res; +} + +public void inorder (TreeNode root, int k) { + if (root == null) return; + + inorder(root.left, k); + + if (count++ == k) { + res = root.val; + return; + } + + inorder(root.right, k); +} +``` 解法二: From fc054c2fbf41c1c00d62f56fa3b6c239285e1cb6 Mon Sep 17 00:00:00 2001 From: lucifer Date: Tue, 24 Dec 2019 15:26:09 +0800 Subject: [PATCH 25/25] Update 230.kth-smallest-element-in-a-bst.md --- problems/230.kth-smallest-element-in-a-bst.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/problems/230.kth-smallest-element-in-a-bst.md b/problems/230.kth-smallest-element-in-a-bst.md index 1c2c78eba..b11e07d78 100644 --- a/problems/230.kth-smallest-element-in-a-bst.md +++ b/problems/230.kth-smallest-element-in-a-bst.md @@ -56,6 +56,8 @@ What if the BST is modified (insert/delete operations) often and you need to fin 解法一: +JavaScript Code: + ```js @@ -107,7 +109,7 @@ var kthSmallest = function(root, k) { }; ``` -Java Solution: +Java Code: ```java /** @@ -143,6 +145,8 @@ public void inorder (TreeNode root, int k) { 解法二: +JavaScript Code: + ```js /**