-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
204 lines (120 loc) · 229 KB
/
atom.xml
File metadata and controls
204 lines (120 loc) · 229 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>JasonLam's Blog</title>
<subtitle>Just Enjoy It!</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="JasonLam0990.github.io/"/>
<updated>2019-04-13T08:42:12.255Z</updated>
<id>JasonLam0990.github.io/</id>
<author>
<name>JasonLam</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Javascript数组方法总结</title>
<link href="JasonLam0990.github.io/2019/04/13/Javascript%E6%95%B0%E7%BB%84%E6%96%B9%E6%B3%95%E6%80%BB%E7%BB%93/"/>
<id>JasonLam0990.github.io/2019/04/13/Javascript数组方法总结/</id>
<published>2019-04-13T05:40:49.000Z</published>
<updated>2019-04-13T08:42:12.255Z</updated>
<content type="html"><![CDATA[<hr><h1 id="数组方法"><a href="#数组方法" class="headerlink" title="数组方法"></a>数组方法</h1><hr><h2 id="Array-from"><a href="#Array-from" class="headerlink" title="Array.from()"></a>Array.from()</h2><div class="note info"><p>从类数组对象或者可迭代对象中创建一个新的数组实例。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 从类数组对象中创建一个新的数组实例</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">arguments</span>) <span class="comment">// { '0': 1, '1': 2, '2': 3 }</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">arguments</span>.length) <span class="comment">// 3</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Array</span>.from(<span class="built_in">arguments</span>);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(f(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)); <span class="comment">// [1, 2, 3]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 从可迭代对象中创建一个新的数组实例,可以获取对象中的元素,如 Map和 Set 等,并进行一定操作</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> arr = <span class="built_in">Array</span>.from([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>], x => x + x)</span><br><span class="line"><span class="built_in">console</span>.log(arr) <span class="comment">// expected output: [2, 4, 6]</span></span><br></pre></td></tr></table></figure><h2 id="Array-isArray"><a href="#Array-isArray" class="headerlink" title="Array.isArray()"></a>Array.isArray()</h2><div class="note info"><p>Array.isArray() 用于确定传递的值是否是一个 Array。如果对象是 Array,则为true; 否则为false。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">arguments</span>) <span class="comment">// { '0': 1, '1': 2, '2': 3 }</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">arguments</span>.length) <span class="comment">// 3</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">Array</span>.isArray(<span class="built_in">arguments</span>)) <span class="comment">// 类数组,false</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">Array</span>.isArray(<span class="built_in">Array</span>.from(<span class="built_in">arguments</span>))) <span class="comment">// 数组,true</span></span><br><span class="line">}</span><br><span class="line">f(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// Polyfill</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!<span class="built_in">Array</span>.isArray) {</span><br><span class="line"> <span class="built_in">Array</span>.isArray = <span class="function"><span class="keyword">function</span>(<span class="params">arg</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Object</span>.prototype.toString.call(arg) === <span class="string">'[object Array]'</span>;</span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="Array-of"><a href="#Array-of" class="headerlink" title="Array.of()"></a>Array.of()</h2><div class="note info"><p>根据一组参数来创建新的数组实例,支持任意的参数数量和类型。这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Array</span>.of(<span class="number">7</span>); <span class="comment">// [7] </span></span><br><span class="line"><span class="built_in">Array</span>.of(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>); <span class="comment">// [1, 2, 3]</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">Array</span>() <span class="comment">// []</span></span><br><span class="line"><span class="built_in">Array</span>(<span class="number">7</span>); <span class="comment">// [ , , , , , , ]</span></span><br><span class="line"><span class="built_in">Array</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>); <span class="comment">// [1, 2, 3]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// -----------------------------------</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">Array</span>.of() <span class="comment">// []</span></span><br><span class="line"><span class="built_in">Array</span>.of(<span class="literal">undefined</span>) <span class="comment">// [undefined]</span></span><br><span class="line"><span class="built_in">Array</span>.of(<span class="number">1</span>) <span class="comment">// [1]</span></span><br><span class="line"><span class="built_in">Array</span>.of(<span class="number">1</span>, <span class="number">2</span>) <span class="comment">// [1, 2]</span></span><br></pre></td></tr></table></figure><hr><h1 id="数组实例方法"><a href="#数组实例方法" class="headerlink" title="数组实例方法"></a>数组实例方法</h1><hr><h2 id="修改器方法(会改变调用它们的对象自身的值,即改变原数组)"><a href="#修改器方法(会改变调用它们的对象自身的值,即改变原数组)" class="headerlink" title="修改器方法(会改变调用它们的对象自身的值,即改变原数组)"></a>修改器方法(会改变调用它们的对象自身的值,即改变原数组)</h2><h3 id="Array-prototype-unshift"><a href="#Array-prototype-unshift" class="headerlink" title="Array.prototype.unshift()"></a>Array.prototype.unshift()</h3><div class="note info"><p>在数组的开头增加一个或多个元素,并返回数组的新长度。</p></div><h3 id="Array-prototype-push"><a href="#Array-prototype-push" class="headerlink" title="Array.prototype.push()"></a>Array.prototype.push()</h3><div class="note info"><p>在数组的末尾增加一个或多个元素,并返回数组的新长度。</p></div><h3 id="Array-prototype-shift"><a href="#Array-prototype-shift" class="headerlink" title="Array.prototype.shift()"></a>Array.prototype.shift()</h3><div class="note info"><p>删除数组的第一个元素,并返回这个元素。</p></div><h3 id="Array-prototype-pop"><a href="#Array-prototype-pop" class="headerlink" title="Array.prototype.pop()"></a>Array.prototype.pop()</h3><div class="note info"><p>删除数组的最后一个元素,并返回这个元素。</p></div><h3 id="Array-prototype-reverse"><a href="#Array-prototype-reverse" class="headerlink" title="Array.prototype.reverse()"></a>Array.prototype.reverse()</h3><div class="note info"><p>颠倒数组中元素的排列顺序,即原先的第一个变为最后一个,原先的最后一个变为第一个。</p></div><h3 id="Array-prototype-sort"><a href="#Array-prototype-sort" class="headerlink" title="Array.prototype.sort()"></a>Array.prototype.sort()</h3><div class="note info"><p>对数组元素进行排序,并返回当前数组。默认排序顺序是根据字符串Unicode码点。如果是对数字排序一般需要重写比较函数</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">numbers.sort(<span class="function">(<span class="params">a, b</span>) =></span> a - b);</span><br></pre></td></tr></table></figure><h3 id="Array-prototype-splice-【容易与slice方法搞混】"><a href="#Array-prototype-splice-【容易与slice方法搞混】" class="headerlink" title="Array.prototype.splice()【容易与slice方法搞混】"></a>Array.prototype.splice()【容易与slice方法搞混】</h3><div class="note info"><p>通过删除或替换现有元素来修改数组, 并以数组形式返回被修改的内容。此方法会改变原数组。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 参数:</span></span><br><span class="line"><span class="comment">// 1.指定修改的开始位置(从0计数)</span></span><br><span class="line"><span class="comment">// 2.整数,表示要移除的数组元素的个数。 </span></span><br><span class="line"><span class="comment">// 3.要添加进数组的元素, 从start 位置开始。如果不指定,则 splice() 将只删除数组元素。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> months = [<span class="string">'Jan'</span>, <span class="string">'March'</span>, <span class="string">'April'</span>, <span class="string">'June'</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// inserts at 1st index position</span></span><br><span class="line">months.splice(<span class="number">1</span>, <span class="number">0</span>, <span class="string">'Feb'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(months); <span class="comment">// ['Jan', 'Feb', 'March', 'April', 'June']</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// replaces 1 element at 4th index</span></span><br><span class="line">months.splice(<span class="number">4</span>, <span class="number">1</span>, <span class="string">'May'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(months); <span class="comment">// ['Jan', 'Feb', 'March', 'April', 'May']</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 从第 2 位开始删除所有元素</span></span><br><span class="line">months.splice(<span class="number">2</span>);</span><br><span class="line"><span class="built_in">console</span>.log(months); <span class="comment">// ['Jan', 'March']</span></span><br></pre></td></tr></table></figure><h2 id="访问方法(不改变原数组,只会返回一个新数组或一个其它的期望值)"><a href="#访问方法(不改变原数组,只会返回一个新数组或一个其它的期望值)" class="headerlink" title="访问方法(不改变原数组,只会返回一个新数组或一个其它的期望值)"></a>访问方法(不改变原数组,只会返回一个新数组或一个其它的期望值)</h2><h3 id="Array-prototype-includes"><a href="#Array-prototype-includes" class="headerlink" title="Array.prototype.includes()"></a>Array.prototype.includes()</h3><div class="note info"><p>判断当前数组是否包含某指定的值,如果是返回 true,否则返回 false。</p></div><h3 id="Array-prototype-indexOf"><a href="#Array-prototype-indexOf" class="headerlink" title="Array.prototype.indexOf()"></a>Array.prototype.indexOf()</h3><div class="note info"><p>返回数组中第一个与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1。</p></div><h3 id="Array-prototype-lastIndexOf"><a href="#Array-prototype-lastIndexOf" class="headerlink" title="Array.prototype.lastIndexOf()"></a>Array.prototype.lastIndexOf()</h3><div class="note info"><p>返回数组中最后一个(从右边数第一个)与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1。</p></div><h3 id="Array-prototype-join"><a href="#Array-prototype-join" class="headerlink" title="Array.prototype.join()"></a>Array.prototype.join()</h3><div class="note info"><p>连接所有数组元素组成一个字符串。</p></div><h3 id="Array-prototype-concat"><a href="#Array-prototype-concat" class="headerlink" title="Array.prototype.concat()"></a>Array.prototype.concat()</h3><div class="note info"><p>返回一个由当前数组和其它若干个数组或者若干个非数组值组合而成的新数组。</p></div><h3 id="Array-prototype-slice"><a href="#Array-prototype-slice" class="headerlink" title="Array.prototype.slice()"></a>Array.prototype.slice()</h3><div class="note info"><p>截取当前数组中一段元素(左闭右开)[begin,end) 组合成一个新数组并返回。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 如果参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 </span></span><br><span class="line"><span class="comment">// slice(-2, -1)表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。</span></span><br><span class="line"><span class="comment">// 如果 end 被省略,则slice 会一直提取到原数组末尾。</span></span><br><span class="line"><span class="comment">// 如果 end 大于数组长度,slice 也会一直提取到原数组末尾。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> animals = [<span class="string">'ant'</span>, <span class="string">'bison'</span>, <span class="string">'camel'</span>, <span class="string">'duck'</span>, <span class="string">'elephant'</span>];</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(animals.slice(<span class="number">2</span>));</span><br><span class="line"><span class="comment">// expected output: Array ["camel", "duck", "elephant"]</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(animals.slice(<span class="number">2</span>, <span class="number">4</span>));</span><br><span class="line"><span class="comment">// expected output: Array ["camel", "duck"]</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(animals.slice(<span class="number">1</span>, <span class="number">5</span>));</span><br><span class="line"><span class="comment">// expected output: Array ["bison", "camel", "duck", "elephant"]</span></span><br></pre></td></tr></table></figure><h2 id="迭代方法(对数组进行遍历,大部分都需要指定一个回调函数作为参数)"><a href="#迭代方法(对数组进行遍历,大部分都需要指定一个回调函数作为参数)" class="headerlink" title="迭代方法(对数组进行遍历,大部分都需要指定一个回调函数作为参数)"></a>迭代方法(对数组进行遍历,大部分都需要指定一个回调函数作为参数)</h2><h3 id="Array-prototype-entries"><a href="#Array-prototype-entries" class="headerlink" title="Array.prototype.entries()"></a>Array.prototype.entries()</h3><div class="note info"><p>返回一个数组迭代器对象,该迭代器会包含所有数组元素的键值对。</p></div><h3 id="Array-prototype-keys"><a href="#Array-prototype-keys" class="headerlink" title="Array.prototype.keys()"></a>Array.prototype.keys()</h3><div class="note info"><p>返回一个数组迭代器对象,该迭代器会包含所有数组元素的键。</p></div><h3 id="Array-prototype-values"><a href="#Array-prototype-values" class="headerlink" title="Array.prototype.values()"></a>Array.prototype.values()</h3><div class="note info"><p>返回一个数组迭代器对象,该迭代器会包含所有数组元素的值。</p></div><h3 id="Array-prototype-find"><a href="#Array-prototype-find" class="headerlink" title="Array.prototype.find()"></a>Array.prototype.find()</h3><div class="note info"><p>找到第一个满足测试函数的元素并返回那个元素的值,如果找不到,则返回 undefined。</p></div><h3 id="Array-prototype-findIndex"><a href="#Array-prototype-findIndex" class="headerlink" title="Array.prototype.findIndex()"></a>Array.prototype.findIndex()</h3><div class="note info"><p>找到第一个满足测试函数的元素并返回那个元素的索引,如果找不到,则返回 -1。</p></div><h3 id="Array-prototype-forEach"><a href="#Array-prototype-forEach" class="headerlink" title="Array.prototype.forEach()"></a>Array.prototype.forEach()</h3><div class="note info"><p>为数组中的每个元素执行一次回调函数。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">2</span>,<span class="number">4</span>,<span class="number">6</span>,<span class="number">8</span>,<span class="number">10</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>;i<arr.length;i++){</span><br><span class="line"> <span class="built_in">console</span>.log(arr[i]) <span class="comment">// 2 4 6 8 10 </span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">arr.forEach(<span class="function">(<span class="params">element,index</span>) =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`<span class="subst">${index}</span> - <span class="subst">${element}</span>`</span>)</span><br><span class="line"> <span class="comment">// 0 - 2</span></span><br><span class="line"> <span class="comment">// 1 - 4</span></span><br><span class="line"> <span class="comment">// 2 - 6</span></span><br><span class="line"> <span class="comment">// 3 - 8</span></span><br><span class="line"> <span class="comment">// 4 - 10</span></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">// 注意: 没有办法中止或者跳出 forEach() 循环,除了抛出一个异常。如果你需要这样,使用 forEach() 方法是错误的。</span></span><br><span class="line"><span class="comment">// 若你需要提前终止循环,你可以使用:every()、some()、find()等,这些数组方法可以对数组元素判断,以便确定是否需要继续遍历</span></span><br><span class="line"><span class="comment">// 若条件允许,也可以使用 filter() 提前过滤出需要遍历的部分,再用 forEach() 处理。</span></span><br></pre></td></tr></table></figure><h3 id="Array-prototype-every"><a href="#Array-prototype-every" class="headerlink" title="Array.prototype.every()"></a>Array.prototype.every()</h3><div class="note info"><p>如果数组中的每个元素都满足测试函数,则返回 true,否则返回 false。空数组也是返回true。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">30</span>, <span class="number">39</span>, <span class="number">29</span>, , <span class="number">10</span>, <span class="number">13</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> isMatch = arr.every(<span class="function"><span class="params">element</span> =></span>{</span><br><span class="line"> <span class="keyword">return</span> element < <span class="number">40</span>;</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(isMatch) <span class="comment">// expected output: true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个使 callback 返回 false(表示可转换为布尔值 false 的值)的元素。</span></span><br><span class="line"><span class="comment">// 如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 true,every 就会返回 true。callback 只会为那些已经被赋值的索引调用,不会为那些被删除或从来没被赋值(空值)的索引调用。</span></span><br></pre></td></tr></table></figure><h3 id="Array-prototype-some"><a href="#Array-prototype-some" class="headerlink" title="Array.prototype.some()"></a>Array.prototype.some()</h3><div class="note info"><p>如果数组中至少有一个元素满足测试函数,则返回 true,否则返回 false。空数组也是返回false。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> hasEvenNumber = arr.some(<span class="function"><span class="params">element</span> =></span>{</span><br><span class="line"> <span class="keyword">return</span> element % <span class="number">2</span> === <span class="number">0</span>;</span><br><span class="line">});</span><br><span class="line"><span class="comment">// 存在偶数</span></span><br><span class="line"><span class="built_in">console</span>.log(hasEvenNumber); <span class="comment">// expected output: true</span></span><br></pre></td></tr></table></figure><h3 id="Array-prototype-filter"><a href="#Array-prototype-filter" class="headerlink" title="Array.prototype.filter()"></a>Array.prototype.filter()</h3><div class="note info"><p>将所有在过滤函数中返回 true 的数组元素放进一个新数组中并返回。如无任何数组元素通过测试,则返回空数组</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> words = [<span class="string">'spray'</span>, <span class="string">'limit'</span>, <span class="string">'elite'</span>, <span class="string">'exuberant'</span>, <span class="string">'destruction'</span>, <span class="string">'present'</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> result = words.filter(<span class="function"><span class="params">word</span> =></span> word.length > <span class="number">6</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(result); <span class="comment">// expected output: ["exuberant", "destruction", "present"]</span></span><br></pre></td></tr></table></figure><h3 id="Array-prototype-map"><a href="#Array-prototype-map" class="headerlink" title="Array.prototype.map()"></a>Array.prototype.map()</h3><div class="note info"><p>返回一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">4</span>, <span class="number">9</span>, <span class="number">16</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// pass a function to map</span></span><br><span class="line"><span class="keyword">const</span> map = arr.map(<span class="function"><span class="params">x</span> =></span> x * <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(map); <span class="comment">// expected output: Array [2, 8, 18, 32]</span></span><br></pre></td></tr></table></figure><h3 id="Array-prototype-reduce"><a href="#Array-prototype-reduce" class="headerlink" title="Array.prototype.reduce()"></a>Array.prototype.reduce()</h3><div class="note info"><p>从左到右为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值。</p></div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 一、将数组中的值累乘</span></span><br><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> res = arr.reduce(<span class="function">(<span class="params">accumulator,element</span>) =></span>{</span><br><span class="line"> <span class="keyword">return</span> accumulator * element</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(res); <span class="comment">// expected output: 24</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 二、计算数组中每个元素出现的次数</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> names = [<span class="string">'Alice'</span>, <span class="string">'Bob'</span>, <span class="string">'Tiff'</span>, <span class="string">'Bruce'</span>, <span class="string">'Alice'</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> countedNames = names.reduce(<span class="function">(<span class="params">allNames, name</span>) =></span>{</span><br><span class="line"> <span class="keyword">if</span> (name <span class="keyword">in</span> allNames) {</span><br><span class="line"> allNames[name]++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> allNames[name] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> allNames;</span><br><span class="line">},{});</span><br><span class="line"><span class="built_in">console</span>.log(countedNames) <span class="comment">// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// initialValue可选,此例中initialValue为{}</span></span><br><span class="line"><span class="comment">// 作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。在没有初始值的空数组上调用 reduce 将报错。</span></span><br></pre></td></tr></table></figure><h3 id="Array-prototype-reduceRight"><a href="#Array-prototype-reduceRight" class="headerlink" title="Array.prototype.reduceRight()"></a>Array.prototype.reduceRight()</h3><div class="note info"><p>同上,不过遍历顺序变成了从右到左</p></div><hr><p>参考文章:<br>《Array MDN文档》<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array" target="_blank" rel="noopener">https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array</a></p>]]></content>
<summary type="html">
Javascript的数组提供了非常多有用的方法,同时也使得Javascript更有函数式编程的味道。之前基本都是模糊地在使用他们,而且用的也很浅,所以这回我准备好好的认识认识他们。将他们进行一个分类,以及应用场景的归纳,争取融会贯通到我日常的编程当中~
</summary>
<category term="Javascript" scheme="JasonLam0990.github.io/categories/Javascript/"/>
<category term="数组" scheme="JasonLam0990.github.io/tags/%E6%95%B0%E7%BB%84/"/>
</entry>
<entry>
<title>如何写出逻辑清晰简洁,好维护的Javascript代码?</title>
<link href="JasonLam0990.github.io/2019/04/10/%E5%A6%82%E4%BD%95%E5%86%99%E5%87%BA%E9%80%BB%E8%BE%91%E6%B8%85%E6%99%B0%E7%AE%80%E6%B4%81%EF%BC%8C%E5%A5%BD%E7%BB%B4%E6%8A%A4%E7%9A%84Javascript%E4%BB%A3%E7%A0%81%EF%BC%9F/"/>
<id>JasonLam0990.github.io/2019/04/10/如何写出逻辑清晰简洁,好维护的Javascript代码?/</id>
<published>2019-04-10T01:59:14.000Z</published>
<updated>2019-04-13T08:41:53.705Z</updated>
<content type="html"><![CDATA[<h1 id="一、代码简洁、逻辑清晰"><a href="#一、代码简洁、逻辑清晰" class="headerlink" title="一、代码简洁、逻辑清晰"></a>一、代码简洁、逻辑清晰</h1><hr><h2 id="使用ES6新特性"><a href="#使用ES6新特性" class="headerlink" title="使用ES6新特性"></a>使用ES6新特性</h2><ul><li><p>字符串连接使用模板字符串 ` 和 ${} 代替 传统+</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> name = <span class="string">'jasonlam'</span></span><br><span class="line"><span class="keyword">let</span> time = <span class="string">'8:00'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// bad code</span></span><br><span class="line"><span class="keyword">let</span> message = <span class="string">'hello '</span> + name + <span class="string">', it\'s '</span> + time +<span class="string">' now'</span></span><br><span class="line"><span class="built_in">console</span>.log(message) <span class="comment">// hello jasonlam, it's 8:00 now</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// good code</span></span><br><span class="line"><span class="keyword">let</span> message = <span class="string">`hello <span class="subst">${name}</span>, it's <span class="subst">${time}</span> now`</span></span><br><span class="line"><span class="built_in">console</span>.log(message) <span class="comment">// hello jasonlam, it's 8:00 now</span></span><br></pre></td></tr></table></figure></li><li><p>使用解构赋值</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 一、简洁明了地获取对象、数组、函数return中的值</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> data = { <span class="attr">name</span>: <span class="string">'jasonlam'</span>, <span class="attr">age</span>: <span class="number">22</span> };</span><br><span class="line"></span><br><span class="line"><span class="comment">// bad code</span></span><br><span class="line"><span class="keyword">let</span> name = data.name; <span class="comment">// jasonlam</span></span><br><span class="line"><span class="keyword">let</span> age = data.age; <span class="comment">// 22</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// good code</span></span><br><span class="line"><span class="keyword">const</span> { name, age } = data; <span class="comment">// 简单明了</span></span><br><span class="line"><span class="built_in">console</span>.log(name) <span class="comment">// jasonlam</span></span><br><span class="line"><span class="built_in">console</span>.log(age) <span class="comment">// 22</span></span><br><span class="line"></span><br><span class="line">--------------------------------------------</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fullName = [<span class="string">'jason'</span>, <span class="string">'lam'</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// bad code</span></span><br><span class="line"><span class="keyword">let</span> firstName = fullName[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">let</span> lastName = fullName[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// good code</span></span><br><span class="line"><span class="keyword">const</span> [firstName, lastName] = fullName;</span><br><span class="line"><span class="built_in">console</span>.log(firstName) <span class="comment">// jason</span></span><br><span class="line"><span class="built_in">console</span>.log(lastName) <span class="comment">// lam</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 二、交换变量的值</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> x = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">let</span> y = <span class="number">2</span>;</span><br><span class="line">[x, y] = [y, x];</span><br><span class="line"></span><br><span class="line"><span class="comment">// 三、遍历Map结构</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> map = <span class="keyword">new</span> <span class="built_in">Map</span>();</span><br><span class="line">map.set(<span class="string">'first'</span>, <span class="string">'hello'</span>);</span><br><span class="line">map.set(<span class="string">'second'</span>, <span class="string">'world'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> [key, value] <span class="keyword">of</span> map) {</span><br><span class="line"> <span class="built_in">console</span>.log(key + <span class="string">" is "</span> + value);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// first is hello</span></span><br><span class="line"><span class="comment">// second is world</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 四、加载模块的指定方法</span></span><br><span class="line"><span class="comment">// 加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> { SourceMapConsumer, SourceNode } = <span class="built_in">require</span>(<span class="string">"source-map"</span>)</span><br></pre></td></tr></table></figure></li><li><p>ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面</p></li><li>尾调用优化 - 尾递归,递归函数改写 - 函数curry化、参数默认值</li></ul><h1 id="二、可维护性"><a href="#二、可维护性" class="headerlink" title="二、可维护性"></a>二、可维护性</h1><hr><h2 id="变量相关"><a href="#变量相关" class="headerlink" title="变量相关"></a>变量相关</h2><ul><li>数据只使用一次或不使用就无需装到变量中(没用的就删除掉,不然过久了自己都不敢删,怕是不是哪里会用到)</li><li>变量命名最好字面上就要看得懂并且尽可能简洁不啰嗦,别搞那些花里胡哨的</li><li>特定的数值(参数)最好放在变量里并且要命名好,在JS与CSS预处理器(如Less or Sass)都有用武之地</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// JS Bad Code:</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(value.length < <span class="number">8</span>){</span><br><span class="line"><span class="comment">// 为什么要小于8,8表示的是什么?长度,还是位移,还是高度?Oh,my God!!</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// JS Good Code</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> MAX_INPUT_LENGTH = <span class="number">8</span>;</span><br><span class="line"><span class="keyword">if</span> (value.length < MAX_INPUT_LENGTH) { </span><br><span class="line"><span class="comment">// 一目了然,判断中表示的是不能超过最大输入长度 </span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 这部分的代码并不具有很强的代表性,但就是希望告诉你可以这么做</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Less Bad Code</span></span><br><span class="line"><span class="selector-class">.text-line</span> {</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="number">20px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.banner</span> {</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="number">60px</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Less Good Code</span></span><br><span class="line"><span class="variable">@Banner_LINE_HEIGHT:</span> <span class="number">20px</span>;</span><br><span class="line"><span class="selector-class">.text-line</span> {</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="variable">@Banner_LINE_HEIGHT</span>; <span class="comment">// 1行的高度</span></span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.banner</span> {</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="variable">@Banner_LINE_HEIGHT</span> * <span class="number">3</span>; <span class="comment">// 3行的高度</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="函数相关"><a href="#函数相关" class="headerlink" title="函数相关"></a>函数相关</h2><ul><li>从函数名就可以知道返回值的类型,对于返回<code>true or false</code>的函数,最好以<code>should/is/can/has</code>开头</li><li>功能函数最好为纯函数,一个函数完成一个独立的功能,不要一个函数混杂多个功能</li><li>动作函数要以动词开头,如<code>send/add/delete</code></li><li>优先使用函数式编程</li></ul><hr><p>参考文章:<br>《看看这些被同事喷的JS代码风格你写过多少》 <a href="https://github.com/jackiewillen/blog/issues/14" target="_blank" rel="noopener">https://github.com/jackiewillen/blog/issues/14</a><br>《ECMAScript 6 入门》—— 阮一峰 <a href="http://es6.ruanyifeng.com/" target="_blank" rel="noopener">http://es6.ruanyifeng.com/</a></p>]]></content>
<summary type="html">
其实严格来讲,我还没有足够的资历去写这样一篇文章。有感于看大佬们的一些文章和代码,感觉到能写出逻辑清晰简洁,好维护的Javascript代码是一件类似于习惯养成的事,所以我想借写这篇文章的机会,将那些能使得代码逻辑清晰,提高代码可维护性的相关技巧总结一下~
</summary>
<category term="代码规范" scheme="JasonLam0990.github.io/categories/%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83/"/>
<category term="数组" scheme="JasonLam0990.github.io/tags/%E6%95%B0%E7%BB%84/"/>
<category term="ES6" scheme="JasonLam0990.github.io/tags/ES6/"/>
<category term="代码规范" scheme="JasonLam0990.github.io/tags/%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83/"/>
</entry>
<entry>
<title>微信事业群面试题:HardMan (LazyMan) </title>
<link href="JasonLam0990.github.io/2019/04/02/%E5%BE%AE%E4%BF%A1%E4%BA%8B%E4%B8%9A%E7%BE%A4%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%9AHardMan-LazyMan/"/>
<id>JasonLam0990.github.io/2019/04/02/微信事业群面试题:HardMan-LazyMan/</id>
<published>2019-04-02T07:01:17.000Z</published>
<updated>2019-04-02T14:34:38.018Z</updated>
<content type="html"><![CDATA[<blockquote class="blockquote-center"><h1 id="题目重述"><a href="#题目重述" class="headerlink" title="题目重述"></a>题目重述</h1><hr><p>实现一个 HardMan:<br> HardMan(“jack”) 输出:<br> I am jack</p><p>HardMan(“jack”).rest(10).learn(“computer”) 输出<br>I am jack<br>//等待10秒<br>Start learning after 10 seconds<br>Learning computer</p><p>HardMan(“jack”).restFirst(5).learn(“chinese”) 输出<br>//等待5秒<br>Start learning after 5 seconds<br>I am jack<br>Learning chinese</p></blockquote><h1 id="方法一、使用-纯Callbacks-调用"><a href="#方法一、使用-纯Callbacks-调用" class="headerlink" title="方法一、使用 纯Callbacks 调用"></a>方法一、使用 纯Callbacks 调用</h1><h2 id="主要涉及到的知识点"><a href="#主要涉及到的知识点" class="headerlink" title="主要涉及到的知识点"></a>主要涉及到的知识点</h2><ul><li>1.使用ES6中的箭头函数可规避this指向的问题,否则需要用bind来绑定</li><li>2.setTimeout异步事件,会在同步事件执行完后再开始执行</li><li>3.实现链式调用,函数返回this即可</li><li>4.队列的使用</li><li>5.运用了类和面向对象的编程思想</li></ul><h2 id="代码展示"><a href="#代码展示" class="headerlink" title="代码展示"></a>代码展示</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">_HardMan</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>(name) {</span><br><span class="line"> <span class="keyword">this</span>.tasks = [];</span><br><span class="line"> <span class="comment">// 很关键的一步, setTimeout为异步任务,这样可以使得所有的任务入队以后,才开始执行第一个next函数,主要是考虑了restFirst的情况</span></span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.next())</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`I am <span class="subst">${name}</span>`</span>)</span><br><span class="line"> <span class="keyword">this</span>.next()</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> next() {</span><br><span class="line"> <span class="keyword">let</span> task = <span class="keyword">this</span>.tasks.shift()</span><br><span class="line"> task && task()</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> learn(params) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`Learning <span class="subst">${params}</span>`</span>)</span><br><span class="line"> <span class="keyword">this</span>.next()</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wait(sec) {</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`Start learning after <span class="subst">${sec}</span> seconds`</span>)</span><br><span class="line"> <span class="keyword">this</span>.next()</span><br><span class="line"> }, sec * <span class="number">1000</span>);</span><br><span class="line"> }</span><br><span class="line"> waitPrint(sec) {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`//等待<span class="subst">${sec}</span>秒..`</span>)</span><br><span class="line"> <span class="keyword">this</span>.next()</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> rest(sec) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="keyword">this</span>.waitPrint(sec))</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="keyword">this</span>.wait(sec))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> restFirst(sec) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.unshift(<span class="keyword">this</span>.wait(sec))</span><br><span class="line"> <span class="keyword">this</span>.tasks.unshift(<span class="keyword">this</span>.waitPrint(sec))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> HardMan = <span class="function"><span class="keyword">function</span> (<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> _HardMan(name)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">HardMan(<span class="string">"jack"</span>).restFirst(<span class="number">5</span>).learn(<span class="string">"chinese"</span>)</span><br><span class="line"><span class="comment">// //等待5秒..</span></span><br><span class="line"><span class="comment">// Start learning after 5 seconds</span></span><br><span class="line"><span class="comment">// I am jack</span></span><br><span class="line"><span class="comment">// Learning chinese</span></span><br><span class="line"></span><br><span class="line">HardMan(<span class="string">"jack"</span>).rest(<span class="number">3</span>).learn(<span class="string">"computer"</span>)</span><br><span class="line"><span class="comment">// //等待3秒..</span></span><br><span class="line"><span class="comment">// I am jack</span></span><br><span class="line"><span class="comment">// Start learning after 3 seconds</span></span><br></pre></td></tr></table></figure><hr><h1 id="方法二、使用-Promise-amp-Queue"><a href="#方法二、使用-Promise-amp-Queue" class="headerlink" title="方法二、使用 Promise & Queue"></a>方法二、使用 Promise & Queue</h1><h2 id="主要涉及到的知识点-1"><a href="#主要涉及到的知识点-1" class="headerlink" title="主要涉及到的知识点"></a>主要涉及到的知识点</h2><ul><li>利用了Promise的异步特性</li></ul><h2 id="代码展示-1"><a href="#代码展示-1" class="headerlink" title="代码展示"></a>代码展示</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">_HardMan</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span> (name) {</span><br><span class="line"> <span class="keyword">this</span>.tasks = [];</span><br><span class="line"> <span class="comment">// 很关键的一步, setTimeout为异步任务,这样可以使得所有的任务入队以后,才开始执行第一个next函数,主要是考虑了restFirst的情况</span></span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.next());</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span> </span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`I am <span class="subst">${name}</span>`</span>)</span><br><span class="line"> resolve()</span><br><span class="line"> })</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> <span class="comment">//其实这里可以不用return this,因为调用构造函数没有更改this的指向</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> next () {</span><br><span class="line"> <span class="keyword">let</span> task = <span class="keyword">this</span>.tasks.shift();</span><br><span class="line"> task && task().then(<span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.next());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> rest(sec) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span></span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`//等待<span class="subst">${sec}</span>秒..`</span>)</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`Start learning after <span class="subst">${sec}</span> seconds`</span>)</span><br><span class="line"> resolve()</span><br><span class="line"> }, sec * <span class="number">1000</span>);</span><br><span class="line"> })</span><br><span class="line"> )</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> restFirst (sec) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.unshift(<span class="function"><span class="params">()</span> =></span></span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`//等待<span class="subst">${sec}</span>秒..`</span>)</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`Start learning after <span class="subst">${sec}</span> seconds`</span>)</span><br><span class="line"> resolve()</span><br><span class="line"> }, sec * <span class="number">1000</span>);</span><br><span class="line"> })</span><br><span class="line"> )</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> learn(params) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span> </span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`Learning <span class="subst">${params}</span>`</span>)</span><br><span class="line"> resolve()</span><br><span class="line"> })</span><br><span class="line"> )</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> HardMan = <span class="function"><span class="keyword">function</span> (<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> _HardMan(name)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">HardMan(<span class="string">"jack"</span>).restFirst(<span class="number">3</span>).learn(<span class="string">"Chinese"</span>).learn(<span class="string">"Englsih"</span>).rest(<span class="number">2</span>).learn(<span class="string">"Japanese"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// //等待3秒..</span></span><br><span class="line"><span class="comment">// Start learning after 3 seconds</span></span><br><span class="line"><span class="comment">// I am jack</span></span><br><span class="line"><span class="comment">// Learning Chinese</span></span><br><span class="line"><span class="comment">// Learning Englsih</span></span><br><span class="line"><span class="comment">// //等待2秒..</span></span><br><span class="line"><span class="comment">// Start learning after 2 seconds</span></span><br><span class="line"><span class="comment">// Learning Japanese</span></span><br></pre></td></tr></table></figure><h2 id="使用-Async-Await-对方法二进行优化"><a href="#使用-Async-Await-对方法二进行优化" class="headerlink" title="使用 Async/Await 对方法二进行优化"></a>使用 Async/Await 对方法二进行优化</h2><p>首先我们可以简单地优化一下,将重复的代码用wait抽象出来</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">wait(sec) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`//等待<span class="subst">${sec}</span>秒..`</span>)</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`Start learning after <span class="subst">${sec}</span> seconds`</span>)</span><br><span class="line"> resolve()</span><br><span class="line"> }, sec * <span class="number">1000</span>);</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">rest(sec) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.wait(sec))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">restFirst(sec) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.unshift(<span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.wait(sec))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后删除掉next方法,tasks队列中使用Async/Await顺序执行取代<code>this.next()</code>即可</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">setTimeout(<span class="keyword">async</span> () => {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> task <span class="keyword">of</span> <span class="keyword">this</span>.tasks) {</span><br><span class="line"> <span class="keyword">await</span> task()</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>最终代码</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">_HardMan</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>(name) {</span><br><span class="line"> <span class="keyword">this</span>.tasks = [];</span><br><span class="line"> <span class="comment">// 很关键的一步, setTimeout为异步任务,这样可以使得所有的任务入队以后,才开始执行第一个next函数,主要是考虑了restFirst的情况</span></span><br><span class="line"> setTimeout(<span class="keyword">async</span> () => {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> task <span class="keyword">of</span> <span class="keyword">this</span>.tasks) {</span><br><span class="line"> <span class="keyword">await</span> task()</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span></span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`I am <span class="subst">${name}</span>`</span>)</span><br><span class="line"> resolve()</span><br><span class="line"> })</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> <span class="comment">//其实这里可以不用return this,因为调用构造函数没有更改this的指向</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wait(sec) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`//等待<span class="subst">${sec}</span>秒..`</span>)</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`Start learning after <span class="subst">${sec}</span> seconds`</span>)</span><br><span class="line"> resolve()</span><br><span class="line"> }, sec * <span class="number">1000</span>);</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> rest(sec) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.wait(sec))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> restFirst(sec) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.unshift(<span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.wait(sec))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> learn(params) {</span><br><span class="line"> <span class="keyword">this</span>.tasks.push(<span class="function"><span class="params">()</span> =></span></span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`Learning <span class="subst">${params}</span>`</span>)</span><br><span class="line"> resolve()</span><br><span class="line"> })</span><br><span class="line"> )</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> HardMan = <span class="function"><span class="keyword">function</span> (<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> _HardMan(name)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">HardMan(<span class="string">"jack"</span>).restFirst(<span class="number">3</span>).learn(<span class="string">"Chinese"</span>).learn(<span class="string">"Englsih"</span>).rest(<span class="number">2</span>).learn(<span class="string">"Japanese"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// //等待3秒..</span></span><br><span class="line"><span class="comment">// Start learning after 3 seconds</span></span><br><span class="line"><span class="comment">// I am jack</span></span><br><span class="line"><span class="comment">// Learning Chinese</span></span><br><span class="line"><span class="comment">// Learning Englsih</span></span><br><span class="line"><span class="comment">// //等待2秒..</span></span><br><span class="line"><span class="comment">// Start learning after 2 seconds</span></span><br><span class="line"><span class="comment">// Learning Japanese</span></span><br></pre></td></tr></table></figure><blockquote class="blockquote-center"><h1 id="题外话-浏览器Event-Loop"><a href="#题外话-浏览器Event-Loop" class="headerlink" title="题外话 : 浏览器Event Loop"></a>题外话 : 浏览器Event Loop</h1><hr><p>首先区分是同步事件还是异步事件?<br>如果是异步事件,是宏事件还是微事件?<br>宏事件:整体代码script,setTimeout,setInterval<br>微事件:Promise.then,process.nextTick<br>参考:<a><a href="https://juejin.im/post/59e85eebf265da430d571f89" target="_blank" rel="noopener">https://juejin.im/post/59e85eebf265da430d571f89</a></a></p></blockquote>]]></content>
<summary type="html">
这道题是面试腾讯暑期实习生时,被WXG捞起来视频面时做的一道题,当时一脸懵逼,想了好一会,不过确实是不会做。主要是因为当时对类的使用以及Promise的掌握都还不够熟练,今天刚好想到这道题,于是翻出来好好地做了一下!
</summary>
<category term="面试题" scheme="JasonLam0990.github.io/categories/%E9%9D%A2%E8%AF%95%E9%A2%98/"/>
<category term="链式调用" scheme="JasonLam0990.github.io/tags/%E9%93%BE%E5%BC%8F%E8%B0%83%E7%94%A8/"/>
<category term="类和面向对象" scheme="JasonLam0990.github.io/tags/%E7%B1%BB%E5%92%8C%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/"/>
<category term="Promise" scheme="JasonLam0990.github.io/tags/Promise/"/>
</entry>
<entry>
<title>Http与Https的区别及其过程</title>
<link href="JasonLam0990.github.io/2019/03/27/Http%E4%B8%8EHttps%E5%BF%85%E7%9F%A5%E5%BF%85%E4%BC%9A/"/>
<id>JasonLam0990.github.io/2019/03/27/Http与Https必知必会/</id>
<published>2019-03-27T02:07:14.000Z</published>
<updated>2019-03-27T16:46:20.490Z</updated>
<content type="html"><![CDATA[<h1 id="HTTP"><a href="#HTTP" class="headerlink" title="HTTP"></a>HTTP</h1><p>HTTP(Hyper Text Transfer Protocol,超文本传输协议),主要被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。</p><h2 id="HTTP的特点"><a href="#HTTP的特点" class="headerlink" title="HTTP的特点"></a>HTTP的特点</h2><ul><li>默认采用80作为通讯端口</li><li>HTTP是<strong>无状态</strong>的,即同一个客户端第二次访问同一个服务器上的页面时,服务器无法知道这个客户端曾经访问过,服务器也无法分辨不同的客户端。HTTP 的无状态特性简化了服务器的设计,使服务器更容易支持大量并发的HTTP请求。(如果希望保持状态,可以通过引入cookie和session)</li><li>HTTP是<strong>无连接</strong>的,即限制每次连接只处理一个请求。服务器处理完客户的请求并响应后,就断开连接。采用这种方式可以节省传输时间,同时可以尽快将服务器资源释放出来服务其他的客户端。</li></ul><h2 id="HTTP的缺点"><a href="#HTTP的缺点" class="headerlink" title="HTTP的缺点"></a>HTTP的缺点</h2><ul><li>窃听风险:HTTP所封装的信息是明文的,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息</li><li>篡改风险:无法证明报文的完整性, 攻击者可能已经截获并对报文进行了修改。</li><li>冒充风险:客户端与服务器之间没有任何身份确认的过程,无法保证通信双方的身份,攻击者可以冒充他人身份参与通信。</li></ul><hr><h1 id="HTTPS"><a href="#HTTPS" class="headerlink" title="HTTPS"></a>HTTPS</h1><p>HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer),可以理解为HTTP+SSL/TLS, 即 <strong>HTTPS是运行在SSL/TLS之上的HTTP协议</strong>。HTTPS是可以进行加密传输、报文完整性校验、身份认证的网络协议,比HTTP协议要更加安全。</p><p>引用《图解HTTP》中的话来说:<strong>HTTP+加密+认证+完整性保护=HTTPS</strong></p><h2 id="HTTPS的特点"><a href="#HTTPS的特点" class="headerlink" title="HTTPS的特点"></a>HTTPS的特点</h2><ul><li>默认采用443作为通讯端口</li><li>所有信息都是加密传播,第三方无法窃听</li><li>具有校验机制,一旦被篡改,通信双方会立刻发现</li><li>配备身份证书,可防止身份被冒充</li></ul><h2 id="HTTPS的缺点"><a href="#HTTPS的缺点" class="headerlink" title="HTTPS的缺点"></a>HTTPS的缺点</h2><ul><li>HTTPS的页面响应速度比HTTP要慢,主要是因为HTTPS在HTTP的基础上还需要进行一系列的加解密过程,这个过程会需要一定的时间</li><li>HTTPS涉及到的安全算法会消耗 CPU 资源,会增加服务器的负担</li><li>使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。(如果全站升HTTPS了,相应的CDN也需要使用HTTPS的,价格也会比HTTP的要贵一些)</li></ul><hr><h1 id="HTTPS的原理"><a href="#HTTPS的原理" class="headerlink" title="HTTPS的原理"></a>HTTPS的原理</h1><p>SSL/TLS协议的基本思路是采用公钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。但同时为了减少耗用的时间,HTTPS 采用共享密钥加密(对称加密)和公开密钥加密(非对称加密)两者并用的混合加密机制。</p><p>总的来说就是三步:<br>(1) 客户端向服务器端索要并验证公钥。<br>(2) 双方协商生成”对话密钥”。<br>(3) 双方采用”对话密钥”进行加密通信。</p><p>Question & Answer<br>(1)如何保证公钥不被篡改?<br> 解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。<br>(2)公钥加密计算量太大,如何减少耗用的时间?<br> 每一次对话(session),客户端和服务器端都生成一个”对话密钥”(session key),用它来加密信息。由于”对话密钥”是对称加密,所以运算速度非常快,而服务器公钥只用于加密”对话密钥”(session key)本身,这样就减少了加密运算的消耗时间。</p><h2 id="一起理清几个概念"><a href="#一起理清几个概念" class="headerlink" title="一起理清几个概念"></a>一起理清几个概念</h2><ul><li>对称加密:加密和解密都是使用的同一个密钥(DES、AES-GCM算法等)</li><li>非对称加密:加密使用的密钥和解密使用的密钥是不相同的,分别称为:公钥、私钥,公钥和算法都是公开的,而私钥是保密的。非对称加密算法性能较低,但是安全性比较强,由于其加密特性,非对称加密算法能加密的数据长度也是有限的(RSA、DSA算法等)</li><li>哈希算法:将任意长度的信息转换为较短的固定长度的值,通常其长度要比信息小得多,且算法不可逆(MD5、SHA-1算法等)</li><li>数字签名:数字签名就是在待传送的信息后面再加上一段内容(待传送的信息经过hash后的值),hash值一般都会加密后(也就是数字签名)再和信息一起发送,以保证这个hash值不被修改,以此证明信息没有被修改过。</li><li>生成”对话密钥”(session key)一共需要三个随机数。</li><li>服务器的公钥和私钥只在加密和解密”对话密钥”(非对称加密)时使用,握手之后的对话使用”对话密钥”(session key)加密(对称加密),不会再使用到服务器的公钥和私钥了。</li><li>服务器公钥(public key)放在服务器的数字证书之中。</li></ul><h1 id="SSL握手详细的步骤"><a href="#SSL握手详细的步骤" class="headerlink" title="SSL握手详细的步骤"></a>SSL握手详细的步骤</h1><p><img src="http://www.ruanyifeng.com/blogimg/asset/2014/bg2014092003.png" alt="图来自与阮一峰博客"></p><p>1.(ClientHello)客户端向服务器发起HTTPS请求,连接到服务器的443端口。在这一步,客户端主要向服务器提供以下信息。</p><ul><li>客户端支持的协议版本,比如TLS 1.0版</li><li>客户端支持的加密方法,比如RSA公钥加密</li><li>客户端支持的压缩方法</li><li>一个客户端生成的随机数(public random),稍后用于生成”对话密钥”(session key)</li></ul><p>2.(SeverHello)服务器收到客户端请求后,向客户端发出回应,回应包含以下内容</p><ul><li>确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。</li><li>确认使用的加密方法,比如RSA公钥加密</li><li>服务器证书(证书中包含了服务器公钥public key)</li><li>一个服务器生成的随机数(server random),稍后用于生成”对话密钥”(session key)</li></ul><p>3.客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。<br>如果证书没有问题,客户端就会从证书中取出服务器的公钥(public key)。然后,生成一个随机数,我们将该随机数称之为client key,即客户端密钥。该随机数(client key)用服务器公钥(public key)进行非对称加密,这样客户端密钥(client key)就变成密文了,可以防止被窃听。此时,客户端会发起HTTPS中的第二个HTTP请求,将加密之后的客户端密钥(client key)发送给服务器。</p><p>4.服务器收到加密之后的客户端密钥(client key)之后,会用自己的服务器私钥对其进行非对称解密,解密之后的明文就是客户端密钥(client key)。有了它以后,客户端和服务器就同时都有了三个随机数(public random, server random, client key),接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把”会话密钥”(session key)</p><p>5.之后客户端与服务器的通信都使用”会话密钥”(session key)对需要传输的数据进行对称加解密,这样要传输的数据就变成了密文,第三方无法窃听。</p><p>至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用”会话密钥”(session key)加密了需要传输的内容。</p><p>整个握手阶段都不加密(也没法加密),都是明文的。因此,如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(client key)能不能被破解。</p><hr><p>参考文章:<br>《图解SSL/TLS协议》<a href="http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html" target="_blank" rel="noopener">http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html</a><br>《SSL/TLS协议运行机制的概述》<a href="http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html" target="_blank" rel="noopener">http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html</a><br>《HTTPS理论基础及其在Android中的最佳实践》<a href="https://blog.csdn.net/iispring/article/details/51615631" target="_blank" rel="noopener">https://blog.csdn.net/iispring/article/details/51615631</a></p>]]></content>
<summary type="html">
无论是日常Web开发中,还是面试中,熟练掌握基础的计算机网络知识是非常必要的,说到网络基础,当然绕不开HTTP与HTTPS了,他们的区别,发起请求的过程等等,接下来就由我给你娓娓道来~
</summary>
<category term="计算机网络" scheme="JasonLam0990.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
<category term="HTTP & HTTPS" scheme="JasonLam0990.github.io/tags/HTTP-HTTPS/"/>
</entry>
<entry>
<title>动态规划其实也不难</title>
<link href="JasonLam0990.github.io/2019/03/22/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E5%85%B6%E5%AE%9E%E4%B9%9F%E4%B8%8D%E9%9A%BE/"/>
<id>JasonLam0990.github.io/2019/03/22/动态规划其实也不难/</id>
<published>2019-03-21T16:27:48.000Z</published>
<updated>2019-03-21T16:28:21.451Z</updated>
<content type="html"><![CDATA[<div class="note default"><p>本文解题思维部分主要学习自“极客时间”的《算法面试通关40讲》专栏,加上了我一些自己的见解</p></div><hr><h1 id="动态规划解题思维"><a href="#动态规划解题思维" class="headerlink" title="动态规划解题思维"></a>动态规划解题思维</h1><ul><li>递归 + (递归中重复计算的部分)记忆化 = 递推</li><li>对状态的定义,比如<code>dp[n]</code>中的n代表的内容是什么,有时候根据题目还可能会用二维数组等,如<code>dp[i,j]</code></li><li>状态转移方程 指的是当前状态与前一个阶段状态的关系,如 <code>dp[n]=dp[n-1] + dp[n-2]</code>,类似于递推公式。在一些题型中还可能会涉及if-else判断</li><li>最优子结构指的是题目符合可以将问题分解为反复求解 前一个最优状态 + 当前状态 即可最终求出最优结果的一个结构</li></ul><hr><h1 id="回溯-VS-贪心-VS-DP"><a href="#回溯-VS-贪心-VS-DP" class="headerlink" title="回溯 VS 贪心 VS DP"></a>回溯 VS 贪心 VS DP</h1><ul><li>回溯(递归) —— 存在重复计算 (当遇到不存在最优子结构的问题中,我们无法使用动态规划进行优化时,就只能使用回溯穷举所有可能)</li><li>贪心 —— 永远得到局部最优,贪心算法只顾眼前利益,不管后期的规划,在很多实际问题中应用较少。除非问题每次贪心能最终推得最优解。</li><li>DP —— 在回溯(递归)的基础上,通过记录局部最优子结构的值,减少重复计算</li></ul><hr><h1 id="解题思维展示"><a href="#解题思维展示" class="headerlink" title="解题思维展示"></a>解题思维展示</h1><ul><li>例题:林俊贤从起点走到终点,一次只能向下/右走一步,有多少种走法?(涂了粉色的格子不能走)</li></ul><p><img src="/images/pic.png" width="30%" height="30%"></p><h4 id="一、递归(但是会存在大量重复运算)——-思维一般是从上往下-从前往后运行"><a href="#一、递归(但是会存在大量重复运算)——-思维一般是从上往下-从前往后运行" class="headerlink" title="一、递归(但是会存在大量重复运算)—— 思维一般是从上往下/从前往后运行"></a>一、递归(但是会存在大量重复运算)—— 思维一般是从上往下/从前往后运行</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">countPaths</span>(<span class="params">grid,row,col</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(!validSquare)(grid,row,col) <span class="keyword">return</span> <span class="number">0</span> <span class="comment">//如果是石头</span></span><br><span class="line"> <span class="keyword">if</span>(isAtEnd)(grid,row,col) <span class="keyword">return</span> <span class="number">1</span> <span class="comment">//到了终点</span></span><br><span class="line"> <span class="keyword">return</span> countPaths(grid,row+<span class="number">1</span>,col) + countPaths(grid,row,col+<span class="number">1</span>)</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="二、DP-进行-优化,通过记录避免重复计算-——-思维一般是从下往上-从后往前运行"><a href="#二、DP-进行-优化,通过记录避免重复计算-——-思维一般是从下往上-从后往前运行" class="headerlink" title="二、DP 进行 优化,通过记录避免重复计算 —— 思维一般是从下往上/从后往前运行"></a>二、DP 进行 优化,通过记录避免重复计算 —— 思维一般是从下往上/从后往前运行</h4><ul><li><p>对状态的定义,使用<code>dp[i,j]</code>这样的二维数组来存储当前的最优解</p></li><li><p>状态转移方程<br><code>dp[i,j] = dp[i-1,j] + dp[i,j-1]</code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(grid[i,j]==<span class="string">'空地'</span>){</span><br><span class="line"> dp[i,j] = dp[i<span class="number">-1</span>,j] + dp[i,j<span class="number">-1</span>]</span><br><span class="line">}<span class="keyword">else</span>{</span><br><span class="line"> dp[i,j] = <span class="number">0</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>最优子结构 本题很容易看出具有最优子结构,也就是说当前位置的最优解取决于下方节点与右侧节点的最优解,下方节点与右侧节点同理,最终是取决于终点</p></li><li><p>初始状态 在grid的最下方一行和最右侧一行,由于都只能向右/向下走,所以都是只有一种走法</p></li></ul><hr><h1 id="动态规划经典问题"><a href="#动态规划经典问题" class="headerlink" title="动态规划经典问题"></a>动态规划经典问题</h1><h2 id="一、最长公共子序列"><a href="#一、最长公共子序列" class="headerlink" title="一、最长公共子序列"></a>一、最长公共子序列</h2><ul><li>思路:首先定义状态<code>dp[i][j]</code>为字符串a1,a2…ai与字符串 b1,b2…bj的最长公共子序列的长度,经过分析可以得到相应的三条公式,具体的我这里就不赘述了,网上有许多关于这个问题的讲解,这里就贴一下我用Javascript实现的代码。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = <span class="string">'xyxxzxyzxy'</span></span><br><span class="line"><span class="keyword">let</span> b = <span class="string">'zxzyyzxxyxxz'</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">lcs</span>(<span class="params">a, b</span>) </span>{</span><br><span class="line"> <span class="comment">// 初始化dp表格二维数组</span></span><br><span class="line"> <span class="keyword">let</span> n = a.length</span><br><span class="line"> <span class="keyword">let</span> m = b.length</span><br><span class="line"> <span class="keyword">let</span> dp = <span class="keyword">new</span> <span class="built_in">Array</span>(n+<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < n + <span class="number">1</span>; i++) {</span><br><span class="line"> dp[i] = <span class="keyword">new</span> <span class="built_in">Array</span>(m+<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j < m + <span class="number">1</span>; j++) {</span><br><span class="line"> dp[i][j] = <span class="number">0</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 开始填表,由于i,j是为了dp数组所以从1开始,所以对应的字符串的位置应为i-1和j-1</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i < n+<span class="number">1</span>;i++){</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">1</span>; j < m+<span class="number">1</span> ;j++){</span><br><span class="line"> <span class="keyword">if</span>(a[i<span class="number">-1</span>] == b[j<span class="number">-1</span>]){</span><br><span class="line"> dp[i][j] = dp[i<span class="number">-1</span>][j<span class="number">-1</span>] + <span class="number">1</span></span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> dp[i][j] = <span class="built_in">Math</span>.max(dp[i - <span class="number">1</span>][j], dp[i][j<span class="number">-1</span>])</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 输出lcs长度并使用递归的方法找出其中一个lcs</span></span><br><span class="line"> <span class="keyword">return</span>{</span><br><span class="line"> length: dp[n][m],</span><br><span class="line"> lcs: printLCS(dp, a, b, n, m)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printLCS</span>(<span class="params">dp, str1, str2, i, j</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (i == <span class="number">0</span> || j == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">""</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (str1[i - <span class="number">1</span>] == str2[j - <span class="number">1</span>]) {</span><br><span class="line"> <span class="keyword">return</span> printLCS(dp, str1, str2, i - <span class="number">1</span>, j - <span class="number">1</span>) + str1[i - <span class="number">1</span>];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (dp[i][j - <span class="number">1</span>] > dp[i - <span class="number">1</span>][j]) {</span><br><span class="line"> <span class="keyword">return</span> printLCS(dp, str1, str2, i, j - <span class="number">1</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> printLCS(dp, str1, str2, i - <span class="number">1</span>, j);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(lcs(a, b)) <span class="comment">// { length: 6, lcs: 'xyxxxz' }</span></span><br></pre></td></tr></table></figure><h2 id="二、01背包问题(指的是背包不可包含一个以上同类物品)"><a href="#二、01背包问题(指的是背包不可包含一个以上同类物品)" class="headerlink" title="二、01背包问题(指的是背包不可包含一个以上同类物品)"></a>二、01背包问题(指的是背包不可包含一个以上同类物品)</h2><ul><li>思路:<code>dp[i,j]</code>指的是在j容量下,前i个物品所能得到的最大价值</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// capacity</span></span><br><span class="line"><span class="keyword">let</span> c = <span class="number">9</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> size = [<span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line"><span class="keyword">let</span> value = [<span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">7</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">// 不超过背包容量的前提下,尽可能多的装物品,使总价值最大</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">package</span>(<span class="params">c,size,value</span>)</span>{</span><br><span class="line"> <span class="comment">// 初始化二维数组</span></span><br><span class="line"> <span class="keyword">let</span> n = size.length</span><br><span class="line"> <span class="keyword">let</span> m = value.length</span><br><span class="line"> <span class="keyword">let</span> dp = <span class="keyword">new</span> <span class="built_in">Array</span>(n + <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < n + <span class="number">1</span>; i++) {</span><br><span class="line"> dp[i] = <span class="keyword">new</span> <span class="built_in">Array</span>(c + <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j < c + <span class="number">1</span>; j++) {</span><br><span class="line"> dp[i][j] = <span class="number">0</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">console</span>.log(dp)</span><br><span class="line"> <span class="comment">// i为物品,j为容量,dp[i,j]指的是在j容量下,前i个物品所能得到的最大价值</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">1</span>;i<n+<span class="number">1</span>;i++){</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> j = <span class="number">1</span>;j<c+<span class="number">1</span>;j++){</span><br><span class="line"> dp[i][j] = dp[i - <span class="number">1</span>][j]<span class="comment">// 什么都不拿</span></span><br><span class="line"> <span class="keyword">if</span>(j>=size[i<span class="number">-1</span>]){</span><br><span class="line"> dp[i][j] = <span class="built_in">Math</span>.max(dp[i][j], dp[i - <span class="number">1</span>][j - size[i - <span class="number">1</span>]] + value[i - <span class="number">1</span>])</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">console</span>.log(dp[n][c]) <span class="comment">// 12</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">package(c, size, value)</span><br></pre></td></tr></table></figure><hr><h1 id="螺旋KO动态规划习题拳击赛"><a href="#螺旋KO动态规划习题拳击赛" class="headerlink" title="螺旋KO动态规划习题拳击赛"></a>螺旋KO动态规划习题拳击赛</h1><h2 id="一、最大子数组"><a href="#一、最大子数组" class="headerlink" title="一、最大子数组"></a>一、最大子数组</h2><div class="note info"><p>解法对应于Leetcode 53 Maximum SubArray</p></div><ul><li>思路:首先找状态转移方程,容易知道有<code>nums[i] = Math.max(nums[i], nums[i - 1] + nums[i])</code>,一个for循环,数组的位置就存储了对应下标位置可以有的最大子数组的值。但是题目需要我们返回的是最大值,所以我们需要一个额外的变量max来存储当前的最大值</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[]} nums</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> maxSubArray = <span class="function"><span class="keyword">function</span> (<span class="params">nums</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (nums.length == <span class="number">1</span>) <span class="keyword">return</span> nums[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">let</span> max = nums[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i < nums.length; i++) {</span><br><span class="line"> nums[i] = <span class="built_in">Math</span>.max(nums[i], nums[i - <span class="number">1</span>] + nums[i])</span><br><span class="line"> max = nums[i]>max ? nums[i] : max</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> max</span><br><span class="line">};</span><br></pre></td></tr></table></figure><hr><h2 id="二、乘积最大子数组"><a href="#二、乘积最大子数组" class="headerlink" title="二、乘积最大子数组"></a>二、乘积最大子数组</h2><div class="note info"><p>解法对应于Leetcode 152 Maximum Product SubArray</p></div><ul><li>思路:此题解法乍一看与上一题类似,很容易想到<code>dp[i] = Math.max(nums[i],dp[i-1] * nums[i])</code>,但是在实际操作的时候会发现当遇到的nums[i]为负时处理逻辑是不同的,需要分正负两种情况来作讨论,所以我们原先定的一维数组的<code>状态定义</code>是思考不周到的,所以我们加多一个维度,0和1各自代表正负来作区分,形成一个二维数组。之后就是与动态规划一样,for循环,然后比较,最终取正数数组中的最大值即可。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[]} nums</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> maxProduct = <span class="function"><span class="keyword">function</span> (<span class="params">nums</span>) </span>{</span><br><span class="line"> <span class="comment">// initialize the two-dimensional Array</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">let</span> dp = <span class="keyword">new</span> <span class="built_in">Array</span>(<span class="number">2</span>)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < dp.length; i++) {</span><br><span class="line"> dp[i] = <span class="keyword">new</span> <span class="built_in">Array</span>(nums.length)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 0 represents positive dimension, 1 represents negative dimension</span></span><br><span class="line"> </span><br><span class="line"> dp[<span class="number">0</span>][<span class="number">0</span>] = nums[<span class="number">0</span>]</span><br><span class="line"> dp[<span class="number">1</span>][<span class="number">0</span>] = nums[<span class="number">0</span>]</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i < nums.length; i++) {</span><br><span class="line"> dp[<span class="number">0</span>][i] = <span class="built_in">Math</span>.max(dp[<span class="number">0</span>][i - <span class="number">1</span>] * nums[i],dp[<span class="number">1</span>][i<span class="number">-1</span>] * nums[i], nums[i])</span><br><span class="line"> dp[<span class="number">1</span>][i] = <span class="built_in">Math</span>.min(dp[<span class="number">0</span>][i - <span class="number">1</span>] * nums[i],dp[<span class="number">1</span>][i<span class="number">-1</span>] * nums[i], nums[i])</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Math</span>.max(...dp[<span class="number">0</span>])</span><br><span class="line">};</span><br></pre></td></tr></table></figure><hr><h2 id="三、三角形的最小路径和"><a href="#三、三角形的最小路径和" class="headerlink" title="三、三角形的最小路径和"></a>三、三角形的最小路径和</h2><div class="note info"><p>解法对应于Leetcode 120 Triangle</p></div><h3 id="解法一、常规解法"><a href="#解法一、常规解法" class="headerlink" title="解法一、常规解法"></a>解法一、常规解法</h3><ul><li>思路:由题意可知,本题应是由三角形的下部开始往上进行动态规划,可列出状态转移方程<code>triangle[i][j] += Math.min(triangle[i + 1][j], triangle[i + 1][j + 1])</code>,之后根据三角形的特征,使用两个for循环,计算完毕,答案就在三角形的最顶端了,返回<code>triangle[0][0]</code>即可。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[][]} triangle</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> minimumTotal = <span class="function"><span class="keyword">function</span> (<span class="params">triangle</span>) </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = triangle.length - <span class="number">2</span>; i >= <span class="number">0</span>; i--) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j < triangle[i].length; j++) {</span><br><span class="line"> triangle[i][j] += <span class="built_in">Math</span>.min(triangle[i + <span class="number">1</span>][j], triangle[i + <span class="number">1</span>][j + <span class="number">1</span>])</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> triangle[<span class="number">0</span>][<span class="number">0</span>]</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="解法二、对常规解法进行优化(状态压缩)"><a href="#解法二、对常规解法进行优化(状态压缩)" class="headerlink" title="解法二、对常规解法进行优化(状态压缩)"></a>解法二、对常规解法进行优化(状态压缩)</h3><ul><li>思路:与解法一的区别是此处是用一个一维数组就能使得动态规划进行,在此题中它的优势还不算明显,因为本体是可以在triangle原地计算的,在其他动态规划题型中有时候需要new一个二维数组出来辅佐动态规划,但如果我们能灵活地使用状态压缩,用一维数组就做了二维数组做的事,就能较好地降低空间复杂度。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[][]} triangle</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> minimumTotal = <span class="function"><span class="keyword">function</span> (<span class="params">triangle</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> mini = triangle[triangle.length<span class="number">-1</span>]</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = triangle.length - <span class="number">2</span>; i >= <span class="number">0</span>; i--) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j < triangle[i].length; j++) {</span><br><span class="line"> mini[j] = triangle[i][j] + <span class="built_in">Math</span>.min(mini[j], mini[j+<span class="number">1</span>])</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> mini[<span class="number">0</span>]</span><br><span class="line">};</span><br></pre></td></tr></table></figure><hr><h2 id="四、最长上升子序列"><a href="#四、最长上升子序列" class="headerlink" title="四、最长上升子序列"></a>四、最长上升子序列</h2><div class="note info"><p>解法对应于Leetcode 300 Longest Increasing Subsequence</p></div><ul><li>思路:首先处理dp数组的初始状态,即序列只有自己时,均为1。经过分析可以知道<code>dp[i] = Math.max(dp[i], dp[j] + 1)</code>,其中i是外层循环,即遍历nums数组中的每一个数,j为内层循环,指向i前的每一个数,每个<code>dp[i]</code>状态指的是处理至当前i时,最长的上升子序列长度。判断<code>nums[j]<nums[i]</code>如果i前面的数小于它,那么就会比较,是当前位置的子序列长度大,还是前一个状态的子序列(j会走过i前面的每一个数)+1要大。同时外层循环每遍历完一个数,要记得更新<code>res</code>。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[]} nums</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> lengthOfLIS = <span class="function"><span class="keyword">function</span>(<span class="params">nums</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!nums.length) <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> <span class="keyword">let</span> res = <span class="number">1</span></span><br><span class="line"> <span class="keyword">let</span> dp = <span class="keyword">new</span> <span class="built_in">Array</span>(nums.length)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < dp.length; i++) {</span><br><span class="line"> dp[i] = <span class="number">1</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">1</span>;i<dp.length;i++){</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> j =<span class="number">0</span>;j<i;j++){</span><br><span class="line"> <span class="keyword">if</span>(nums[j]<nums[i]){</span><br><span class="line"> dp[i] = <span class="built_in">Math</span>.max(dp[i], dp[j] + <span class="number">1</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> res = <span class="built_in">Math</span>.max(res,dp[i])</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res</span><br><span class="line">};</span><br></pre></td></tr></table></figure><hr><h2 id="五、硬币最少找零问题"><a href="#五、硬币最少找零问题" class="headerlink" title="五、硬币最少找零问题"></a>五、硬币最少找零问题</h2><div class="note info"><p>解法对应于Leetcode 322 Coin Change</p></div><ul><li>思路:注意dp数组的初始状态,由于状态转移方程我们是求硬币的最少值<code>min</code>,同时求解过程中还会存在无解的情况,所以我们初始化数组为<code>amount+1</code>,在<code>return</code>的时候就判断<code>dp[amount] > amount ? -1 : dp[amount]</code>。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[]} coins</span></span><br><span class="line"><span class="comment"> * @param {number} amount</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> coinChange = <span class="function"><span class="keyword">function</span> (<span class="params">coins, amount</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> dp = <span class="keyword">new</span> <span class="built_in">Array</span>(amount + <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">let</span> max = amount + <span class="number">1</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < dp.length; i++) {</span><br><span class="line"> dp[i] = max</span><br><span class="line"> }</span><br><span class="line"> dp[<span class="number">0</span>] = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i < dp.length; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j < coins.length; j++) {</span><br><span class="line"> <span class="keyword">if</span> (coins[j] <= i) {</span><br><span class="line"> dp[i] = <span class="built_in">Math</span>.min(dp[i], dp[i - coins[j]] + <span class="number">1</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> dp[amount] > amount ? <span class="number">-1</span> : dp[amount]</span><br><span class="line">};</span><br></pre></td></tr></table></figure><hr><h1 id="面试中的动态规划问题"><a href="#面试中的动态规划问题" class="headerlink" title="面试中的动态规划问题"></a>面试中的动态规划问题</h1><blockquote>微信小程序团队一共有 n 名成员,决定出去秋游,在海边遇到出租摩托艇的杰克马,马先生手上有 m 辆待出租的摩托艇,价格分别是 b1 、b2 … bm;<br>由于习惯了微信支付,团队中每个人身上的现金都有限,分别是 a1 a2 … an,对了,一起出门的老板还带有 S 元的团队经费,这个经费是每个人都可以使用的<br><br><font color="#187892" size="number">那么考虑以下两个场景</font><br><br>场景1<br>团队成员都很有爱,都愿意借钱给其他同事,那么这时候团队最多能租到多少摩托艇<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">max</span>(<span class="params"> Array n, Array m, S</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> num</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><br>场景2<br>团队成员都十分小气,是不愿意借钱给别人的,那么请考虑以下两个问题<br><br>//问题一 老板是否能想到一个策略,使得所有人都能租到摩托艇?<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isAll</span>(<span class="params">Array n, Array m, S</span>)</span>{</span><br><span class="line"> <span class="keyword">return</span> bool</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><br>//问题二 请问给出一个策略<br>// 使得整个团队租到最多的摩托艇<br>// 在租到最多摩托艇的情况下,整体的支出尽量的少<br><br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">max</span>(<span class="params"> Array n, Array m, S</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> num,<span class="comment">// 多少摩托艇</span></span><br><span class="line"> cost <span class="comment">// 总体资金支出</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br><br></blockquote><h4 id="调试代码部分"><a href="#调试代码部分" class="headerlink" title="调试代码部分"></a>调试代码部分</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 一共5人,有7辆摩托</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> m = [<span class="number">5</span>,<span class="number">3</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">4</span>,<span class="number">4</span>,<span class="number">7</span>] <span class="comment">//每辆摩托的价格</span></span><br><span class="line"><span class="keyword">let</span> n = [<span class="number">3</span>,<span class="number">4</span>,<span class="number">3</span>,<span class="number">3</span>,<span class="number">6</span>] <span class="comment">//每个人身上的现金</span></span><br><span class="line"><span class="keyword">let</span> s = <span class="number">3</span> <span class="comment">// 团队经费</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 场景1</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">max</span>(<span class="params">n,m,s</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> total = n.reduce(<span class="function">(<span class="params">a,b</span>) =></span> a+b) + s</span><br><span class="line"> m.sort(<span class="function">(<span class="params">a,b</span>)=></span>a-b)</span><br><span class="line"> <span class="keyword">let</span> res = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>;i<m.length;i++){</span><br><span class="line"> <span class="keyword">if</span> (total - m[i] >= <span class="number">0</span>){</span><br><span class="line"> total -= m[i]</span><br><span class="line"> res += <span class="number">1</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(max(n, m, s)) <span class="comment">//5</span></span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 场景2 问题一</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">isAll</span>(<span class="params">n,m,s</span>) </span>{</span><br><span class="line"> m.sort(<span class="function">(<span class="params">a, b</span>) =></span> a - b)</span><br><span class="line"> n.sort(<span class="function">(<span class="params">a, b</span>) =></span> a - b)</span><br><span class="line"> <span class="keyword">let</span> need = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < n.length; i++) {</span><br><span class="line"> <span class="keyword">let</span> gap = n[i] - m[i]</span><br><span class="line"> <span class="keyword">if</span> (gap < <span class="number">0</span>) need += gap</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> s >= need ? <span class="literal">true</span> : <span class="literal">false</span> <span class="comment">//团队经费够不够补贴每个人自己不够的部分</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(isAll(n, m, s)) <span class="comment">//true</span></span><br></pre></td></tr></table></figure><h4 id="场景2的问题二暂时还不会做,有无大神指教一下?"><a href="#场景2的问题二暂时还不会做,有无大神指教一下?" class="headerlink" title="场景2的问题二暂时还不会做,有无大神指教一下?"></a>场景2的问题二暂时还不会做,有无大神指教一下?</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 场景2 问题二</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">maxSolution</span>(<span class="params">n, m, s</span>) </span>{</span><br><span class="line"> <span class="comment">// 1.团队成员都十分小气,是不愿意借钱给别人的,</span></span><br><span class="line"> <span class="comment">// 2.有团队经费 let s = 3 </span></span><br><span class="line"> <span class="comment">// 3.摩托艇的价格 let m = [5, 3, 3, 4, 4, 4, 7]</span></span><br><span class="line"> <span class="comment">// 4。每个人身上有的现金 let n = [3,4,3,3,6],他们身上的钱对于摩托艇来说,有的人不够,有的人多了。</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 问:使得整个团队租到最多的摩托艇,在租到最多摩托艇的情况下,整体的支出尽量的少</span></span><br><span class="line"> m.sort(<span class="function">(<span class="params">a, b</span>) =></span> a - b) <span class="comment">// [3,3,4,4,4,5,7]</span></span><br><span class="line"> n.sort(<span class="function">(<span class="params">a, b</span>) =></span> a - b) <span class="comment">// [3,3,3,4,6]</span></span><br><span class="line"> <span class="keyword">let</span> gap = []</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>;i<n.length;i++){</span><br><span class="line"> gap[i] = </span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> number,</span><br><span class="line"> cost</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(maxSolution(n, m, s))</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
动态规划在我没有专门去攻克它以前,总感觉是一座大山,过段时间没做过相关的思考,很容易就忘记了。所以本文就较为详细地分析了动态规划相关题型的解题思路,并对LeetCode上一些常见动态规划题目&我遇到过的动态规划面试题的解法进行归纳总结与分析。希望看完以后,你也能和我一样,说出:动态规划其实也不难。
</summary>
<category term="数据结构与算法" scheme="JasonLam0990.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="动态规划" scheme="JasonLam0990.github.io/tags/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
</entry>
<entry>
<title>树的归纳总结</title>
<link href="JasonLam0990.github.io/2019/03/18/%E6%A0%91%E7%9A%84%E5%BD%92%E7%BA%B3%E6%80%BB%E7%BB%93/"/>
<id>JasonLam0990.github.io/2019/03/18/树的归纳总结/</id>
<published>2019-03-18T01:14:45.000Z</published>
<updated>2019-03-18T07:13:02.526Z</updated>
<content type="html"><![CDATA[<h1 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h1><hr><h3 id="树的概念"><a href="#树的概念" class="headerlink" title="树的概念"></a>树的概念</h3><ul><li>有三个比较相似的概念:高度(Height)、深度(Depth)、层(Level)</li></ul><blockquote><ul><li>节点的高度 = 节点到叶子节点的最长路径(边数)</li><li>节点的深度 = 从根节点出发,到这个节点所需经历的边的个数</li><li>节点的层数 = 节点的深度+1</li><li>树的高度 = 根节点的高度</li></ul></blockquote><h3 id="二叉树的概念"><a href="#二叉树的概念" class="headerlink" title="二叉树的概念"></a>二叉树的概念</h3><ul><li><p>二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子节点和右子节点。</p></li><li><p>有两个比较特殊的二叉树:满二叉树、完全二叉树</p><p></p></li></ul><blockquote><ul><li>满二叉树:叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点</li><li>完全二叉树:就是我们按顺序给二叉树的节点标号时,1,2,3,4…如果是连在一起的就是完全二叉树,如何标号成1,2,3,5这种就不是完全二叉树</li></ul></blockquote><div class="note info"><p>树的话一般使用链式存储法,完全二叉树(其实就是堆)则是用数组存储最节省内存</p></div><h1 id="二叉树的遍历"><a href="#二叉树的遍历" class="headerlink" title="二叉树的遍历"></a>二叉树的遍历</h1><hr><p>前面总结了树和二叉树的基本定义,接下来一起来看二叉树中非常重要的操作,二叉树的遍历。我将会用递归和非递归两种方式来归纳以下四种遍历方式的Javascript代码。</p><div class="tabs" id><ul class="nav-tabs"><li class="tab active"><a href="#-1">前序遍历</a></li><li class="tab"><a href="#-2">中序遍历</a></li><li class="tab"><a href="#-3">后序遍历</a></li><li class="tab"><a href="#-4">层次遍历</a></li></ul><div class="tab-content"><div class="tab-pane active" id="-1"><h4 id="递归实现"><a href="#递归实现" class="headerlink" title="递归实现"></a>递归实现</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">preOrder</span>(<span class="params">root</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(root){</span><br><span class="line"> <span class="built_in">console</span>.log(root)</span><br><span class="line"> preOrder(root.left)</span><br><span class="line"> preOrder(root.right)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="非递归实现"><a href="#非递归实现" class="headerlink" title="非递归实现"></a>非递归实现</h4><h5 id="思路:前序遍历为-根-左-右-,主要任务就是用自己定义的栈来代替系统栈的功能。首先根节点入栈,进入while循环,如果栈不为空,则取出栈顶元素并访问,然后将栈顶元素的左右节点入栈,要注意顺序,右节点先入栈,左节点后入栈。则左节点先出栈,右节点后出栈,符合-根-左-右-的顺序。"><a href="#思路:前序遍历为-根-左-右-,主要任务就是用自己定义的栈来代替系统栈的功能。首先根节点入栈,进入while循环,如果栈不为空,则取出栈顶元素并访问,然后将栈顶元素的左右节点入栈,要注意顺序,右节点先入栈,左节点后入栈。则左节点先出栈,右节点后出栈,符合-根-左-右-的顺序。" class="headerlink" title="思路:前序遍历为 根-左-右 ,主要任务就是用自己定义的栈来代替系统栈的功能。首先根节点入栈,进入while循环,如果栈不为空,则取出栈顶元素并访问,然后将栈顶元素的左右节点入栈,要注意顺序,右节点先入栈,左节点后入栈。则左节点先出栈,右节点后出栈,符合 根-左-右 的顺序。"></a>思路:前序遍历为 根-左-右 ,主要任务就是用自己定义的栈来代替系统栈的功能。首先根节点入栈,进入while循环,如果栈不为空,则取出栈顶元素并访问,然后将栈顶元素的左右节点入栈,要注意顺序,右节点先入栈,左节点后入栈。则左节点先出栈,右节点后出栈,符合 根-左-右 的顺序。</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">preOrder</span>(<span class="params">root</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(root){</span><br><span class="line"> <span class="keyword">let</span> stack = [root] <span class="comment">//新建栈,并将根结点root入栈 </span></span><br><span class="line"> <span class="keyword">while</span>(stack.length > <span class="number">0</span>){ <span class="comment">//当栈不为空</span></span><br><span class="line"> <span class="keyword">let</span> topNode = stack.pop() <span class="comment">//取栈顶元素</span></span><br><span class="line"> <span class="built_in">console</span>.log(topNode) <span class="comment">//访问</span></span><br><span class="line"> <span class="keyword">if</span>(topNode.right){ <span class="comment">//若右节点存在,入栈</span></span><br><span class="line"> stack.push(topNode.right)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(topNode.left){ <span class="comment">//若左节点存在,入栈</span></span><br><span class="line"> stack.push(topNode.left) </span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="LeetCode对应习题144"><a href="#LeetCode对应习题144" class="headerlink" title="LeetCode对应习题144"></a>LeetCode对应习题144</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">/<strong></strong></span></span><br><span class="line"><span class="comment"><em> Definition for a binary tree node.</em></span></span><br><span class="line"><span class="comment"> function TreeNode(val) {</span></span><br><span class="line"><span class="comment"><em> this.val = val;</em></span></span><br><span class="line"><span class="comment"> this.left = this.right = null;</span></span><br><span class="line"><span class="comment"><em> }</em></span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment"><em> @param {TreeNode} root</em></span></span><br><span class="line"><span class="comment"> @return {number[]}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">var</span> preorderTraversal = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> []</span><br><span class="line"> <span class="keyword">let</span> res = []</span><br><span class="line"> <span class="keyword">let</span> stack = [root]</span><br><span class="line"> <span class="keyword">while</span>(stack.length > <span class="number">0</span>){</span><br><span class="line"> <span class="keyword">let</span> node = stack.pop()</span><br><span class="line"> res.push(node.val)</span><br><span class="line"> <span class="keyword">if</span>(node.right){</span><br><span class="line"> stack.push(node.right)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(node.left){</span><br><span class="line"> stack.push(node.left)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res</span><br><span class="line">};</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="-2"><h4 id="递归实现"><a href="#递归实现" class="headerlink" title="递归实现"></a>递归实现</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">inOrder</span>(<span class="params">root</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(root){</span><br><span class="line"> preOrder(root.left)</span><br><span class="line"> <span class="built_in">console</span>.log(root)</span><br><span class="line"> preOrder(root.right)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="非递归实现"><a href="#非递归实现" class="headerlink" title="非递归实现"></a>非递归实现</h4><h5 id="思路:中序遍历为-左-根-右-,首先将游标指向根节点,然后一直向左下遍历并入栈,直到找到最左的。此时再开始回溯,如果栈不为空,则取出栈顶元素并访问,然后将游标指向当前游标位置的右节点,如果右节点为空则无操作,若不为空,则右节点(其实就类似我们最初的根节点了)入栈,并继续按照找最左的方式遍历并入栈,如此往复。直到最终栈为空,进入终态。"><a href="#思路:中序遍历为-左-根-右-,首先将游标指向根节点,然后一直向左下遍历并入栈,直到找到最左的。此时再开始回溯,如果栈不为空,则取出栈顶元素并访问,然后将游标指向当前游标位置的右节点,如果右节点为空则无操作,若不为空,则右节点(其实就类似我们最初的根节点了)入栈,并继续按照找最左的方式遍历并入栈,如此往复。直到最终栈为空,进入终态。" class="headerlink" title="思路:中序遍历为 左-根-右 ,首先将游标指向根节点,然后一直向左下遍历并入栈,直到找到最左的。此时再开始回溯,如果栈不为空,则取出栈顶元素并访问,然后将游标指向当前游标位置的右节点,如果右节点为空则无操作,若不为空,则右节点(其实就类似我们最初的根节点了)入栈,并继续按照找最左的方式遍历并入栈,如此往复。直到最终栈为空,进入终态。"></a>思路:中序遍历为 左-根-右 ,首先将游标指向根节点,然后一直向左下遍历并入栈,直到找到最左的。此时再开始回溯,如果栈不为空,则取出栈顶元素并访问,然后将游标指向当前游标位置的右节点,如果右节点为空则无操作,若不为空,则右节点(其实就类似我们最初的根节点了)入栈,并继续按照找最左的方式遍历并入栈,如此往复。直到最终栈为空,进入终态。</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">inOrder</span>(<span class="params">root</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(root){</span><br><span class="line"> <span class="keyword">let</span> stack = []</span><br><span class="line"> <span class="keyword">let</span> cursor = root <span class="comment">//游标指向根节点</span></span><br><span class="line"> <span class="keyword">while</span>(stack.length > <span class="number">0</span> || cursor){ </span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在根节点的左子树遍历完后,根节点出栈并访问,游标指向根节点的右节点时,此时栈是为空的,为了防止遍历停止,</span></span><br><span class="line"> <span class="comment">// 加上cursor !== null 来判断此时右子树是否为空。若此时仍有右子树,则为真,可继续维持循环的进行。</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(cursor){ <span class="comment">//左子树存在,则入栈</span></span><br><span class="line"> stack.push(cursor)</span><br><span class="line"> cursor = cursor.left</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// let node = stack.pop() //取出栈顶元素</span></span><br><span class="line"> <span class="comment">// console.log(node) //访问 </span></span><br><span class="line"> <span class="comment">// if(node.right){</span></span><br><span class="line"> <span class="comment">// cursor = node.right</span></span><br><span class="line"> <span class="comment">// }</span></span><br><span class="line"></span><br><span class="line"> cursor = stack.pop()</span><br><span class="line"> res.push(cursor.val)</span><br><span class="line"> cursor = cursor.right</span><br><span class="line"> <span class="comment">//此处两种写法都可以,但是后者似乎更直观</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="LeetCode对应习题94"><a href="#LeetCode对应习题94" class="headerlink" title="LeetCode对应习题94"></a>LeetCode对应习题94</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/<strong></strong></span></span><br><span class="line"><span class="comment"><em> Definition for a binary tree node.</em></span></span><br><span class="line"><span class="comment"> function TreeNode(val) {</span></span><br><span class="line"><span class="comment"><em> this.val = val;</em></span></span><br><span class="line"><span class="comment"> this.left = this.right = null;</span></span><br><span class="line"><span class="comment"><em> }</em></span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment"><em> @param {TreeNode} root</em></span></span><br><span class="line"><span class="comment"> @return {number[]}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">var</span> inorderTraversal = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> []</span><br><span class="line"> <span class="keyword">let</span> res = []</span><br><span class="line"> <span class="keyword">let</span> stack = []</span><br><span class="line"> <span class="keyword">let</span> cursor = root</span><br><span class="line"> <span class="keyword">while</span>(stack.length > <span class="number">0</span> || cursor){</span><br><span class="line"> <span class="keyword">while</span>(cursor){</span><br><span class="line"> stack.push(cursor)</span><br><span class="line"> cursor = cursor.left</span><br><span class="line"> }</span><br><span class="line"> cursor = stack.pop()</span><br><span class="line"> res.push(cursor.val)</span><br><span class="line"> cursor = cursor.right</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res</span><br><span class="line">};</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="-3"><h4 id="递归实现"><a href="#递归实现" class="headerlink" title="递归实现"></a>递归实现</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">postOrder</span>(<span class="params">root</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(root){</span><br><span class="line"> preOrder(root.left)</span><br><span class="line"> preOrder(root.right)</span><br><span class="line"> <span class="built_in">console</span>.log(root)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="非递归实现"><a href="#非递归实现" class="headerlink" title="非递归实现"></a>非递归实现</h4><h5 id="思路:前序遍历为-根-左-右-,而后序遍历为-左-右-根,那么我们只需要交换前序遍历时对左右子树的遍历顺序,则变为-根-右-左,然后再逆序,则为我们需要的后序遍历-左-右-根-啦!"><a href="#思路:前序遍历为-根-左-右-,而后序遍历为-左-右-根,那么我们只需要交换前序遍历时对左右子树的遍历顺序,则变为-根-右-左,然后再逆序,则为我们需要的后序遍历-左-右-根-啦!" class="headerlink" title="思路:前序遍历为 根-左-右 ,而后序遍历为 左-右-根,那么我们只需要交换前序遍历时对左右子树的遍历顺序,则变为 根-右-左,然后再逆序,则为我们需要的后序遍历 左-右-根 啦!"></a>思路:前序遍历为 根-左-右 ,而后序遍历为 左-右-根,那么我们只需要交换前序遍历时对左右子树的遍历顺序,则变为 根-右-左,然后再逆序,则为我们需要的后序遍历 左-右-根 啦!</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">postOrder</span>(<span class="params">root</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(root){</span><br><span class="line"> <span class="keyword">let</span> stack1 = [root] <span class="comment">//新建栈,并将根结点root入栈</span></span><br><span class="line"> <span class="keyword">let</span> stack2 = []</span><br><span class="line"> <span class="keyword">while</span>(stack1.length > <span class="number">0</span>){ <span class="comment">//当栈不为空</span></span><br><span class="line"> <span class="keyword">let</span> topNode = stack1.pop() <span class="comment">//取栈顶元素</span></span><br><span class="line"> stack2.push(topNode) <span class="comment">//访问</span></span><br><span class="line"> <span class="keyword">if</span>(topNode.left){ <span class="comment">//若左节点存在,入栈</span></span><br><span class="line"> stack1.push(topNode.left) </span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(topNode.right){ <span class="comment">//若右节点存在,入栈</span></span><br><span class="line"> stack1.push(topNode.right)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(stack2.length > <span class="number">0</span>){</span><br><span class="line"> <span class="built_in">console</span>.log(stack2.pop())</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="LeetCode对应习题145"><a href="#LeetCode对应习题145" class="headerlink" title="LeetCode对应习题145"></a>LeetCode对应习题145</h4><h5 id="解法一-双栈法"><a href="#解法一-双栈法" class="headerlink" title="解法一 双栈法"></a>解法一 双栈法</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/<strong></strong></span></span><br><span class="line"><span class="comment"><em> Definition for a binary tree node.</em></span></span><br><span class="line"><span class="comment"> function TreeNode(val) {</span></span><br><span class="line"><span class="comment"><em> this.val = val;</em></span></span><br><span class="line"><span class="comment"> this.left = this.right = null;</span></span><br><span class="line"><span class="comment"><em> }</em></span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment"><em> @param {TreeNode} root</em></span></span><br><span class="line"><span class="comment"> @return {number[]}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">var</span> postorderTraversal = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> []</span><br><span class="line"> <span class="keyword">let</span> res = []</span><br><span class="line"> <span class="keyword">let</span> stack = [root]</span><br><span class="line"> <span class="keyword">while</span>(stack.length > <span class="number">0</span>){</span><br><span class="line"> <span class="keyword">let</span> node = stack.pop()</span><br><span class="line"> res.push(node.val)</span><br><span class="line"> <span class="keyword">if</span>(node.left){</span><br><span class="line"> stack.push(node.left)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(node.right){</span><br><span class="line"> stack.push(node.right)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res.reverse()</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h5 id="解法二-深度优先搜索法(队列)"><a href="#解法二-深度优先搜索法(队列)" class="headerlink" title="解法二 深度优先搜索法(队列)"></a>解法二 深度优先搜索法(队列)</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/<strong></strong></span></span><br><span class="line"><span class="comment"><em> Definition for a binary tree node.</em></span></span><br><span class="line"><span class="comment"> function TreeNode(val) {</span></span><br><span class="line"><span class="comment"><em> this.val = val;</em></span></span><br><span class="line"><span class="comment"> this.left = this.right = null;</span></span><br><span class="line"><span class="comment"><em> }</em></span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment"><em> @param {TreeNode} root</em></span></span><br><span class="line"><span class="comment"> @return {number[]}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">var</span> postorderTraversal = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"><span class="keyword">if</span> (!root) <span class="keyword">return</span> [];</span><br><span class="line"><span class="keyword">const</span> queue = [root];</span><br><span class="line"><span class="keyword">const</span> res = [];</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> (queue.length > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">const</span> node = queue.shift();</span><br><span class="line"> res.unshift(node.val);</span><br><span class="line"> <span class="keyword">if</span> (node.left) queue.unshift(node.left);</span><br><span class="line"> <span class="keyword">if</span> (node.right) queue.unshift(node.right);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> res;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><div class="note default"><p>其实还有一种一个栈实现的非递归方法,但是最近有好几个面试,只得加快归纳总结的速度,不能覆盖到了,以后有时间了再补回来吧~</p></div></div><div class="tab-pane" id="-4"><h4 id="使用队列实现"><a href="#使用队列实现" class="headerlink" title="使用队列实现"></a>使用队列实现</h4><h5 id="思路:队伍先进先出,首先根节点入队,然后进入while循环,若队列不为空,则队列最前端出队并访问,同时将其左右节点依次如队,若为空则无操作,输出结果则为层次遍历~"><a href="#思路:队伍先进先出,首先根节点入队,然后进入while循环,若队列不为空,则队列最前端出队并访问,同时将其左右节点依次如队,若为空则无操作,输出结果则为层次遍历~" class="headerlink" title="思路:队伍先进先出,首先根节点入队,然后进入while循环,若队列不为空,则队列最前端出队并访问,同时将其左右节点依次如队,若为空则无操作,输出结果则为层次遍历~"></a>思路:队伍先进先出,首先根节点入队,然后进入while循环,若队列不为空,则队列最前端出队并访问,同时将其左右节点依次如队,若为空则无操作,输出结果则为层次遍历~</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">levelOrder</span>(<span class="params">root</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(root){</span><br><span class="line"> <span class="keyword">let</span> queue = [root] <span class="comment">//新建队列,并将root入队</span></span><br><span class="line"> <span class="keyword">while</span>(queue.length > <span class="number">0</span>){</span><br><span class="line"> <span class="keyword">let</span> top = queue.shift()</span><br><span class="line"> <span class="built_in">console</span>.log(top)</span><br><span class="line"> <span class="keyword">if</span>(top.left){</span><br><span class="line"> queue.push(top.left)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(top.right){</span><br><span class="line"> queue.push(top.right)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="LeetCode对应习题102"><a href="#LeetCode对应习题102" class="headerlink" title="LeetCode对应习题102"></a>LeetCode对应习题102</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/<strong></strong></span></span><br><span class="line"><span class="comment"><em> Definition for a binary tree node.</em></span></span><br><span class="line"><span class="comment"> function TreeNode(val) {</span></span><br><span class="line"><span class="comment"><em> this.val = val;</em></span></span><br><span class="line"><span class="comment"> this.left = this.right = null;</span></span><br><span class="line"><span class="comment"><em> }</em></span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment">/</span></span><br><span class="line"><span class="comment"><em> @param {TreeNode} root</em></span></span><br><span class="line"><span class="comment"> @return {number[][]}</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">var</span> levelOrder = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> []</span><br><span class="line"> <span class="keyword">let</span> res = []</span><br><span class="line"> <span class="keyword">let</span> queue = [root]</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">while</span>(queue.length > <span class="number">0</span>){</span><br><span class="line"> <span class="keyword">let</span> len = queue.length</span><br><span class="line"> <span class="keyword">let</span> current = []</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>;i<len;i++){</span><br><span class="line"> <span class="keyword">let</span> node = queue.shift()</span><br><span class="line"> current.push(node.val)</span><br><span class="line"> <span class="keyword">if</span> (node.left) {</span><br><span class="line"> queue.push(node.left);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (node.right) {</span><br><span class="line"> queue.push(node.right);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> res.push(current)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div></div><h1 id="配套练习题"><a href="#配套练习题" class="headerlink" title="配套练习题"></a>配套练习题</h1><hr><div class="note primary"><p>树的解法中最好优先思考递归的方法,比较容易写。如果对访问速度有要求时,再思考非递归的方式来使用手动实现栈替代系统栈。</p></div><h3 id="一、交换二叉树"><a href="#一、交换二叉树" class="headerlink" title="一、交换二叉树"></a>一、交换二叉树</h3><div class="note info"><p>解法对应于Leetcode 226 Invert Binary Tree</p></div><ul><li>思路:其实就是遍历树的过程,可以用深度遍历(前中后序),或者广度遍历(层次),然后将visit的操作改成交换的操作即可,交换的简便写法是使用ES6的解构赋值</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {TreeNode} root</span></span><br><span class="line"><span class="comment"> * @return {TreeNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> invertTree = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> [root.left,root.right] = [root.right,root.left];</span><br><span class="line"> invertTree(root.left);</span><br><span class="line"> invertTree(root.right);</span><br><span class="line"> <span class="keyword">return</span> root;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><hr><h3 id="二、求二叉树的最大深度(按照理解我感觉这里应该叫作最大层数?)"><a href="#二、求二叉树的最大深度(按照理解我感觉这里应该叫作最大层数?)" class="headerlink" title="二、求二叉树的最大深度(按照理解我感觉这里应该叫作最大层数?)"></a>二、求二叉树的最大深度(按照理解我感觉这里应该叫作最大层数?)</h3><div class="note info"><p>解法对应于Leetcode 104 Maximum Depth of Binary Tree</p></div><h4 id="解法一、递归法"><a href="#解法一、递归法" class="headerlink" title="解法一、递归法"></a>解法一、递归法</h4><ul><li>思路:从自身到左右孩子之间算上层数差1,之后就是不断递归下去。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {TreeNode} root</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> maxDepth = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Math</span>.max(maxDepth(root.left),maxDepth(root.right))+<span class="number">1</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="解法二、BFS"><a href="#解法二、BFS" class="headerlink" title="解法二、BFS"></a>解法二、BFS</h4><ul><li>思路:与之前写过的层次遍历代码类似,不再赘述了。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {TreeNode} root</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> maxDepth = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> <span class="keyword">let</span> res = <span class="number">0</span></span><br><span class="line"> <span class="keyword">let</span> queue = [root]</span><br><span class="line"> <span class="keyword">while</span>(queue.length > <span class="number">0</span>){</span><br><span class="line"> <span class="keyword">let</span> len = queue.length </span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>;i<len;i++){</span><br><span class="line"> <span class="keyword">let</span> node = queue.shift()</span><br><span class="line"> <span class="keyword">if</span> (node.left) {</span><br><span class="line"> queue.push(node.left);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (node.right) {</span><br><span class="line"> queue.push(node.right);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> res += <span class="number">1</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res</span><br><span class="line">};</span><br></pre></td></tr></table></figure><hr><h3 id="三、判断是否是二叉搜索树"><a href="#三、判断是否是二叉搜索树" class="headerlink" title="三、判断是否是二叉搜索树"></a>三、判断是否是二叉搜索树</h3><div class="note info"><p>解法对应于Leetcode 98 Validate Binary Search Tree</p></div><ul><li>思路:这个解法挺巧妙的,中序遍历二叉搜索树, 若序列递增, 则说明为二叉搜索树</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {TreeNode} root</span></span><br><span class="line"><span class="comment"> * @return {boolean}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> isValidBST = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line"> <span class="keyword">let</span> stack = []</span><br><span class="line"> <span class="keyword">let</span> cursor = root</span><br><span class="line"> <span class="keyword">let</span> inorder = - <span class="built_in">Number</span>.MAX_SAFE_INTEGER</span><br><span class="line"> <span class="keyword">while</span>(stack.length > <span class="number">0</span> || cursor){</span><br><span class="line"> <span class="keyword">while</span>(cursor){</span><br><span class="line"> stack.push(cursor)</span><br><span class="line"> cursor = cursor.left</span><br><span class="line"> }</span><br><span class="line"> cursor = stack.pop()</span><br><span class="line"> <span class="keyword">if</span>(cursor.val <= inorder) <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line"> inorder = cursor.val</span><br><span class="line"> cursor = cursor.right</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="四、二叉树路径和"><a href="#四、二叉树路径和" class="headerlink" title="四、二叉树路径和"></a>四、二叉树路径和</h3><div class="note info"><p>解法对应于Leetcode 112 Path Sum</p></div><ul><li><p>思路:使用递归的方式,同时对左右子树进行遍历,每一次分叉下去,都会用Sum减掉当前节点的值,之后的节点只需要判断传进来的root是否是叶子节点以及是否等于传进来的Sum即可。这个解法非常巧妙</p></li><li><p>注意事项:题目中的路径指的是根节点到叶子节点的路径,所以判断时要<code>!root.left && !root.right</code>来判读是否是叶子节点。</p></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {TreeNode} root</span></span><br><span class="line"><span class="comment"> * @param {number} sum</span></span><br><span class="line"><span class="comment"> * @return {boolean}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> hasPathSum = <span class="function"><span class="keyword">function</span>(<span class="params">root, sum</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span>(!root) <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line"> <span class="keyword">if</span>(!root.left && !root.right) <span class="keyword">return</span> root.val == sum</span><br><span class="line"> <span class="keyword">return</span> hasPathSum(root.left,sum - root.val) || hasPathSum(root.right,sum - root.val)</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
树是一种非线性表结构,比线性表的数据结构要复杂得多。我将按照树、二叉树、二叉查找树的顺序来复习以及做相关习题,红黑树的话感觉前端似乎可以暂时不用涉及这么深?我就先不总结归纳这一部分了。
</summary>
<category term="数据结构与算法" scheme="JasonLam0990.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="树" scheme="JasonLam0990.github.io/tags/%E6%A0%91/"/>
</entry>
<entry>
<title>单链表归纳总结</title>
<link href="JasonLam0990.github.io/2019/03/16/%E5%8D%95%E9%93%BE%E8%A1%A8%E5%BD%92%E7%BA%B3%E6%80%BB%E7%BB%93/"/>
<id>JasonLam0990.github.io/2019/03/16/单链表归纳总结/</id>
<published>2019-03-15T16:15:23.000Z</published>
<updated>2019-03-16T00:55:23.129Z</updated>
<content type="html"><![CDATA[<div class="note default"><p>常见应用场景:一些缓存场景,如LRU缓存淘汰算法</p></div><div class="note primary"><p>单链表升级版:双向链表、循环链表</p></div><h2 id="小技巧"><a href="#小技巧" class="headerlink" title="小技巧"></a>小技巧</h2><ul><li><h3 id="技巧一:利用哨兵(头节点)简化实现难度"><a href="#技巧一:利用哨兵(头节点)简化实现难度" class="headerlink" title="技巧一:利用哨兵(头节点)简化实现难度"></a>技巧一:利用哨兵(头节点)简化实现难度</h3></li></ul><blockquote><p>如果我们要在链表中进行插入操作时,当链表为空时和当链表不为空时,操作是不同的。如果我们要在链表中进行删除操作时,当要删除的节点是最末节点时和当要删除的节点不是最末节点时,操作是不同的。<br><br>针对链表的插入、删除操作,需要对插入第一个结点和删除最后一个结点的情况进行特殊处理。这样代码实现起来就会很繁琐,不简洁,而且也容易因为考虑不全而出错,使用哨兵(头节点)可以帮助我们统一操作。<br><br>如果我们引入哨兵结点,在任何时候,不管链表是不是空,head指针都会一直指向这个哨兵结点。我们也把这种有哨兵结点的链表叫带头链表。相反,没有哨兵结点的链表就叫作不带头链表。<br><br>因为哨兵结点一直存在,所以插入第一个结点和插入其他结点,删除最后一个结点和删除其他结点,都可以统一为相同的代码实现逻辑了。</p></blockquote><ul><li><h3 id="技巧二:重点留意边界条件处理"><a href="#技巧二:重点留意边界条件处理" class="headerlink" title="技巧二:重点留意边界条件处理"></a>技巧二:重点留意边界条件处理</h3></li></ul><blockquote><ul><li>如果链表为空时,代码是否能正常工作? </li><li>如果链表只包含一个结点时,代码是否能正常工作?</li><li>如果链表只包含两个结点时,代码是否能正常工作?</li><li>代码逻辑在处理头结点和尾结点的时候,是否能正常工作?</li></ul></blockquote><ul><li><h3 id="技巧三:举例画图,辅助思考"><a href="#技巧三:举例画图,辅助思考" class="headerlink" title="技巧三:举例画图,辅助思考"></a>技巧三:举例画图,辅助思考</h3></li></ul><h2 id="配套练习题"><a href="#配套练习题" class="headerlink" title="配套练习题"></a>配套练习题</h2><h3 id="一、单链表反转"><a href="#一、单链表反转" class="headerlink" title="一、单链表反转"></a>一、单链表反转</h3><div class="note info"><p>解法对应于Leetcode 206 单链表反转</p></div><ul><li><p>思路:在遍历单链表的同时反转指针,从而达到使单链表逆序的功能。</p></li><li><p>注意事项:要在纸上简单画一下过程,理顺一下每一步的顺序,不要丢失指针即可。</p></li><li><p>方法:首先新建null节点为node,并让一个游标cursor指向head,因为我们需要反转指针,cursor.next = node如果先执行了的话,就会造成丢失指针,故需要有一个临时的nextNode保存当前处理节点的下一个节点,并在最后使得cursor = nextNode</p></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Input: 1 -> 2 -> 3 -> 4 -> 5 -> NULL</span></span><br><span class="line"><span class="comment">// Output: 5 -> 4 -> 3 -> 2 -> 1 -> NULL</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} head</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> reverseList = <span class="function"><span class="keyword">function</span> (<span class="params">head</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> node = <span class="literal">null</span></span><br><span class="line"> <span class="keyword">let</span> cursor = head</span><br><span class="line"> <span class="keyword">while</span> (cursor != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">let</span> nextNode = cursor.next</span><br><span class="line"> cursor.next = node</span><br><span class="line"> node = cursor</span><br><span class="line"> cursor = nextNode</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> node</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="二、链表中环的检测"><a href="#二、链表中环的检测" class="headerlink" title="二、链表中环的检测"></a>二、链表中环的检测</h3><div class="note info"><p>解法对应于Leetcode 141 链表中环的检测</p></div><h4 id="解法一、快慢指针法"><a href="#解法一、快慢指针法" class="headerlink" title="解法一、快慢指针法"></a>解法一、快慢指针法</h4><ul><li><p>思路:快指针跑在前头,慢指针在后,如果存在环的话,快指针就一定能追上慢指针。</p></li><li><p>注意事项:while的条件,因为快指针跑的快,所以主要是判断fast的临界。只有当fast和fast.next均不为null时,才不会发生<code>TypeError: Cannot read property 'next' of null</code>之类的错误</p></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Input: 1 -> 2 -> 3 -> 4 -> 5 -> NULL</span></span><br><span class="line"><span class="comment">// Output: 5 -> 4 -> 3 -> 2 -> 1 -> NULL</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} head</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> reverseList = <span class="function"><span class="keyword">function</span> (<span class="params">head</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> node = <span class="literal">null</span></span><br><span class="line"> <span class="keyword">let</span> cursor = head</span><br><span class="line"> <span class="keyword">while</span> (cursor != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">let</span> nextNode = cursor.next</span><br><span class="line"> cursor.next = node</span><br><span class="line"> node = cursor</span><br><span class="line"> cursor = nextNode</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> node</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="解法二、Set集合映射法"><a href="#解法二、Set集合映射法" class="headerlink" title="解法二、Set集合映射法"></a>解法二、Set集合映射法</h4><ul><li>思路:新建一个Set,遍历链表,判断Set是否含有当前处理的节点,若有,说明之前已经遇到过,有环。否则就说明是新的节点,那么就add到Set中,然后继续下一个节点</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} head</span></span><br><span class="line"><span class="comment"> * @return {boolean}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> hasCycle = <span class="function"><span class="keyword">function</span> (<span class="params">head</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> <span class="keyword">set</span> = new Set()</span><br><span class="line"> while (head != null) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">set</span>.has(head)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">set</span>.add(head)</span><br><span class="line"> head = head.next</span><br><span class="line"> }</span><br><span class="line"> return false</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="三、两个有序的链表合并"><a href="#三、两个有序的链表合并" class="headerlink" title="三、两个有序的链表合并"></a>三、两个有序的链表合并</h3><div class="note info"><p>解法对应于Leetcode 21 两个有序的链表合并</p></div><h4 id="解法一、新建链表法"><a href="#解法一、新建链表法" class="headerlink" title="解法一、新建链表法"></a>解法一、新建链表法</h4><ul><li>思路:新的链使用哨兵guard,然后l1与l2反复比较头节点大小,小的就摘除,接到新的链后面。相等的话就l1先l2后,都接到新的链后面。当其中一条链为空,就把另外一条链剩下的都接到新链后即可。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} l1</span></span><br><span class="line"><span class="comment"> * @param {ListNode} l2</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> mergeTwoLists = <span class="function"><span class="keyword">function</span> (<span class="params">l1, l2</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (!l1) <span class="keyword">return</span> l2</span><br><span class="line"> <span class="keyword">if</span> (!l2) <span class="keyword">return</span> l1</span><br><span class="line"> <span class="keyword">let</span> guard = <span class="keyword">new</span> ListNode(<span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">let</span> cursor = guard</span><br><span class="line"> <span class="keyword">while</span> (l1 && l2) {</span><br><span class="line"> <span class="keyword">if</span> (l1.val < l2.val) {</span><br><span class="line"> cursor.next = l1</span><br><span class="line"> l1 = l1.next</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (l1.val > l2.val) {</span><br><span class="line"> cursor.next = l2</span><br><span class="line"> l2 = l2.next</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> cursor.next = l1</span><br><span class="line"> l1 = l1.next</span><br><span class="line"> cursor = cursor.next</span><br><span class="line"> cursor.next = l2</span><br><span class="line"> l2 = l2.next</span><br><span class="line"> }</span><br><span class="line"> cursor = cursor.next</span><br><span class="line"> }</span><br><span class="line"> cursor.next = l1 || l2</span><br><span class="line"> <span class="keyword">return</span> guard.next</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="解法二、原地合并法(递归)"><a href="#解法二、原地合并法(递归)" class="headerlink" title="解法二、原地合并法(递归)"></a>解法二、原地合并法(递归)</h4><ul><li>递归指的是把问题分解成为规模更小的、 具有与原问题有着相同解法的问题。</li></ul><blockquote><ul><li>递归特性一: 必须有一个明确的结束条件</li><li>递归特性二: 每次递归都是为了让问题规模变小</li><li>递归特性三:层次过多会导致栈溢出, 且效率不高</li></ul></blockquote><ul><li>思路:使用递归的方法,明确结束条件是当其中一条链为空时,递归就会结束。每次递归都使得head所在的链少一个节点,进而使问题规模变小</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} l1</span></span><br><span class="line"><span class="comment"> * @param {ListNode} l2</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> mergeTwoLists = <span class="function"><span class="keyword">function</span> (<span class="params">l1, l2</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (!l1) <span class="keyword">return</span> l2</span><br><span class="line"> <span class="keyword">if</span> (!l2) <span class="keyword">return</span> l1</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> head = l1.val < l2.val ? l1 : l2</span><br><span class="line"> <span class="keyword">let</span> left = l1.val < l2.val ? l2 : l1</span><br><span class="line"></span><br><span class="line"> head.next = mergeTwoLists(head.next, left)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> head</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="四、删除链表倒数第-n-个结点"><a href="#四、删除链表倒数第-n-个结点" class="headerlink" title="四、删除链表倒数第 n 个结点"></a>四、删除链表倒数第 n 个结点</h3><div class="note info"><p>解法对应于Leetcode 19 删除链表倒数第 n 个结点</p></div><h4 id="解法一、快慢指针法-(一趟搞定)"><a href="#解法一、快慢指针法-(一趟搞定)" class="headerlink" title="解法一、快慢指针法 - (一趟搞定)"></a>解法一、快慢指针法 - (一趟搞定)</h4><ul><li><p>思路:为了方便处理只有一个节点的情况,我们引入头指针guard。让快慢指针fast & slow均指向guard,然后看传入的n的值,n为多少,则快指针就先走几步,由于我们引入了头节点,所以快指针相应的要多走一步,故为n+1。接下来就是快慢指针同时往后走,直到快指针走到头。我们画图可以发现,当前的slow处于待删除节点的前方,我们接下来就使用slow.next = slow.next.next即可删除对应的节点了,之后再返回头指针的next即可。</p></li><li><p>注意事项:引入头指针后,fast应先走n+1步。做链表题一定要同时画一画草图,思路更清晰</p></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} head</span></span><br><span class="line"><span class="comment"> * @param {number} n</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> removeNthFromEnd = <span class="function"><span class="keyword">function</span> (<span class="params">head, n</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> guard = <span class="keyword">new</span> ListNode(<span class="literal">null</span>)</span><br><span class="line"> guard.next = head</span><br><span class="line"> <span class="keyword">let</span> fast = guard</span><br><span class="line"> <span class="keyword">let</span> slow = guard</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < n + <span class="number">1</span>; i++) {</span><br><span class="line"> fast = fast.next</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span> (fast) {</span><br><span class="line"> fast = fast.next</span><br><span class="line"> slow = slow.next</span><br><span class="line"> }</span><br><span class="line"> slow.next = slow.next.next</span><br><span class="line"> <span class="keyword">return</span> guard.next</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="解法二、快慢指针法-(两趟搞定)"><a href="#解法二、快慢指针法-(两趟搞定)" class="headerlink" title="解法二、快慢指针法 - (两趟搞定)"></a>解法二、快慢指针法 - (两趟搞定)</h4><ul><li>思路:同样的,哨兵guard头节点是为了处理只有一个节点时的特殊情况。第一遍先从头遍历完链表,计算出从head走到链表结尾需要的步数length。然后用length-n算出从head要到倒数第n个节点前需要的步数。那么如果是从guard开始走length - n步就可以走到待删除节点的前面,然后使用cursor.next = cursor.next.next即可</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} head</span></span><br><span class="line"><span class="comment"> * @param {number} n</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> removeNthFromEnd = <span class="function"><span class="keyword">function</span> (<span class="params">head, n</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> guard = <span class="keyword">new</span> ListNode(<span class="literal">null</span>)</span><br><span class="line"> guard.next = head</span><br><span class="line"> <span class="keyword">let</span> cursor = head</span><br><span class="line"> <span class="keyword">let</span> length = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> (cursor) {</span><br><span class="line"> length++</span><br><span class="line"> cursor = cursor.next</span><br><span class="line"> }</span><br><span class="line"> cursor = guard</span><br><span class="line"> length -= n</span><br><span class="line"> <span class="keyword">while</span> (length) {</span><br><span class="line"> length--</span><br><span class="line"> cursor = cursor.next</span><br><span class="line"> }</span><br><span class="line"> cursor.next = cursor.next.next</span><br><span class="line"> <span class="keyword">return</span> guard.next</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="五、求链表的中间结点"><a href="#五、求链表的中间结点" class="headerlink" title="五、求链表的中间结点"></a>五、求链表的中间结点</h3><div class="note info"><p>解法对应于Leetcode 876 求链表的中间结点</p></div><h4 id="解法一、快慢指针法-1"><a href="#解法一、快慢指针法-1" class="headerlink" title="解法一、快慢指针法"></a>解法一、快慢指针法</h4><ul><li>思路:这个很简单,就没什么好说的了。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} head</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> middleNode = <span class="function"><span class="keyword">function</span> (<span class="params">head</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> fast = head</span><br><span class="line"> <span class="keyword">let</span> slow = head</span><br><span class="line"> <span class="keyword">while</span> (fast && fast.next) {</span><br><span class="line"> fast = fast.next.next</span><br><span class="line"> slow = slow.next</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> slow</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
把单链表的相关知识捋了一下,做了一点总结,同时也刷了一些题目,在此做一些记录,方便以后查阅。
</summary>
<category term="数据结构与算法" scheme="JasonLam0990.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="单链表" scheme="JasonLam0990.github.io/tags/%E5%8D%95%E9%93%BE%E8%A1%A8/"/>
</entry>
<entry>
<title>Hello Blog</title>
<link href="JasonLam0990.github.io/2019/03/15/hello-world/"/>
<id>JasonLam0990.github.io/2019/03/15/hello-world/</id>
<published>2019-03-15T02:03:48.000Z</published>
<updated>2019-03-15T16:13:03.340Z</updated>
<content type="html"><![CDATA[<blockquote class="blockquote-center"><p>第一篇文章,还是挺有纪念意义的hhh<br>其实我想有一个自己的博客好久了,但是一直都想的是自己用Vue或React写前端,用Koa或者Express之类的写个后台<br>也因为想的这么复杂,所以学习速度也跟不上,迟迟没把博客搭起来<br>现在准备春招秋招,还是需要有一个存放知识归纳文章的地方,索性就用Github Pages + Hexo解决了,感觉也挺好<br>希望你喜欢这个博客,并能从中有所收获。如有错误的地方,也请批评指正</p></blockquote>]]></content>
<summary type="html">
<blockquote class="blockquote-center"><p>第一篇文章,还是挺有纪念意义的hhh<br>其实我想有一个自己的博客好久了,但是一直都想的是自己用Vue或React写前端,用Koa或者Express之类的写个后台<br>也因为想的这么复杂,所以学
</summary>
<category term="胡言乱语" scheme="JasonLam0990.github.io/categories/%E8%83%A1%E8%A8%80%E4%B9%B1%E8%AF%AD/"/>
</entry>
</feed>