-
Notifications
You must be signed in to change notification settings - Fork 0
/
local-search.xml
515 lines (243 loc) · 723 KB
/
local-search.xml
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>隐私政策</title>
<link href="/2022/11/06/privacy-policy/"/>
<url>/2022/11/06/privacy-policy/</url>
<content type="html"><![CDATA[<p>本隐私政策(简称本政策)于 2022 年 11 月 7 日起发布并生效,本政策是龙岩创客科技有限公司快应用产品【典阅故事汇】(以下简称“本产品”)的隐私保护相关事项所订立的有效合约。您通过点击确认本协议或以其他方式选择接受本协议,即表示您与龙岩创客科技有限公司达成协议并同意接受本政策的全部以下约定内容。</p><p>【龙岩创客科技有限公司】系本产品的登记著作权人,依法享有本产品的著作权。</p><p>本产品由龙岩创客科技有限公司运营并向您提供阅读服务并对您依法享有权利、履行义务、承担法律责任。</p><p>本政策将帮助您了解以下内容:<br>1、我们如何收集和使用您的个人信息</p><p>2、我们如何使用Cookie和同类技术</p><p>3、我们如何共享、转让、公开披露您的个人信息</p><p>4、我们如何保护您的个人信息</p><p>5、您的权利</p><p>6、我们如何处理儿童的个人信息</p><p>7、您的个人信息如何在全球范围转移</p><p>8、本政策如何更新</p><p>9、本政策的适用</p><p>10、争议解决</p><p>11、联系我们</p><p>龙岩创客科技有限公司和本产品登记著作权人非常重视个人信息的保护。用户(简称“您”)在使用我们的产品或服务时,我们可能会收集和使用您的相关信息。一旦您选择使用我们的产品或服务,即表示您认可并接受本条款现有内容及其可能随时更新的内容。如果您不同意,应当终止使用本产品的服务。请您在使用我们的产品前,仔细阅读并了解本《隐私政策》。</p><p>一、我们如何收集和使用您的个人信息<br>个人信息是指以电子或者其他方式记录的能够单独或者与其他信息结合识别特定自然人身份或者反映特定自然人活动情况的各种信息。</p><p>龙岩创客科技有限公司和本产品登记著作权人仅会出于本政策所述的以下目的、方式、范围在为您提供阅读服务时收集和使用您的个人信息:</p><p>1、应用功能一:成为注册用户</p><p>您在申请成为本产品注册用户时,您需提供以下信息:您的设备信息或手机号。</p><p>您提供的上述信息,授权我们在为您使用本服务期间持续使用。在您注销账号时,我们将停止使用并删除上述信息。</p><p>2、应用功能二:个性化推荐、用户画像</p><p>您使用我们服务时,本产品会记录您的操作日志,包括浏览点击记录、添加书架、搜索关键字、读过的书籍和章节、参与的活动。</p><p>我们会基于前述信息对您的偏好、阅读习惯、使用产品的特征进行分析和用户画像,以便为您提供个性化、定制化的服务,向您展现或推荐相关程度更高的服务。</p><p>3、应用功能六:权限启用</p><p>我们承诺决不超范围、超频次搜集您的个人信息,决不搜集与使用本产品服务非必需或无合理应用场景的信息。</p><p>您在使用本产品时,为提供给您服务之目的,本产品可能在您使用该应用某些场景下向您申请终端设备的以下权限,当然您可以拒绝开启以下权限,或在手机的设置中关闭本产品的以下权限,关闭以下权限不会影响您对本产品其他功能的使用:</p><p>访问电话:通过获取您的电话状态权限我们记录您的设备识别码(即IMEI或IMSI码)进行匿名化处理,用于统计及安全校验;</p><p>访问本地存储:通过开启本地存储权限,将本软件内的书籍下载到您的手机存储,以及通过手机存储将您的本地书籍上传到本软件;</p><p>访问照片:您可以直接选择手机内的照片或图片进行上传或与客服沟通时提供证明;</p><p>访问您设备上的媒体内容和文件:用于读写图书封面、活动图片的缓存,提升应用使用流畅度。</p><p>开启推送:您可以通过开启推送权限来接收本产品推送的消息,你也可以关闭该权限;</p><p>开启无线数据:您可以通过连接无线网络或蜂窝网络来实现本产品需要的联网功能;</p><p>访问安装程序列表:通过获取您的安装程序列表我们可以确认您是否安装了我们所推广的产品,以便我们及时向您发放相应奖励。</p><p>开启麦克风和语音识别:您可以通过语音来控制本软件的语音朗读功能及语音控制功能;</p><p>开启后台应用刷新:开启后可以实现听书、语音朗读不受产品切换到后台的影响而暂停播放;</p><p>使用剪贴板:您可以复制并粘贴读者QQ群号码、客服电话,也可以选择不使用剪贴板权限。</p><p>二、我们如何使用Cookie和同类技术<br>Cookie和同类技术是互联网中的通用常用技术。为确保本平台正常运转、使您获得更轻松的访问体验、向您推荐您可能感兴趣的内容,我们可能会在您的移动设备上存储名为Cookie的小数据文件。Cookie通常包含标识符、站点名称以及一些号码和字符。借助于Cookie我们将记录您的登录信息及在本产品中的操作信息,以便我们存储您的偏好及使用习惯,帮您省去重复输入注册信息的步骤,并帮助判断您的账户安全状态,以为您提供更轻松的用户体验和服务。</p><p>我们不会将Cookie用于本政策所述目的之外的任何用途。您可根据自己的偏好管理或停用Cookie。有关详情,请参AboutCookies.org。如果停用Cookie,您有可能无法享受最佳的服务体验,我们的推荐内容与您的相关性也会降低。</p><p>三、我们如何共享、转让、公开披露您的个人信息<br>(一)共享</p><p>我们不会将您的个人信息向龙岩创客科技有限公司和本产品登记著作权人及关联公司以外的任何公司、组织和个人共享,但以下情况除外:</p><p>1、在获取明确同意的情况下共享:在获得您的明确同意后,我们会与其他方共享您的个人信息。</p><p>2、我们可能会根据法律法规规定,或按政府主管部门的强制性规定,对外共享您的个人信息。</p><p>3、与授权合作伙伴共享:仅为实现本政策中声明的目的,我们的某些服务将由授权合作伙伴提供。我们可能会与合作伙伴共享您的某些个人信息,以提供更好的客户服务和用户体验。我们仅会出于合法、正当、必要、特定、明确的目的共享您的个人信息,并且只会共享提供服务所必要的个人信息。我们的合作伙伴无权将共享的个人信息用于任何其他用途。</p><p>(二)转让</p><p>我们不会将您的个人信息转让给任何公司、组织和个人,但以下情况除外:</p><p>1、在获取明确同意的情况下转让:获得您的明确同意后,我们会向其他方转让您的个人信息;</p><p>2、在涉及合并、收购或破产清算时,若涉及到个人信息转让,我们会在要求新的持有您个人信息的公司、组织继续受此隐私政策的约束,否则我们将要求该公司、组织重新向您征求授权同意。</p><p>(三)公开披露</p><p>我们仅会在以下情况下,公开披露您的个人信息:</p><p>1、获得您明确同意后;</p><p>2、基于法律的披露:在法律、法律程序、诉讼或政府主管部门强制性要求的情况下,我们可能会公开披露您的个人信息。</p><p>(四)对外共享可能涉及的个人信息类型:设备识别码、产品版本信息;对外公开披露可能涉及的个人信息类型:阅读书籍、阅读时长。</p><p>我们已知晓对外共享、转让、公开披露个人信息所承担的相应法律责任,并将采取合理措施保障个人信息安全。</p><p>四、我们如何保护和保存您的个人信息<br>(一)技术保护措施</p><p>我们非常重视您个人信息的安全,将努力采取各种符合业界标准的合理的安全措施来保护您的信息,使您的信息不会被泄漏、毁损或者丢失,包括但不限于SSL、隐私信息加密存储、数据中心的访问控制。我们会使用加密技术提高个人信息的安全性;我们会使用受信赖的保护机制防止个人信息遭到恶意攻击;我们会部署访问控制机制,尽力确保只有授权人员才可访问个人信息。</p><p>(二)安全管理体系</p><p>我们有行业先进的以数据为核心,围绕数据生命周期进行的数据安全管理体系,从组织建设、制度设计、人员管理、产品技术、个人信息安全影响评估方面多维度提升整个系统的安全性。</p><p>我们有行业先进的以数据为核心,围绕数据生命周期进行的数据安全管理体系,从组织建设、制度设计、人员管理、产品技术、个人信息安全影响评估方面多维度提升整个系统的安全性。</p><p>我们对可能接触到您的信息的员工或外包人员也采取了严格管理,包括但不限于根据岗位的不同采取不同的权限控制,与他们签署保密协议,监控他们的操作情况措施。</p><p>(三)账号保护</p><p>您的账户均有安全保护功能,请妥善保管您的账户及密码信息。如果您发现账号被盗用或个人信息泄露,请及时联系我们,以便我们采取相应措施。</p><p>(四)信息安全事件处理</p><p>尽管有前述安全措施,但同时也请您理解在信息网络上不存在“完善的安全措施”。</p><p>若不幸发生个人信息安全事件,我们将按照法律法规的要求向您告知:安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施。事件相关情况我们将以电话、推送通知的方式告知您,难以逐一告知个人信息主体时,我们会采取合理、有效的方式发布公告。同时,我们还将按照监管部门要求,上报个人信息安全事件的处置情况。</p><p>(五)保存期限</p><p>我们仅在中国大陆地区存放您的个人信息。我们会采取一切合理可行的措施,确保未收集无关的个人信息。我们只会在达成本政策所述目的所需的且法律规定的最短期限内保留您的个人信息,除非需要延长保留期或受到法律的允许。</p><p>在您的个人信息超出保留期间后,我们会根据法律法规的要求删除您的个人信息、或使其匿名化处理。</p><p>五、您的权利<br>按照中国相关的法律、法规、标准,我们保障您对自己的个人信息行使以下权利:</p><p>(一)访问您的个人信息</p><p>您有权通过用户中心自行访问您的个人信息,可参见(六)我们如何响应您的请求,法律法规规定的例外情况除外</p><p>(二)更正您的个人信息</p><p>当您发现我们处理的关于您的个人信息有错误时,您有权要求我们做出更正。如何更正个人信息,可参见(六)我们如何响应您的请求。</p><p>(三)删除您的个人信息 在下述情形中,您可以向我们提出删除个人信息的请求:</p><p>1、我们处理个人信息的行为违反法律法规;</p><p>2、我们收集、使用您的个人信息,却未征得您的同意;</p><p>3、我们处理个人信息的行为违反了与您的约定;</p><p>4、您不再使用我们的产品或服务,或您注销了账号;</p><p>5、我们不再为您提供产品或服务。</p><p>如何删除个人信息,可参见(六)我们如何响应您的请求,若我们决定遵循您的请求,我们还将同时通知从我们获得您的个人信息的实体要求其及时删除,除非法律法规另有规定,或这些实体获得您的独立授权。</p><p>当您从我们的服务中删除信息后,我们可能不会立即在备份系统中删除相应的信息,但会在备份更新时删除这些信息。</p><p>(六)响应您的上述请求</p><p>您可以通过手机“设置”功能选择关闭您希望关闭的权限。</p><p>您还可以通过个人中心查看您的个人信息,也可以点击“我的”-“联系客服”,进行个人信息查询、个人信息更正、个人信息删除、用户账户注销、撤回已同意的授权的用户操作,为保障安全,您可能需要提供书面请求,或以其他方式证明您的身份。我们可能会先要求您验证自己的身份,然后再处理您的请求。</p><p>我们将在十五个工作日内作出答复。若您不满意,还可以通过与客服联系进行申诉。</p><p>七、本政策如何更新<br>本隐私政策更新后,本平台会在您登录及版本更新时以推送通知、弹窗、在网站公告形式向您展示变更后的隐私政策与内容,以便您及时了解本隐私政策的最新版本。我们将严格遵循向您披露的隐私政策收集使用规则开展个人信息处理活动,若个人信息使用目的发生变化时会再次征得您的同意,若您继续使用我们的服务,表示同意接受修订后的本政策的内容。</p><p>八、本政策的适用<br>本产品的所有服务均适用本政策。</p><p>当您在首次登录本产品时,我们会提示您进行阅读本政策,并征得您的同意。除非另有约定或者法律规定,本隐私政策不适用于龙岩创客科技有限公司和本产品登记著作权人链接到其他第三方的产品或服务,您使用这些第三方服务(包括您向这些第三方提供的任何个人信息),将受这些第三方的服务条款及隐私政策约束(而非本隐私政策),具体规定请您仔细阅读第三方的条款。请您妥善保护自己的个人信息,仅在必要的情况下向第三方提供。</p><p>九、争议管辖<br>本隐私政策的成立、生效、履行、解释及纠纷解决,适用中华人民共和国大陆地区法律。</p><p>若您和我们发生任何纠纷或争议,首先应友好协商解决;协商不成的,均提请北京仲裁委员会按照其仲裁规则进行仲裁。仲裁裁决是终局的,对双方均有约束力。</p><p>十、联系我们<br>公司名称:龙岩创客科技有限公司</p><p>注册地址:漳平市桂林街道桂滨路 8 号 301 室</p><p>个人信息保护相关负责人联系方式:</p><p>客服电子邮件:<a href="mailto:jerome_77777@163.com">jerome_77777@163.com</a></p><p>您在产品使用的过程中及对本隐私政策有任何疑问、意见和建议的,均可通过以上联系方式与我们联系。</p>]]></content>
</entry>
<entry>
<title>算法题汇总</title>
<link href="/2022/02/16/algorithm-face/"/>
<url>/2022/02/16/algorithm-face/</url>
<content type="html"><![CDATA[<h2 id="常规"><a href="#常规" class="headerlink" title="常规"></a>常规</h2><h3 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> PENDING = <span class="hljs-string">'PANDING'</span><br><span class="hljs-keyword">const</span> FULFILLED = <span class="hljs-string">'FULFILLED'</span><br><span class="hljs-keyword">const</span> REJECTED = <span class="hljs-string">'REJECTED'</span><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Promise</span> </span>{<br> <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">executor</span>)</span> {<br> <span class="hljs-comment">// 状态</span><br> <span class="hljs-built_in">this</span>.status = PENDING<br> <span class="hljs-comment">// 失败原因</span><br> <span class="hljs-built_in">this</span>.reason = <span class="hljs-literal">undefined</span><br> <span class="hljs-comment">// 成功的值</span><br> <span class="hljs-built_in">this</span>.value = <span class="hljs-literal">undefined</span><br> <span class="hljs-built_in">this</span>.onResolveCallback = []<br> <span class="hljs-built_in">this</span>.onRejectCallback = []<br><br> <span class="hljs-keyword">let</span> resolve = <span class="hljs-function">(<span class="hljs-params">value</span>) =></span> {<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.status === PENDING) {<br> <span class="hljs-built_in">this</span>.status = FULFILLED<br> <span class="hljs-built_in">this</span>.value = value<br> <span class="hljs-built_in">this</span>.onResolveCallback.forEach(<span class="hljs-function"><span class="hljs-params">fn</span> =></span> fn())<br> }<br> }<br><br> <span class="hljs-keyword">let</span> reject = <span class="hljs-function">(<span class="hljs-params">reason</span>) =></span> {<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.status === PENDING) {<br> <span class="hljs-built_in">this</span>.status = REJECTED<br> <span class="hljs-built_in">this</span>.reason = reason<br> <span class="hljs-built_in">this</span>.onRejectCallback.forEach(<span class="hljs-function"><span class="hljs-params">fn</span> =></span> fn())<br> }<br> }<br><br> <span class="hljs-keyword">try</span> {<br> executor(resolve, reject)<br> } <span class="hljs-keyword">catch</span> (error) {<br> reject(error)<br> }<br> }<br><br> <span class="hljs-function"><span class="hljs-title">then</span>(<span class="hljs-params">onFullfilled, onRejected</span>)</span> {<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.status === FULFILLED) {<br> onFullfilled(<span class="hljs-built_in">this</span>.value)<br> }<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.status === REJECTED) {<br> onRejected(<span class="hljs-built_in">this</span>.reason)<br> }<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.status === PENDING) {<br> <span class="hljs-built_in">this</span>.onResolveCallback.push(<span class="hljs-function">() =></span> {<br> onFullfilled(<span class="hljs-built_in">this</span>.value)<br> })<br> <span class="hljs-built_in">this</span>.onRejectCallback.push(<span class="hljs-function">() =></span> {<br> onRejected(<span class="hljs-built_in">this</span>.reason)<br> })<br> }<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="Object-create"><a href="#Object-create" class="headerlink" title="Object.create"></a>Object.create</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params">obj</span>) </span>{<br> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">F</span>(<span class="hljs-params"></span>) </span>{}<br> F.prototype = obj<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> F()<br>}<br></code></pre></td></tr></table></figure><h3 id="new-操作符"><a href="#new-操作符" class="headerlink" title="new 操作符"></a>new 操作符</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">objectFactory</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-keyword">let</span> newObj = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">let</span> <span class="hljs-title">constructor</span> = <span class="hljs-title">Array</span>.<span class="hljs-title">prototype</span>.<span class="hljs-title">shift</span>.<span class="hljs-title">call</span>(<span class="hljs-params"><span class="hljs-built_in">arguments</span></span>)<br> <span class="hljs-title">let</span> <span class="hljs-title">result</span> = <span class="hljs-title">null</span><br> <span class="hljs-title">if</span>(<span class="hljs-params"><span class="hljs-keyword">typeof</span> constructor !== <span class="hljs-string">"function"</span></span>) {<br> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'type error'</span>)<br> <span class="hljs-keyword">return</span><br> }<br> newObj = <span class="hljs-built_in">Object</span>.create(<span class="hljs-title">constructor</span>.<span class="hljs-title">prototype</span>)<br> <span class="hljs-title">result</span> = <span class="hljs-title">constructor</span>.<span class="hljs-title">apply</span>(<span class="hljs-params">newObj, <span class="hljs-built_in">arguments</span></span>)<br> <span class="hljs-title">let</span> <span class="hljs-title">flag</span> = <span class="hljs-title">result</span> && (<span class="hljs-params"><span class="hljs-keyword">typeof</span> result === <span class="hljs-string">'object'</span> || <span class="hljs-keyword">typeof</span> result === <span class="hljs-string">'function'</span></span>)<br> <span class="hljs-title">return</span> <span class="hljs-title">flag</span> ? <span class="hljs-title">result</span> : <span class="hljs-title">newObj</span><br>}<br></code></pre></td></tr></table></figure><h3 id="Promise-all"><a href="#Promise-all" class="headerlink" title="Promise.all"></a>Promise.all</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">promiseAll</span>(<span class="hljs-params">promises</span>) </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> {<br> <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">Array</span>.isArray(promises)) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">'argument must be an array'</span>)<br> }<br> <span class="hljs-keyword">let</span> result = []<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < promises.length; i++) {<br> <span class="hljs-built_in">Promise</span>.resolve(promises[i]).then(<span class="hljs-function"><span class="hljs-params">value</span> =></span> {<br> result.push(value)<br> <span class="hljs-keyword">if</span> (i === promises.length - <span class="hljs-number">1</span>) {<br> resolve(result)<br> }<br> }, <span class="hljs-function"><span class="hljs-params">err</span> =></span> {<br> reject(err)<br> })<br> }<br> })<br>}<br></code></pre></td></tr></table></figure><h3 id="Promise-race"><a href="#Promise-race" class="headerlink" title="Promise.race"></a>Promise.race</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">promiseRace</span>(<span class="hljs-params">promises</span>) </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < promises.length; i++) {<br> promises[i].then(resolve, reject)<br> }<br> })<br>}<br></code></pre></td></tr></table></figure><h3 id="防抖函数"><a href="#防抖函数" class="headerlink" title="防抖函数"></a>防抖函数</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">debounce</span>(<span class="hljs-params">fn, wait</span>) </span>{<br> <span class="hljs-keyword">let</span> timer = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">return</span> <span class="hljs-function">() =></span> {<br> <span class="hljs-keyword">if</span> (timer) {<br> <span class="hljs-built_in">clearTimeout</span>(timer)<br> timer = <span class="hljs-literal">null</span><br> }<br><br> timer = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {<br> fn.apply(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>)<br> timer = <span class="hljs-literal">null</span><br> }, wait)<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="节流函数"><a href="#节流函数" class="headerlink" title="节流函数"></a>节流函数</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">throttle</span>(<span class="hljs-params">fn, delay</span>) </span>{<br> <span class="hljs-keyword">let</span> timer = <span class="hljs-literal">null</span><br><br> <span class="hljs-keyword">return</span> <span class="hljs-function">() =></span> {<br> <span class="hljs-keyword">if</span> (timer) {<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {<br> fn.call(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>)<br> timer = <span class="hljs-literal">null</span><br> }, delay)<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="call-函数"><a href="#call-函数" class="headerlink" title="call 函数"></a>call 函数</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-built_in">Function</span>.prototype.myCall = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) </span>{<br> context = context || <span class="hljs-built_in">window</span><br> context.fn = <span class="hljs-built_in">this</span><br> <span class="hljs-keyword">let</span> args = [...arguments].splice(<span class="hljs-number">1</span>)<br> <span class="hljs-keyword">let</span> result = context.fn(...args)<br> <span class="hljs-keyword">delete</span> context.fn<br> <span class="hljs-keyword">return</span> result<br>}<br></code></pre></td></tr></table></figure><h3 id="apply-函数"><a href="#apply-函数" class="headerlink" title="apply 函数"></a>apply 函数</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-built_in">Function</span>.prototype.myApply = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) </span>{<br> context = context || <span class="hljs-built_in">window</span><br> context.fn = <span class="hljs-built_in">this</span><br> <span class="hljs-keyword">let</span> args = [...arguments].splice(<span class="hljs-number">1</span>)[<span class="hljs-number">0</span>] <span class="hljs-comment">// 取第二个参数</span><br> <span class="hljs-keyword">if</span>(!<span class="hljs-built_in">Array</span>.isArray(args)) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">'apply second argument must be an array'</span>)<br> }<br> <span class="hljs-keyword">let</span> result = context.fn(args)<br> <span class="hljs-keyword">delete</span> context.fn<br> <span class="hljs-keyword">return</span> result<br>}<br></code></pre></td></tr></table></figure><h3 id="bind-函数"><a href="#bind-函数" class="headerlink" title="bind 函数"></a>bind 函数</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-built_in">Function</span>.prototype.myBind = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">context</span>) </span>{<br> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">this</span> !== <span class="hljs-string">'function'</span>) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">'bind must be use by a function'</span>)<br> }<br> <span class="hljs-keyword">let</span> self = <span class="hljs-built_in">this</span><br> <span class="hljs-keyword">let</span> args = <span class="hljs-built_in">Array</span>.prototype.slice.call(<span class="hljs-built_in">arguments</span>, <span class="hljs-number">1</span>)<br> <span class="hljs-keyword">let</span> fbound = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-keyword">return</span> self.apply(<span class="hljs-built_in">this</span> <span class="hljs-keyword">instanceof</span> fbound ? <span class="hljs-built_in">this</span> : context, args.concat([].slice.call(<span class="hljs-built_in">arguments</span>)))<br> }<br><br> <span class="hljs-keyword">let</span> func = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{}<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.prototype) {<br> func.prototype = <span class="hljs-built_in">this</span>.prototype<br> }<br> fbound.prototype = <span class="hljs-keyword">new</span> func()<br> <span class="hljs-keyword">return</span> fbound<br>}<br></code></pre></td></tr></table></figure><h3 id="Ajax-请求"><a href="#Ajax-请求" class="headerlink" title="Ajax 请求"></a>Ajax 请求</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ajax</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-keyword">let</span> xhr = <span class="hljs-keyword">new</span> XMLHttpRequest()<br> xhr.open(<span class="hljs-string">'GET'</span>, <span class="hljs-string">'http://xx'</span>, <span class="hljs-literal">true</span>)<br> xhr.onreadystatechange = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.readyState !== <span class="hljs-number">4</span>) <span class="hljs-keyword">return</span><br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.status === <span class="hljs-number">200</span>) {<br> handle(<span class="hljs-built_in">this</span>.response)<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-built_in">console</span>.error(<span class="hljs-built_in">this</span>.statusText)<br> }<br> }<br><br> xhr.onerror = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">console</span>.error(<span class="hljs-built_in">this</span>.statusText)<br> }<br><br> xhr.responseType = <span class="hljs-string">'json'</span><br> xhr.setRequestHeader(<span class="hljs-string">"Accept"</span>, <span class="hljs-string">"application/json"</span>);<br> xhr.send(<span class="hljs-literal">null</span>);<br>}<br></code></pre></td></tr></table></figure><h3 id="实现链式调用"><a href="#实现链式调用" class="headerlink" title="实现链式调用"></a>实现链式调用</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">u.console(<span class="hljs-string">``</span><span class="hljs-string">'breakfast'</span><span class="hljs-string">``</span>).setTimeout(<span class="hljs-number">3000</span>).console(<span class="hljs-string">``</span><span class="hljs-string">'lunch'</span><span class="hljs-string">``</span>).setTimeout(<span class="hljs-number">3000</span>).console(<span class="hljs-string">``</span><span class="hljs-string">'dinner'</span><span class="hljs-string">``</span>)<br></code></pre></td></tr></table></figure><figure class="highlight js"><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><code class="hljs js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">U</span> </span>{<br> <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> {<br> <span class="hljs-built_in">this</span>.promise = <span class="hljs-built_in">Promise</span>.resolve()<br> }<br><br> <span class="hljs-function"><span class="hljs-title">console</span>(<span class="hljs-params">val</span>)</span> {<br> <span class="hljs-built_in">this</span>.promise = <span class="hljs-built_in">this</span>.promise.then(<span class="hljs-function">() =></span> {<br> <span class="hljs-built_in">console</span>.log(val)<br> })<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span><br> }<br><br> <span class="hljs-function"><span class="hljs-title">setTimeout</span>(<span class="hljs-params">wait</span>)</span> {<br> <span class="hljs-built_in">this</span>.promise = <span class="hljs-built_in">this</span>.promise.then(<span class="hljs-function">() =></span> {<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> {<br> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {<br> resolve()<br> }, wait)<br> })<br> })<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span><br> }<br>}<br><br><span class="hljs-keyword">const</span> u = <span class="hljs-keyword">new</span> U()<br></code></pre></td></tr></table></figure><h3 id="深拷贝浅拷贝"><a href="#深拷贝浅拷贝" class="headerlink" title="深拷贝浅拷贝"></a>深拷贝浅拷贝</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">simpleClone</span>(<span class="hljs-params">originObj</span>) </span>{<br> <span class="hljs-keyword">let</span> newObj = {}<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> key <span class="hljs-keyword">in</span> originObj) {<br> newObj[key] = originObj[key]<br> }<br> <span class="hljs-keyword">return</span> newObj<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deepClone</span>(<span class="hljs-params">originObj</span>) </span>{<br> <span class="hljs-keyword">let</span> newObj = originObj.constructor === <span class="hljs-built_in">Array</span> ? [] : {}<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> key <span class="hljs-keyword">in</span> originObj) {<br> <span class="hljs-keyword">if</span> (originObj[key] && <span class="hljs-keyword">typeof</span> originObj[key] === <span class="hljs-string">'object'</span>) {<br> newObj[key] = deepClone(originObj[key])<br> } <span class="hljs-keyword">else</span> {<br> newObj[key] = originObj[key]<br> }<br> }<br> <span class="hljs-keyword">return</span> newObj<br>}<br></code></pre></td></tr></table></figure><h3 id="setTimeout、setInterval"><a href="#setTimeout、setInterval" class="headerlink" title="setTimeout、setInterval"></a>setTimeout、setInterval</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mySetTimeout</span>(<span class="hljs-params">fn, timeout</span>) </span>{<br> <span class="hljs-keyword">let</span> timer<br> <span class="hljs-keyword">let</span> startTime = <span class="hljs-built_in">Date</span>.now()<br> <span class="hljs-keyword">const</span> loop = <span class="hljs-function">() =></span> {<br> timer = <span class="hljs-built_in">window</span>.requestAnimationFrame(loop)<br> <span class="hljs-keyword">if</span>(startTime - <span class="hljs-built_in">Date</span>.now() >= timeout) {<br> fn.call(<span class="hljs-built_in">this</span>, timer)<br> <span class="hljs-built_in">window</span>.cancelAnimationFrame(timer)<br> }<br> }<br> <span class="hljs-built_in">window</span>.requestAnimationFrame(loop)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mySetInterval</span>(<span class="hljs-params">fn, interval</span>) </span>{<br> <span class="hljs-keyword">let</span> timer<br> <span class="hljs-keyword">let</span> startTime = <span class="hljs-built_in">Date</span>.now()<br> <span class="hljs-keyword">const</span> loop = <span class="hljs-function">() =></span> {<br> timer = <span class="hljs-built_in">window</span>.requestAnimationFrame(loop)<br> <span class="hljs-keyword">if</span>(startTime - <span class="hljs-built_in">Date</span>.now() >= timeout) {<br> fn.call(<span class="hljs-built_in">this</span>, timer)<br> startTime = <span class="hljs-built_in">Date</span>.now()<br> }<br> }<br> <span class="hljs-built_in">window</span>.requestAnimationFrame(loop)<br>}<br></code></pre></td></tr></table></figure><h3 id="实现-instanceof"><a href="#实现-instanceof" class="headerlink" title="实现 instanceof"></a>实现 instanceof</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myInstanceOf</span>(<span class="hljs-params">obj, type</span>) </span>{<br> <span class="hljs-keyword">let</span> o = type.prototype,<br> l = obj.__proto__<br> <span class="hljs-keyword">while</span>(<span class="hljs-literal">true</span>) {<br> <span class="hljs-keyword">if</span>(l === <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">if</span>(l === o) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> }<br> l = l.__proto__<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="比较两个版本号大小"><a href="#比较两个版本号大小" class="headerlink" title="比较两个版本号大小"></a>比较两个版本号大小</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">compareVersion</span>(<span class="hljs-params">version1, version2</span>) </span>{<br> <span class="hljs-keyword">let</span> num1 = version1.split(<span class="hljs-string">'.'</span>)<br> <span class="hljs-keyword">let</span> num2 = version2.split(<span class="hljs-string">'.'</span>)<br> <span class="hljs-keyword">let</span> n1 = num1.length,<br> n2 = num2.length<br> <span class="hljs-keyword">let</span> i1, i2<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-built_in">Math</span>.max(n1, n2); i++) {<br> i1 = i < n1 ? <span class="hljs-built_in">parseInt</span>(num1[i]) : <span class="hljs-number">0</span><br> i2 = i < n2 ? <span class="hljs-built_in">parseInt</span>(num2[i]) : <span class="hljs-number">0</span><br> <span class="hljs-keyword">if</span> (i1 !== i2) {<br> <span class="hljs-keyword">return</span> i1 > i2 ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span><br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="函数坷里化"><a href="#函数坷里化" class="headerlink" title="函数坷里化"></a>函数坷里化</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">curry</span>(<span class="hljs-params">func</span>) </span>{<br><span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">curried</span>(<span class="hljs-params">...args</span>) </span>{<br><span class="hljs-keyword">if</span>(args.length >= func.length) {<br><span class="hljs-keyword">return</span> func.apply(<span class="hljs-built_in">this</span>, args)<br>}<span class="hljs-keyword">else</span> {<br><span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">...args2</span>) </span>{<br><span class="hljs-keyword">return</span> curried.apply(<span class="hljs-built_in">this</span>, args.concat(args2))<br>}<br>}<br>}<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sum</span>(<span class="hljs-params">a, b, c</span>) </span>{<br><span class="hljs-keyword">return</span> a+b+c<br>}<br><br><span class="hljs-keyword">let</span> curriedSum = curry(sum)<br></code></pre></td></tr></table></figure><h3 id="数组扁平化"><a href="#数组扁平化" class="headerlink" title="数组扁平化"></a>数组扁平化</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">faltten</span>(<span class="hljs-params">arr</span>) </span>{<br> <span class="hljs-keyword">return</span> arr.reduce(<span class="hljs-function">(<span class="hljs-params">pre, cur</span>) =></span> {<br> <span class="hljs-keyword">return</span> pre.concat(<span class="hljs-built_in">Array</span>.isArray(cur) ? faltten(cur) : cur);<br> }, [])<br>}<br></code></pre></td></tr></table></figure><h2 id="树"><a href="#树" class="headerlink" title="树"></a>树</h2><h3 id="路径总和"><a href="#路径总和" class="headerlink" title="路径总和"></a>路径总和</h3><p>给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。</p><figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs nix">输入:<span class="hljs-attr">root</span> = [<span class="hljs-number">5</span>,<span class="hljs-number">4</span>,<span class="hljs-number">8</span>,<span class="hljs-number">11</span>,<span class="hljs-literal">null</span>,<span class="hljs-number">13</span>,<span class="hljs-number">4</span>,<span class="hljs-number">7</span>,<span class="hljs-number">2</span>,<span class="hljs-literal">null</span>,<span class="hljs-literal">null</span>,<span class="hljs-literal">null</span>,<span class="hljs-number">1</span>], <span class="hljs-attr">targetSum</span> = <span class="hljs-number">22</span><br>输出:<span class="hljs-literal">true</span><br></code></pre></td></tr></table></figure><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> hasPathSum = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">root, targetSum</span>) </span>{<br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">if</span>(root.left == <span class="hljs-literal">null</span> && root.right == <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> targetSum - root.val == <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">return</span> hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val)<br>};<br></code></pre></td></tr></table></figure><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h3 id="按之字形顺序打印二叉树"><a href="#按之字形顺序打印二叉树" class="headerlink" title="按之字形顺序打印二叉树"></a>按之字形顺序打印二叉树</h3><p>给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Print</span>(<span class="hljs-params">pRoot</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!pRoot) {<br> <span class="hljs-keyword">return</span> []<br> }<br> <span class="hljs-keyword">let</span> stack = [], flag=<span class="hljs-literal">true</span>, res = []<br> stack.push(pRoot)<br> <span class="hljs-keyword">while</span>(stack.length > <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">let</span> levelArr = []<br> <span class="hljs-keyword">let</span> size = stack.length<br> <span class="hljs-keyword">while</span>(size > <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">let</span> node = stack.shift()<br> levelArr.push(node.val)<br> <span class="hljs-keyword">if</span>(node.left) {<br> stack.push(node.left)<br> }<br> <span class="hljs-keyword">if</span>(node.right) {<br> stack.push(node.right)<br> }<br> size --<br> }<br> flag = !flag<br> flag ? res.push(levelArr.reverse()) : res.push(levelArr)<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="求二叉树的层序遍历"><a href="#求二叉树的层序遍历" class="headerlink" title="求二叉树的层序遍历"></a>求二叉树的层序遍历</h3><p>给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历)</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">levelOrder</span>(<span class="hljs-params"> root </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> []<br> }<br> <span class="hljs-keyword">let</span> stack = [], res = []<br> stack.push(root)<br> <span class="hljs-keyword">while</span>(stack.length > <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">let</span> len = stack.length<br> <span class="hljs-keyword">let</span> levelArr = []<br> <span class="hljs-keyword">while</span>(len > <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">let</span> node = stack.shift()<br> levelArr.push(node.val)<br> <span class="hljs-keyword">if</span>(node.left) {<br> stack.push(node.left)<br> }<br> <span class="hljs-keyword">if</span>(node.right) {<br> stack.push(node.right)<br> }<br> len --<br> }<br> res.push(levelArr)<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="-1"><a href="#-1" class="headerlink" title=""></a></h3><h3 id="实现二叉树先序,中序和后序遍历"><a href="#实现二叉树先序,中序和后序遍历" class="headerlink" title="实现二叉树先序,中序和后序遍历"></a><strong>实现二叉树先序,中序和后序遍历</strong></h3><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> pre = []<br><span class="hljs-keyword">let</span> mid = []<br><span class="hljs-keyword">let</span> after = []<br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">threeOrders</span>(<span class="hljs-params"> root </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> [pre, mid, after]<br> }<br> preOrder(root)<br> midOrder(root)<br> afterOrder(root)<br> <span class="hljs-keyword">return</span> [pre, mid, after]<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">preOrder</span>(<span class="hljs-params">root</span>) </span>{<br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span><br> }<br> pre.push(root.val)<br> preOrder(root.left)<br> preOrder(root.right)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">midOrder</span>(<span class="hljs-params">root</span>) </span>{<br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span><br> }<br> midOrder(root.left)<br> mid.push(root.val)<br> midOrder(root.right)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">afterOrder</span>(<span class="hljs-params">root</span>) </span>{<br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span><br> }<br> afterOrder(root.left)<br> afterOrder(root.right)<br> after.push(root.val)<br>}<br></code></pre></td></tr></table></figure><h3 id="二叉树的镜像"><a href="#二叉树的镜像" class="headerlink" title="二叉树的镜像"></a><strong>二叉树的镜像</strong></h3><p>操作给定的二叉树,将其变换为源二叉树的镜像。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Mirror</span>(<span class="hljs-params">pRoot</span>) </span>{<br> <span class="hljs-keyword">if</span> (pRoot) {<br> <span class="hljs-keyword">let</span> temp = pRoot.left;<br> pRoot.left = pRoot.right;<br> pRoot.right = temp;<br> Mirror(pRoot.left);<br> Mirror(pRoot.right);<br> <span class="hljs-keyword">return</span> pRoot;<br> }<br>}<br><br></code></pre></td></tr></table></figure><h3 id="把二叉树打印成多行"><a href="#把二叉树打印成多行" class="headerlink" title="把二叉树打印成多行"></a><strong>把二叉树打印成多行</strong></h3><p>给定一个节点数为 n 二叉树,要求从上到下按层打印二叉树的 val 值,同一层结点从左至右输出,每一层输出一行,将输出的结果存放到一个二维数组中返回。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Print</span>(<span class="hljs-params">pRoot</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!pRoot) {<br> <span class="hljs-keyword">return</span> []<br> }<br> <span class="hljs-keyword">let</span> stack = []<br> <span class="hljs-keyword">let</span> res = []<br> stack.unshift(pRoot)<br> <span class="hljs-keyword">while</span>(stack.length!==<span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">let</span> size = stack.length<br> <span class="hljs-keyword">let</span> tempRes = []<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<size; i++) {<br> <span class="hljs-keyword">let</span> temp = stack.pop()<br> tempRes.push(temp.val)<br> <span class="hljs-keyword">if</span>(temp.left) {<br> stack.unshift(temp.left)<br> }<br> <span class="hljs-keyword">if</span>(temp.right) {<br> stack.unshift(temp.right)<br> }<br> }<br> res.push(tempRes)<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="在二叉树中找到两个节点的最近公共祖先"><a href="#在二叉树中找到两个节点的最近公共祖先" class="headerlink" title="在二叉树中找到两个节点的最近公共祖先"></a><strong>在二叉树中找到两个节点的最近公共祖先</strong></h3><p>给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lowestCommonAncestor</span>(<span class="hljs-params"> root , o1 , o2 </span>) </span>{<br> <span class="hljs-keyword">return</span> helper(root, o1, o2).val<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">helper</span>(<span class="hljs-params">root, o1, o2</span>) </span>{<br> <span class="hljs-keyword">if</span>(root ==<span class="hljs-literal">null</span> || root.val == o1 || root.val === o2){<br> <span class="hljs-keyword">return</span> root<br> }<br> <span class="hljs-keyword">let</span> left = helper(root.left, o1, o2)<br> <span class="hljs-keyword">let</span> right = helper(root.right, o1, o2)<br> <span class="hljs-keyword">if</span>(left == <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> right<br> }<br> <span class="hljs-keyword">if</span>(right ==<span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> left<br> }<br> <span class="hljs-keyword">return</span> root<br>}<br></code></pre></td></tr></table></figure><h3 id="二叉树的深度"><a href="#二叉树的深度" class="headerlink" title="二叉树的深度"></a><strong>二叉树的深度</strong></h3><p>输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度,根节点的深度视为 1 。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/* function TreeNode(x) {</span><br><span class="hljs-comment"> this.val = x;</span><br><span class="hljs-comment"> this.left = null;</span><br><span class="hljs-comment"> this.right = null;</span><br><span class="hljs-comment">} */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxDepth</span>(<span class="hljs-params"> root </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">let</span> res = <span class="hljs-number">0</span><br> <span class="hljs-keyword">let</span> queue = []<br> queue.push(root)<br> <span class="hljs-keyword">while</span>(queue.length > <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">let</span> len = queue.length<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<len; i++) {<br> <span class="hljs-keyword">const</span> node = queue.shift()<br> <span class="hljs-keyword">if</span>(node.left) {<br> queue.push(node.left)<br> }<br> <span class="hljs-keyword">if</span>(node.right) {<br> queue.push(node.right)<br> }<br> }<br> res ++<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="二叉树的下一个结点"><a href="#二叉树的下一个结点" class="headerlink" title="二叉树的下一个结点"></a><strong>二叉树的下一个结点</strong></h3><p>给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。下图为一棵有9个节点的二叉树。树中从父节点指向子节点的指针用实线表示,从子节点指向父节点的用虚线表示</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetNext</span>(<span class="hljs-params">pNode</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(pNode === <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span><br> }<br> <span class="hljs-keyword">if</span>(pNode.right !== <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">let</span> p1 = pNode.right<br> <span class="hljs-keyword">while</span>(p1.left !== <span class="hljs-literal">null</span>) {<br> p1 = p1.left<br> }<br> <span class="hljs-keyword">return</span> p1<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(pNode.next !== <span class="hljs-literal">null</span> && pNode === pNode.next.left) {<br> <span class="hljs-keyword">return</span> pNode.next<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(pNode.next !== <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">let</span> p2 = pNode.next<br> <span class="hljs-keyword">while</span>(p2.next !== <span class="hljs-literal">null</span> && p2 === p2.next.right) {<br> p2 = p2.next<br> }<br> <span class="hljs-keyword">return</span> p2.next<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span> <br>}<br></code></pre></td></tr></table></figure><h3 id="输出二叉树的右视图"><a href="#输出二叉树的右视图" class="headerlink" title="输出二叉树的右视图"></a><strong>输出二叉树的右视图</strong></h3><p>请根据二叉树的前序遍历,中序遍历恢复二叉树,并打印出二叉树的右视图</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">solve</span>(<span class="hljs-params"> xianxu , zhongxu </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> level = <span class="hljs-number">0</span><br> <span class="hljs-keyword">let</span> res = []<br> rebuild(xianxu, zhongxu, level, res)<br> <span class="hljs-keyword">return</span> res<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rebuild</span>(<span class="hljs-params">xianxu, zhongxu, level, res</span>) </span>{<br> <span class="hljs-keyword">if</span>(xianxu.length == <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span><br> }<br> <span class="hljs-keyword">const</span> root = xianxu[<span class="hljs-number">0</span>]<br> <span class="hljs-keyword">const</span> index = zhongxu.findIndex(<span class="hljs-function"><span class="hljs-params">node</span> =></span> node === root)<br> <span class="hljs-comment">// 左子树先序遍历结果</span><br> <span class="hljs-keyword">const</span> leftNodePreOrder = xianxu.slice(<span class="hljs-number">1</span>, index+<span class="hljs-number">1</span>)<br> <span class="hljs-comment">// 左子树中序遍历结果</span><br> <span class="hljs-keyword">const</span> leftNodeInOrder = zhongxu.slice(<span class="hljs-number">0</span>, index)<br> <span class="hljs-comment">// 右子树先序遍历结果</span><br> <span class="hljs-keyword">const</span> rightNodePreOrder = xianxu.slice(index + <span class="hljs-number">1</span>)<br> <span class="hljs-comment">// 右子树中序遍历结果</span><br> <span class="hljs-keyword">const</span> rightNodeInOrder = zhongxu.slice(index + <span class="hljs-number">1</span>)<br> rebuild(leftNodePreOrder, leftNodeInOrder, level+<span class="hljs-number">1</span>, res)<br> rebuild(rightNodePreOrder, rightNodeInOrder, level+<span class="hljs-number">1</span>, res)<br> res[level] = root<br>}<br></code></pre></td></tr></table></figure><h3 id="二叉树根节点到叶子节点的所有路径和"><a href="#二叉树根节点到叶子节点的所有路径和" class="headerlink" title="二叉树根节点到叶子节点的所有路径和"></a><strong>二叉树根节点到叶子节点的所有路径和</strong></h3><p>给定一个二叉树的根节点root,该树的节点值都在数字\ 0-9 0−9 之间,每一条从根节点到叶子节点的路径都可以用一个数字表示。</p><p>1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点<br>2.叶子节点是指没有子节点的节点<br>3.路径只能从父节点到子节点,不能从子节点到父节点<br>4.总节点数目为n</p><p>例如根节点到叶子节点的一条路径是1\to 2\to 31→2→3,那么这条路径就用\ 123 123 来代替。<br>找出根节点到叶子节点的所有路径表示的数字之和<br>例如:</p><p><img src="https://uploadfiles.nowcoder.com/images/20200807/999991351_1596786228797_BC85E8592A231E74E5338EBA1CFB2D20" alt="img"></p><p>这颗二叉树一共有两条路径,<br>根节点到叶子节点的路径 1\to 21→2 用数字\ 12 12 代替<br>根节点到叶子节点的路径 1\to 31→3 用数字\ 13 13 代替<br>所以答案为\ 12+13=25 12+13=25</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sumNumbers</span>(<span class="hljs-params"> root </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">let</span> res = [], item = [], ans = <span class="hljs-number">0</span><br> dfs(root,item, res)<br> <span class="hljs-built_in">console</span>.log(res)<br> <span class="hljs-keyword">if</span>(res.length ==<span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">parseInt</span>(res[<span class="hljs-number">0</span>].join(<span class="hljs-string">''</span>))<br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<res.length; i++) {<br> <span class="hljs-keyword">if</span>(res[i].length > <span class="hljs-number">1</span>) {<br> ans += <span class="hljs-built_in">parseInt</span>(res[i].join(<span class="hljs-string">''</span>))<br> }<br> }<br> <span class="hljs-keyword">return</span> ans<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dfs</span>(<span class="hljs-params">root,item, res</span>) </span>{<br> item.push(root.val)<br> <span class="hljs-keyword">if</span>(root.left) {<br> dfs(root.left,item, res)<br> item.pop()<br> }<br> <span class="hljs-keyword">if</span>(root.right) {<br> dfs(root.right,item, res)<br> item.pop()<br> }<br> <span class="hljs-keyword">if</span>(!root.left && !root.right) {<br> res.push([].concat(item))<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="对称的二叉树"><a href="#对称的二叉树" class="headerlink" title="对称的二叉树"></a><strong>对称的二叉树</strong></h3><p>给定一棵二叉树,判断其是否是自身的镜像(即:是否对称)</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isSymmetrical</span>(<span class="hljs-params">pRoot</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">return</span> isSame(pRoot, pRoot)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isSame</span>(<span class="hljs-params">root1, root2</span>) </span>{<br> <span class="hljs-keyword">if</span>(!root1 && !root2) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> <span class="hljs-keyword">if</span>(!root1 || !root2) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> <span class="hljs-keyword">return</span> root1.val == root2.val && isSame(root1.left, root2.right) && <br> isSame(root1.right, root2.left)<br>}<br></code></pre></td></tr></table></figure><h3 id="合并二叉树"><a href="#合并二叉树" class="headerlink" title="合并二叉树"></a><strong>合并二叉树</strong></h3><p>已知两颗二叉树,将它们合并成一颗二叉树。合并规则是:都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mergeTrees</span>(<span class="hljs-params"> t1 , t2 </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!t1) <span class="hljs-keyword">return</span> t2<br> <span class="hljs-keyword">if</span>(!t2) <span class="hljs-keyword">return</span> t1<br> t1.val = t1.val + t2.val<br> t1.left = mergeTrees(t1.left, t2.left)<br> t1.right = mergeTrees(t1.right, t2.right)<br> <span class="hljs-keyword">return</span> t1<br>}<br></code></pre></td></tr></table></figure><h3 id="判断是不是平衡二叉树"><a href="#判断是不是平衡二叉树" class="headerlink" title="判断是不是平衡二叉树"></a><strong>判断是不是平衡二叉树</strong></h3><p>输入一棵节点数为 n 二叉树,判断该二叉树是否是平衡二叉树。</p><p>在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树</p><p><strong>平衡二叉树</strong>(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">IsBalanced_Solution</span>(<span class="hljs-params">pRoot</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!pRoot){<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> }<br> <span class="hljs-keyword">return</span> (<span class="hljs-built_in">Math</span>.abs(getMaxDepth(pRoot.left)-getMaxDepth(pRoot.right))<=<span class="hljs-number">1</span><br> && IsBalanced_Solution(pRoot.left)<br> && IsBalanced_Solution(pRoot.right))<br>}<br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMaxDepth</span>(<span class="hljs-params">root</span>) </span>{<br> <span class="hljs-keyword">if</span>(!root) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.max(getMaxDepth(root.left)+<span class="hljs-number">1</span>,getMaxDepth(root.right)+<span class="hljs-number">1</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="二叉树中和为某一值的路径-二"><a href="#二叉树中和为某一值的路径-二" class="headerlink" title="二叉树中和为某一值的路径(二)"></a><strong>二叉树中和为某一值的路径(二)</strong></h3><p>输入一颗二叉树的根节点root和一个整数expectNumber,找出二叉树中结点值的和为expectNumber的所有路径。</p><p>1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点</p><p>2.叶子节点是指没有子节点的节点</p><p>3.路径只能从父节点到子节点,不能从子节点到父节点</p><p>4.总节点数目为n</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FindPath</span>(<span class="hljs-params">root, expectNumber</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> []<br> }<br> <span class="hljs-keyword">let</span> res = [], path = []<br> dfs(root, expectNumber, path, res)<br> <span class="hljs-keyword">return</span> res<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dfs</span>(<span class="hljs-params">root, val, path, res</span>) </span>{<br> path.push(root.val)<br> <span class="hljs-keyword">if</span>(val === root.val && !root.left && !root.right) {<br> res.push([].concat(path))<br> } <br> <span class="hljs-keyword">if</span>(root.left) {<br> dfs(root.left, val-root.val, path, res)<br> }<br> <span class="hljs-keyword">if</span>(root.right) {<br> dfs(root.right, val-root.val, path, res)<br> }<br> path.pop()<br>}<br></code></pre></td></tr></table></figure><h3 id="二叉树的前序遍历"><a href="#二叉树的前序遍历" class="headerlink" title="二叉树的前序遍历"></a><strong>二叉树的前序遍历</strong></h3><p>给你二叉树的根节点 root ,返回它节点值的 前序 遍历。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">preorderTraversal</span>(<span class="hljs-params"> root </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> res = []<br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> res<br> }<br> dfs(root, res)<br> <span class="hljs-keyword">return</span> res<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dfs</span>(<span class="hljs-params">root, res</span>) </span>{<br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span><br> }<br> res.push(root.val)<br> dfs(root.left, res)<br> dfs(root.right, res)<br>}<br></code></pre></td></tr></table></figure><h3 id="二叉树的后序遍历"><a href="#二叉树的后序遍历" class="headerlink" title="二叉树的后序遍历"></a><strong>二叉树的后序遍历</strong></h3><p>给定一个二叉树,返回他的后序遍历的序列。</p><p>后序遍历是值按照 左节点->右节点->根节点 的顺序的遍历。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">postorderTraversal</span>(<span class="hljs-params"> root </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> res = []<br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> res<br> }<br> postorder(root, res)<br> <span class="hljs-keyword">return</span> res<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">postorder</span>(<span class="hljs-params">root, res</span>) </span>{<br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span><br> }<br> postorder(root.left, res)<br> postorder(root.right, res)<br> res.push(root.val)<br>}<br></code></pre></td></tr></table></figure><h3 id="二叉树中和为某一值的路径-一"><a href="#二叉树中和为某一值的路径-一" class="headerlink" title="二叉树中和为某一值的路径(一)"></a><strong>二叉树中和为某一值的路径(一)</strong></h3><p>给定一个二叉树root和一个值 sum ,判断是否有从根节点到叶子节点的节点值之和等于 sum 的路径。</p><p>1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点</p><p>2.叶子节点是指没有子节点的节点</p><p>3.路径只能从父节点到子节点,不能从子节点到父节点</p><p>4.总节点数目为n</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hasPathSum</span>(<span class="hljs-params"> root , sum </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!root) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">let</span> res = []<br> dfs(root, sum, res)<br> <span class="hljs-keyword">return</span> res.length !== <span class="hljs-number">0</span><br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dfs</span>(<span class="hljs-params">root, val, res</span>) </span>{<br> <span class="hljs-keyword">if</span>(root.val === val && !root.left && !root.right) {<br> res.push(root)<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">if</span>(root.left) {<br> dfs(root.left, val-root.val, res)<br> }<br> <span class="hljs-keyword">if</span>(root.right) {<br> dfs(root.right, val-root.val, res)<br> }<br>}<br></code></pre></td></tr></table></figure><h2 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h2><h3 id="第一个只出现一次的字符"><a href="#第一个只出现一次的字符" class="headerlink" title="第一个只出现一次的字符"></a><strong>第一个只出现一次的字符</strong></h3><p>在一个长为 字符串中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FirstNotRepeatingChar</span>(<span class="hljs-params">str</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">let</span> temp = <span class="hljs-string">''</span><br> <span class="hljs-keyword">let</span> res = -<span class="hljs-number">1</span>;<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>,n=str.length; i<n;i++) {<br> temp = str.substr(i+<span class="hljs-number">1</span>)<br> <span class="hljs-keyword">if</span>(temp.indexOf(str[i]) === -<span class="hljs-number">1</span> && str.indexOf(str[i]) === i) {<br> res = i<br> <span class="hljs-keyword">break</span><br> }<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="反转字符串"><a href="#反转字符串" class="headerlink" title="反转字符串"></a><strong>反转字符串</strong></h3><p>写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">solve</span>(<span class="hljs-params"> str </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(str == <span class="hljs-string">''</span>) {<br> <span class="hljs-keyword">return</span> str<br> }<br> <span class="hljs-keyword">let</span> newStr = []<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=str.length-<span class="hljs-number">1</span>; i>=<span class="hljs-number">0</span>; i--) {<br> newStr.push(str[i])<br> }<br> <span class="hljs-keyword">return</span> newStr.join(<span class="hljs-string">''</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="表示数值的字符串"><a href="#表示数值的字符串" class="headerlink" title="表示数值的字符串"></a><strong>表示数值的字符串</strong></h3><p>请实现一个函数用来判断字符串str是否表示数值(包括科学计数法的数字,小数和整数)。</p><p><strong>科学计数法的数字</strong>(按顺序)可以分成以下几个部分:</p><p>1.若干空格</p><p>2.一个整数或者小数</p><p>3.(可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个整数(可正可负)</p><p>4.若干空格</p><p><strong>小数</strong>(按顺序)可以分成以下几个部分:</p><ol><li><p>若干空格</p></li><li><p>(可选)一个符号字符(’+’ 或 ‘-‘)</p></li><li><p>可能是以下描述格式之一:</p></li></ol><p> 3.1 至少一位数字,后面跟着一个点 ‘.’</p><p> 3.2 至少一位数字,后面跟着一个点 ‘.’ ,后面再跟着至少一位数字</p><p> 3.3 一个点 ‘.’ ,后面跟着至少一位数字</p><ol start="4"><li>若干空格</li></ol><p><strong>整数</strong>(按顺序)可以分成以下几个部分:</p><ol><li><p>若干空格</p></li><li><p>(可选)一个符号字符(’+’ 或 ‘-‘)</p></li><li><p>至少一位数字</p></li><li><p>若干空格</p></li></ol><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isNumeric</span>(<span class="hljs-params"> str </span>) </span>{<br> <span class="hljs-keyword">if</span>(str === <span class="hljs-string">''</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> <span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">let</span> res = scanInteger(str, index);<br> <span class="hljs-keyword">let</span> numeric = res.isNumber<br> index = res.index;<br> <span class="hljs-keyword">if</span>(str[index] === <span class="hljs-string">'.'</span>) {<br> index++;<br> res = scanUnsignedInteger(str, index)<br> <span class="hljs-keyword">let</span> isNumbers = res.isNumber;<br> index = res.index;<br> numeric = isNumbers || numeric<br> }<br> <span class="hljs-keyword">if</span>(str[index] === <span class="hljs-string">'e'</span> || str[index] === <span class="hljs-string">'E'</span>) {<br> index ++;<br> res = scanInteger(str, index);<br> numeric = numeric && res.isNumber;<br> index = res.index<br> }<br> <span class="hljs-keyword">return</span> numeric && (index === str.length)<br>}<br> <br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scanInteger</span>(<span class="hljs-params">str, index</span>) </span>{<br> <span class="hljs-keyword">if</span>(str[index] === <span class="hljs-string">'+'</span> || str[index] === <span class="hljs-string">'-'</span>) {<br> index ++<br> }<br> <span class="hljs-keyword">return</span> scanUnsignedInteger(str, index);<br>}<br> <br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scanUnsignedInteger</span>(<span class="hljs-params">str, index</span>) </span>{<br> <span class="hljs-keyword">let</span> begin = index;<br> <span class="hljs-keyword">while</span>(index !== str.length && str[index] >= <span class="hljs-string">'0'</span> && str[index] <= <span class="hljs-string">'9'</span>){<br> index ++<br> }<br> <span class="hljs-keyword">return</span> {<br> <span class="hljs-attr">isNumber</span>: index>begin,<br> index<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="字符串的排列"><a href="#字符串的排列" class="headerlink" title="字符串的排列"></a><strong>字符串的排列</strong></h3><p>输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。</p><p>例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Permutation</span>(<span class="hljs-params">str</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!str) {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">''</span><br> }<br> <span class="hljs-keyword">let</span> res = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Set</span>()<br> perm(<span class="hljs-number">0</span>, str, res)<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">Array</span>.from(res)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">perm</span>(<span class="hljs-params">pos, str, res</span>) </span>{<br> <span class="hljs-keyword">if</span>(pos === str.length) {<br> res.add(str)<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=pos; i<str.length; i++) {<br> str = swapStr(str, pos, i)<br> perm(pos+<span class="hljs-number">1</span>, str, res)<br> str = swapStr(str, pos, i)<br> }<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">swapStr</span>(<span class="hljs-params">str, i, j</span>) </span>{<br> <span class="hljs-keyword">let</span> arr = str.split(<span class="hljs-string">''</span>)<br> <span class="hljs-keyword">let</span> tmp = arr[i]<br> arr[i] = arr[j]<br> arr[j] = tmp<br> <span class="hljs-keyword">return</span> arr.join(<span class="hljs-string">''</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="判断是否为回文字符串"><a href="#判断是否为回文字符串" class="headerlink" title="判断是否为回文字符串"></a><strong>判断是否为回文字符串</strong></h3><p>给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文。如果是回文请返回true,否则返回false。</p><p>字符串回文指该字符串正序与其逆序逐字符一致。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">judge</span>(<span class="hljs-params"> str </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!str) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">if</span>(str.length == <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> }<br> <span class="hljs-comment">// 判断奇数偶数</span><br> <span class="hljs-keyword">let</span> flag = (str.length % <span class="hljs-number">2</span>) == <span class="hljs-number">0</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span><br> <br> <span class="hljs-keyword">let</span> left = flag ? str.length/<span class="hljs-number">2</span> - <span class="hljs-number">1</span>: <span class="hljs-built_in">Math</span>.floor(str.length/<span class="hljs-number">2</span>) - <span class="hljs-number">1</span><br> <span class="hljs-keyword">let</span> right = flag ? str.length/<span class="hljs-number">2</span> : <span class="hljs-built_in">Math</span>.floor(str.length/<span class="hljs-number">2</span>) + <span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(left >= <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">if</span>(str[left] !== str[right]) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> left--<br> right++<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br>}<br></code></pre></td></tr></table></figure><h3 id="字符串出现次数的TopK问题"><a href="#字符串出现次数的TopK问题" class="headerlink" title="字符串出现次数的TopK问题"></a><strong>字符串出现次数的TopK问题</strong></h3><p>给定一个字符串数组,再给定整数 k ,请返回出现次数前k名的字符串和对应的次数。</p><p>返回的答案应该按字符串出现频率由高到低排序。如果不同的字符串有相同出现频率,按字典序排序。</p><p>对于两个字符串,大小关系取决于两个字符串从左到右第一个不同字符的 ASCII 值的大小关系。</p><p>比如”ah1x”小于”ahb”,”231”<”32“</p><p>字符仅包含数字和字母</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">topKstrings</span>(<span class="hljs-params"> strings , k </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(strings.length == <span class="hljs-number">0</span> || k == <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> []<br> }<br> <span class="hljs-keyword">let</span> map = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<strings.length; i++) {<br> map.set(strings[i], map.has(strings[i]) ? map.get(strings[i]) + <span class="hljs-number">1</span> : <span class="hljs-number">1</span>)<br> }<br> <span class="hljs-keyword">let</span> res = <span class="hljs-built_in">Array</span>.from(map.entries())<br> res.sort(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">a,b</span>)</span>{<br> <span class="hljs-keyword">if</span>(a[<span class="hljs-number">1</span>]==b[<span class="hljs-number">1</span>]){<br> <span class="hljs-keyword">if</span>(a[<span class="hljs-number">0</span>]<b[<span class="hljs-number">0</span>]) <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span><br> <span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">return</span> b[<span class="hljs-number">1</span>]-a[<span class="hljs-number">1</span>]<br> })<br> <span class="hljs-keyword">return</span> res.slice(<span class="hljs-number">0</span>, k)<br>}<br></code></pre></td></tr></table></figure><h3 id="最长公共前缀"><a href="#最长公共前缀" class="headerlink" title="最长公共前缀"></a><strong>最长公共前缀</strong></h3><p>给你一个大小为 n 的字符串数组 strs ,其中包含n个字符串 , 编写一个函数来查找字符串数组中的最长公共前缀,返回这个公共前缀。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">longestCommonPrefix</span>(<span class="hljs-params"> strs </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!strs || strs.length == <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">''</span><br> }<br> <span class="hljs-keyword">let</span> row = strs.length, col = strs[<span class="hljs-number">0</span>].length, res = []<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<col; i++) {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=<span class="hljs-number">0</span>; j<row-<span class="hljs-number">1</span>; j++) {<br> <span class="hljs-keyword">if</span>(strs[j][i] !== strs[j+<span class="hljs-number">1</span>][i]) {<br> <span class="hljs-keyword">return</span> res.join(<span class="hljs-string">''</span>)<br> }<br> }<br> res.push(strs[<span class="hljs-number">0</span>][i])<br> }<br> <span class="hljs-keyword">return</span> res.join(<span class="hljs-string">''</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="字符串变形"><a href="#字符串变形" class="headerlink" title="字符串变形"></a><strong>字符串变形</strong></h3><p>对于一个长度为 n 字符串,我们需要对它做一些变形。</p><p>首先这个字符串中包含着一些空格,就像”Hello World”一样,然后我们要做的是把这个字符串中由空格隔开的单词反序,同时反转每个字符的大小写。</p><p>比如”Hello World”变形后就变成了”wORLD hELLO”。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">trans</span>(<span class="hljs-params">s, n</span>)</span>{<br> <span class="hljs-comment">//write code here</span><br> <span class="hljs-keyword">if</span>(n <= <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> s<br> }<br> <span class="hljs-keyword">let</span> sArr = s.split(<span class="hljs-string">' '</span>)<br> <span class="hljs-keyword">let</span> res = []<br> sArr.reverse()<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<sArr.length; i++) {<br> <span class="hljs-keyword">let</span> tmp = <span class="hljs-string">''</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=<span class="hljs-number">0</span>; j<sArr[i].length; j++) {<br> <span class="hljs-keyword">if</span>(<span class="hljs-regexp">/[A-Z]/</span>.test(sArr[i][j])) {<br> tmp += sArr[i][j].toLowerCase()<br> }<span class="hljs-keyword">else</span> {<br> tmp += sArr[i][j].toUpperCase()<br> }<br> }<br> res.push(tmp)<br> }<br> <span class="hljs-keyword">return</span> res.join(<span class="hljs-string">' '</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="把数字翻译成字符串"><a href="#把数字翻译成字符串" class="headerlink" title="把数字翻译成字符串"></a><strong>把数字翻译成字符串</strong></h3><p>有一种将字母编码成数字的方式:’a’->1, ‘b->2’, … , ‘z->26’。</p><p>现在给一串数字,返回有多少种可能的译码结果</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">solve</span>(<span class="hljs-params"> nums </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> len = nums.length<br> <span class="hljs-keyword">if</span>(len ===<span class="hljs-number">0</span> || nums[<span class="hljs-number">0</span>] === <span class="hljs-string">'0'</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">let</span> dp = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(len).fill(<span class="hljs-number">0</span>)<br> dp[<span class="hljs-number">0</span>] = <span class="hljs-number">1</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">1</span>; i<len; i++) {<br> <span class="hljs-keyword">if</span>(nums[i] !== <span class="hljs-string">'0'</span>) {<br> dp[i] = dp[i-<span class="hljs-number">1</span>]<br> }<br> <span class="hljs-keyword">let</span> num = <span class="hljs-built_in">parseInt</span>(nums[i-<span class="hljs-number">1</span>] + nums[i])<br> <span class="hljs-keyword">if</span>(num >= <span class="hljs-number">10</span> && num <=<span class="hljs-number">26</span>) {<br> <span class="hljs-keyword">if</span>(i==<span class="hljs-number">1</span>) {<br> dp[i] += <span class="hljs-number">1</span><br> }<span class="hljs-keyword">else</span> {<br> dp[i] += dp[i-<span class="hljs-number">2</span>]<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> dp[len-<span class="hljs-number">1</span>]<br>}<br></code></pre></td></tr></table></figure><h3 id="判断字符是否唯一"><a href="#判断字符是否唯一" class="headerlink" title="判断字符是否唯一"></a><strong>判断字符是否唯一</strong></h3><p>给定一个字符串,请你判断其中每个字符是否全都不同。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isUnique</span>(<span class="hljs-params"> str </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!str) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">let</span> map = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<str.length; i++) {<br> <span class="hljs-keyword">if</span>(map.has(str[i])) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> } <br> map.set(str[i], i)<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br>}<br></code></pre></td></tr></table></figure><h3 id="最大值"><a href="#最大值" class="headerlink" title="最大值"></a><strong>最大值</strong></h3><p>有一个只由字符’1’到’9’组成的长度为 n<em>n</em> 的字符串 s<em>s</em> ,现在可以截取其中一段长度为 k<em>k</em> 的子串并且将该子串当作十进制的正整数,如对于子串”123”,其对应的十进制数字就是123123 。</p><p>如果想让这个正整数尽可能的大的话,问该正整数最大能是多少。</p><p>函数传入一个长度为 n<em>n</em> 的字符串 s<em>s</em> 和一个正整数 k<em>k</em> ,请你返回答案。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxValue</span>(<span class="hljs-params"> s , k </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(s.length === <span class="hljs-number">0</span> || k === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">let</span> n = s.length<br> <span class="hljs-keyword">let</span> max = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<n; i++) {<br> <span class="hljs-keyword">let</span> res = <span class="hljs-built_in">parseInt</span>(s.slice(i, i+k))<br> max = <span class="hljs-built_in">Math</span>.max(res, max)<br> }<br> <span class="hljs-keyword">return</span> max<br>}<br></code></pre></td></tr></table></figure><h3 id="括号生成"><a href="#括号生成" class="headerlink" title="括号生成"></a><strong>括号生成</strong></h3><p>给出n对括号,请编写一个函数来生成所有的由n对括号组成的合法组合。</p><p>例如,给出n=3,解集为:</p><p>“((()))”, “(()())”, “(())()”, “()()()”, “()(())”</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateParenthesis</span>(<span class="hljs-params"> n </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> res = []<br> <span class="hljs-keyword">let</span> curStr = <span class="hljs-string">''</span><br> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dfs</span>(<span class="hljs-params">str, left, right</span>) </span>{<br> <span class="hljs-keyword">if</span>(left ===<span class="hljs-number">0</span> && right ===<span class="hljs-number">0</span> ) {<br> res.push(str)<br> <span class="hljs-keyword">return</span> <br> }<br> <span class="hljs-keyword">if</span>(right < left) {<br> dfs(str+<span class="hljs-string">')'</span>, left-<span class="hljs-number">1</span>, right)<br> }<br> <span class="hljs-keyword">if</span>(right > <span class="hljs-number">0</span>) {<br> dfs(str+<span class="hljs-string">'('</span>, left, right - <span class="hljs-number">1</span>)<br> }<br> }<br> dfs(curStr, n, n)<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="回文数字"><a href="#回文数字" class="headerlink" title="回文数字"></a><strong>回文数字</strong></h3><p>在不使用额外的内存空间的条件下判断一个整数是否是回文。</p><p>回文指逆序和正序完全相同。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isPalindrome</span>(<span class="hljs-params"> x </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(x < <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> x = x.toString()<br> <span class="hljs-keyword">let</span> left = <span class="hljs-number">0</span>, right = x.length-<span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(left < right) {<br> <span class="hljs-keyword">if</span>(x[left] !== x[right]) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> left ++<br> right --<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br>}<br></code></pre></td></tr></table></figure><h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><h3 id="连续子数组的最大和"><a href="#连续子数组的最大和" class="headerlink" title="连续子数组的最大和"></a>连续子数组的最大和</h3><p>输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,子数组最小长度为1。求所有子数组的和的最大值。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FindGreatestSumOfSubArray</span>(<span class="hljs-params">array</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span>(array.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">let</span> max = array[<span class="hljs-number">0</span>]<br> <span class="hljs-keyword">let</span> dp = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(array.length).fill(<span class="hljs-number">0</span>)<br> dp[<span class="hljs-number">0</span>] = max<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">1</span>; i<array.length; i++) {<br> dp[i] = <span class="hljs-built_in">Math</span>.max(dp[i-<span class="hljs-number">1</span>]+array[i], array[i])<br> max = <span class="hljs-built_in">Math</span>.max(dp[i], max)<br> }<br> <span class="hljs-keyword">return</span> max<br>}<br></code></pre></td></tr></table></figure><h3 id="合并两个有序的数组"><a href="#合并两个有序的数组" class="headerlink" title="合并两个有序的数组"></a>合并两个有序的数组</h3><p>给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">merge</span>(<span class="hljs-params"> A, m, B, n </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> p = m+n-<span class="hljs-number">1</span>, p1 = m-<span class="hljs-number">1</span>, p2 = n-<span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(p1 >= <span class="hljs-number">0</span> || p2 >= <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">if</span>(p1 == -<span class="hljs-number">1</span>) {<br> A[p--] = B[p2--]<br> }<br> <span class="hljs-keyword">if</span>(p2 == -<span class="hljs-number">1</span>) <span class="hljs-keyword">break</span><br> <span class="hljs-keyword">if</span>(A[p1] > B[p2]) {<br> A[p--] = A[p1--]<br> }<span class="hljs-keyword">else</span> {<br> A[p--] = B[p2--]<br> }<br> }<br> <span class="hljs-keyword">return</span> A<br>}<br></code></pre></td></tr></table></figure><h3 id="旋转数组的最小数字"><a href="#旋转数组的最小数字" class="headerlink" title="旋转数组的最小数字"></a><strong>旋转数组的最小数字</strong></h3><p>有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minNumberInRotateArray</span>(<span class="hljs-params">rorateArray</span>) </span>{<br> <span class="hljs-keyword">const</span> len = rorateArray.length<br> <span class="hljs-keyword">if</span> (len === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">let</span> low = <span class="hljs-number">0</span>,<br> high = len - <span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span> (low < high) {<br> <span class="hljs-keyword">let</span> mid = low + <span class="hljs-built_in">Math</span>.floor((high - low) / <span class="hljs-number">2</span>)<br> <span class="hljs-keyword">if</span> (rorateArray[mid] > rorateArray[high]) {<br> low = mid + <span class="hljs-number">1</span><br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (rorateArray[mid] < rorateArray[high]) {<br> high = mid<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (rorateArray[mid] === rorateArray[high]) {<br> high = high - <span class="hljs-number">1</span><br> }<br> }<br><br> <span class="hljs-keyword">return</span> rorateArray[low]<br><br>}<br></code></pre></td></tr></table></figure><h3 id="数组中出现次数超过一半的数字"><a href="#数组中出现次数超过一半的数字" class="headerlink" title="数组中出现次数超过一半的数字"></a><strong>数组中出现次数超过一半的数字</strong></h3><p>给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。</p><p>例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MoreThanHalfNum_Solution</span>(<span class="hljs-params">numbers</span>) </span>{<br> <span class="hljs-keyword">const</span> halfNum = numbers.length / <span class="hljs-number">2</span>;<br> <span class="hljs-keyword">if</span> (!halfNum) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br> }<br><br> numbers.sort();<br> <span class="hljs-keyword">const</span> num = numbers[<span class="hljs-built_in">Math</span>.floor(halfNum)];<br> <span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<numbers.length; i++) {<br> <span class="hljs-keyword">if</span>(num === numbers[i]) {<br> count ++;<br> }<br> }<br> <span class="hljs-keyword">return</span> count > halfNum ? num : <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="数字在升序数组中出现的次数"><a href="#数字在升序数组中出现的次数" class="headerlink" title="数字在升序数组中出现的次数"></a><strong>数字在升序数组中出现的次数</strong></h3><p>给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetNumberOfK</span>(<span class="hljs-params">data, k</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> sum = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>,n=data.length; i<n; i++) {<br> <span class="hljs-keyword">if</span>(sum!==<span class="hljs-number">0</span> && data[i] !== k) {<br> <span class="hljs-keyword">break</span>;<br> }<br> <span class="hljs-keyword">if</span>(data[i] === k) {<br> sum++;<br> }<br> }<br> <span class="hljs-keyword">return</span> sum;<br>}<br></code></pre></td></tr></table></figure><h3 id="数组中只出现一次的两个数字"><a href="#数组中只出现一次的两个数字" class="headerlink" title="数组中只出现一次的两个数字"></a><strong>数组中只出现一次的两个数字</strong></h3><p>一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>array int整型一维数组 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>int整型一维数组</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FindNumsAppearOnce</span>(<span class="hljs-params"> array </span>) </span>{<br> <span class="hljs-keyword">let</span> arrMap = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();<br> <span class="hljs-keyword">let</span> result = [];<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>, n = array.length; i < n; i++) {<br> <span class="hljs-keyword">let</span> item = arrMap.get(array[i]);<br> <span class="hljs-keyword">if</span>(item) {<br> arrMap.set(array[i], item+<span class="hljs-number">1</span>)<br> <span class="hljs-keyword">continue</span>;<br> }<span class="hljs-keyword">else</span> {<br> arrMap.set(array[i], <span class="hljs-number">1</span>)<br> }<br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> [key, value] <span class="hljs-keyword">of</span> arrMap) {<br> <span class="hljs-keyword">if</span>(value === <span class="hljs-number">1</span>) {<br> result.push(key);<br> }<br> }<br> <span class="hljs-keyword">return</span> result.sort();<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">FindNumsAppearOnce</span> : FindNumsAppearOnce<br>};<br></code></pre></td></tr></table></figure><h3 id="用两个栈实现队列"><a href="#用两个栈实现队列" class="headerlink" title="用两个栈实现队列"></a><strong>用两个栈实现队列</strong></h3><p>用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> stack1 = []<br><span class="hljs-keyword">const</span> stack2 = []<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">push</span>(<span class="hljs-params">node</span>)</span><br><span class="hljs-function"></span>{<br> stack1.push(node)<br>}<br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pop</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span>(stack2.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">while</span>(stack1.length !== <span class="hljs-number">0</span>) {<br> stack2.push(stack1.pop())<br> }<br> }<br> <span class="hljs-keyword">return</span> stack2.pop()<br>}<br></code></pre></td></tr></table></figure><h3 id="寻找第K大"><a href="#寻找第K大" class="headerlink" title="寻找第K大"></a><strong>寻找第K大</strong></h3><p>有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。</p><p>给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">quickSort</span> (<span class="hljs-params">arr, s, t</span>) </span>{<br> <span class="hljs-keyword">let</span> i = s, j = t<br> <span class="hljs-keyword">if</span> (s < t) {<br> <span class="hljs-keyword">let</span> tmp = arr[s]<br> <span class="hljs-keyword">while</span> (i != j) {<br> <span class="hljs-keyword">while</span> (j > i && arr[j] <= tmp)<br> j--<br> arr[i] = arr[j]<br> <span class="hljs-keyword">while</span> (i < j && arr[i] >= tmp)<br> i++<br> arr[j] = arr[i]<br> }<br> arr[i] = tmp<br> quickSort(arr, s, i-<span class="hljs-number">1</span>)<br> quickSort(arr, i+<span class="hljs-number">1</span>, t)<br> }<br> <span class="hljs-keyword">return</span> arr<br>}<br> <br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>a int整型一维数组</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>n int整型</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>K int整型</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>int整型</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findKth</span>(<span class="hljs-params"> a , n , K </span>) </span>{<br> <span class="hljs-keyword">if</span> (a.length === <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> <br> <span class="hljs-keyword">let</span> sortDesc = quickSort(a, <span class="hljs-number">0</span>, a.length - <span class="hljs-number">1</span>)<br> <span class="hljs-keyword">return</span> sortDesc[K - <span class="hljs-number">1</span>]<br>}<br></code></pre></td></tr></table></figure><h3 id="最小的K个数"><a href="#最小的K个数" class="headerlink" title="最小的K个数"></a><strong>最小的K个数</strong></h3><p>给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetLeastNumbers_Solution</span>(<span class="hljs-params">input, k</span>) </span>{<br> <span class="hljs-keyword">if</span> (k > input.length) {<br> <span class="hljs-keyword">return</span> []<br> }<br> <span class="hljs-keyword">let</span> result = quickSort(input);<br><br> <span class="hljs-keyword">return</span> result.splice(<span class="hljs-number">0</span>, k);<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">quickSort</span>(<span class="hljs-params">arr, l, r</span>) </span>{<br> <span class="hljs-keyword">const</span> len = arr.length;<br> <span class="hljs-keyword">let</span> left = <span class="hljs-keyword">typeof</span> l !== <span class="hljs-string">'number'</span> ? <span class="hljs-number">0</span> : l;<br> <span class="hljs-keyword">let</span> right = <span class="hljs-keyword">typeof</span> r !== <span class="hljs-string">'number'</span> ? len - <span class="hljs-number">1</span> : r;<br> <span class="hljs-keyword">if</span> (left < right) {<br> <span class="hljs-keyword">let</span> partitionIndex = partition(arr, left, right);<br> quickSort(arr, left, partitionIndex - <span class="hljs-number">1</span>);<br> quickSort(arr, partitionIndex + <span class="hljs-number">1</span>, right);<br> }<br> <span class="hljs-keyword">return</span> arr;<br>}<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param <span class="hljs-type">{数组}</span> </span>arr </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param <span class="hljs-type">{下标}</span> </span>p </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param <span class="hljs-type">{下标}</span> </span>r </span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">partition</span>(<span class="hljs-params">arr, left, right</span>) </span>{<br> <span class="hljs-keyword">let</span> pivot = right;<br> <span class="hljs-keyword">let</span> i = left;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = i; j <= right; j++) {<br> <span class="hljs-keyword">if</span> (arr[j] < arr[pivot]) {<br> swap(arr, j, i);<br> i++;<br> }<br> }<br> swap(arr, i, right);<br> <span class="hljs-keyword">return</span> i;<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">swap</span>(<span class="hljs-params">arr, i, j</span>) </span>{<br> <span class="hljs-keyword">let</span> temp = arr[i];<br> arr[i] = arr[j];<br> arr[j] = temp;<br>}<br></code></pre></td></tr></table></figure><h3 id="排序"><a href="#排序" class="headerlink" title="排序"></a><strong>排序</strong></h3><p>给定一个长度为 n 的数组,请你编写一个函数,返回该数组按升序排序后的结果。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MySort</span>(<span class="hljs-params"> arr </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(arr.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<arr.length; i++) {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=i+<span class="hljs-number">1</span>; j<arr.length; j++) {<br> <span class="hljs-keyword">if</span>(arr[i] > arr[j]) {<br> <span class="hljs-keyword">const</span> temp = arr[i]<br> arr[i] = arr[j]<br> arr[j] = temp<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> arr<br>}<br></code></pre></td></tr></table></figure><h3 id="栈的压入、弹出序列"><a href="#栈的压入、弹出序列" class="headerlink" title="栈的压入、弹出序列"></a><strong>栈的压入、弹出序列</strong></h3><p>输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。</p><ol><li><p>0<=pushV.length == popV.length <=1000</p></li><li><p>-1000<=pushV[i]<=1000</p></li><li><p>pushV 的所有数字均不相同</p></li></ol><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">IsPopOrder</span>(<span class="hljs-params">pushV, popV</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">let</span> stack = []<br> <span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span><br> <span class="hljs-keyword">let</span> temp = []<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>, n = pushV.length; i < n; i++) {<br> stack.push(pushV[i])<br> <span class="hljs-keyword">if</span> (pushV[i] === popV[count]) {<br> stack.pop()<br> temp.push(pushV[i])<br> count++<br> <span class="hljs-keyword">while</span> (stack.indexOf(popV[count]) > -<span class="hljs-number">1</span> && stack[stack.length - <span class="hljs-number">1</span>] === popV[count]) {<br> stack.pop()<br> temp.push(popV[count])<br> count++<br> }<br> }<br> }<br> <span class="hljs-keyword">while</span> (stack.length) {<br> <span class="hljs-keyword">if</span> (stack[stack.length - <span class="hljs-number">1</span>] === popV[count]) {<br> temp.push(popV[count])<br> count++<br> }<br> stack.pop()<br> }<br> <span class="hljs-keyword">return</span> temp.length === popV.length ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span><br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">IsPopOrder</span> : IsPopOrder<br>};<br></code></pre></td></tr></table></figure><h3 id="构建乘积数组"><a href="#构建乘积数组" class="headerlink" title="构建乘积数组"></a><strong>构建乘积数组</strong></h3><p>给定一个数组 A[0,1,…,n-1] ,请构建一个数组 B[0,1,…,n-1] ,其中 B 的元素 B[i]=A[0]<em>A[1]</em>…*A[i-1]<em>A[i+1]</em>…*A[n-1](除 A[i] 以外的全部元素的的乘积)。程序中不能使用除法。(注意:规定 B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2])</p><p>对于 A 长度为 1 的情况,B 无意义,故而无法构建,用例中不包括这种情况。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">multiply</span>(<span class="hljs-params">array</span>) </span>{<br> <span class="hljs-keyword">if</span> (array.length <= <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">const</span> b = []<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < array.length; i++) {<br> <span class="hljs-keyword">let</span> curB = array.reduce(<span class="hljs-function">(<span class="hljs-params">pre, curVal, curIndex</span>) =></span> {<br> <span class="hljs-keyword">if</span> (curIndex === i) {<br> <span class="hljs-keyword">return</span> pre<br> }<br> <span class="hljs-keyword">return</span> pre * curVal<br> })<br> b.push(curB)<br> }<br> <span class="hljs-keyword">return</span> b;<br>}<br></code></pre></td></tr></table></figure><h3 id="数组中重复的数字"><a href="#数组中重复的数字" class="headerlink" title="数组中重复的数字"></a><strong>数组中重复的数字</strong></h3><p>在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">duplicate</span>(<span class="hljs-params"> numbers </span>) </span>{<br> <span class="hljs-keyword">let</span> set = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Set</span>()<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<numbers.length; i++) {<br> <span class="hljs-keyword">if</span>(set.has(numbers[i])) {<br> <span class="hljs-keyword">return</span> numbers[i]<br> }<span class="hljs-keyword">else</span> {<br> set.add(numbers[i])<br> }<br> }<br> <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span><br>}<br></code></pre></td></tr></table></figure><h3 id="三树之和"><a href="#三树之和" class="headerlink" title="三树之和"></a>三树之和</h3><p>给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">threeSum</span>(<span class="hljs-params"> num </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> res = []<br> <span class="hljs-keyword">if</span>(num.length < <span class="hljs-number">3</span>) {<br> <span class="hljs-keyword">return</span> res<br> }<br> num.sort(<span class="hljs-function">(<span class="hljs-params">a,b</span>) =></span> a-b)<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<num.length-<span class="hljs-number">2</span>; i++) {<br> <span class="hljs-keyword">if</span>(num[i] == num[i-<span class="hljs-number">1</span>]) <span class="hljs-keyword">continue</span><br> <span class="hljs-keyword">let</span> l = i+<span class="hljs-number">1</span>,r = num.length-<span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(l < r) {<br> <span class="hljs-keyword">if</span>(num[l] + num[r] === -num[i]) {<br> res.push([num[i], num[l], num[r]])<br> <span class="hljs-keyword">while</span>(num[l] === num[l+<span class="hljs-number">1</span>] && l+<span class="hljs-number">1</span><r) l++<br> <span class="hljs-keyword">while</span>(num[r] === num[r-<span class="hljs-number">1</span>] && r-<span class="hljs-number">1</span>>l) r--<br> l++<br> r--<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(num[l] + num[r] > -num[i]){<br> r--<br> }<span class="hljs-keyword">else</span> {<br> l++<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="最长回文子串"><a href="#最长回文子串" class="headerlink" title="最长回文子串"></a><strong>最长回文子串</strong></h3><p>对于长度为n的一个字符串A(仅包含数字,大小写英文字母),请设计一个高效算法,计算其中最长回文子串的长度。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getLongestPalindrome</span>(<span class="hljs-params"> A </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(A.length <= <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> A.length<br> }<br> <span class="hljs-keyword">let</span> maxLen = <span class="hljs-number">1</span><br> <span class="hljs-keyword">let</span> dp = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(A.length).fill(<span class="hljs-literal">false</span>)<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<A.length; i++) {<br> dp[i] = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(A.length).fill(<span class="hljs-literal">false</span>)<br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> r=<span class="hljs-number">1</span>; r<A.length; r++) {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> l=<span class="hljs-number">0</span>; l<=r; l++) {<br> <span class="hljs-keyword">if</span>(A[l] !== A[r]) <span class="hljs-keyword">continue</span><br> <span class="hljs-keyword">if</span>(l === r) {<br> dp[l][r] = <span class="hljs-literal">true</span><br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(r-l <= <span class="hljs-number">2</span>) {<br> dp[l][r] = <span class="hljs-literal">true</span><br> }<span class="hljs-keyword">else</span> {<br> dp[l][r] = dp[l+<span class="hljs-number">1</span>][r-<span class="hljs-number">1</span>]<br> }<br> <span class="hljs-keyword">if</span>(dp[l][r] && r-l + <span class="hljs-number">1</span> > maxLen) {<br> maxLen = r-l + <span class="hljs-number">1</span><br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> maxLen<br>}<br></code></pre></td></tr></table></figure><h3 id="最长上升子序列"><a href="#最长上升子序列" class="headerlink" title="最长上升子序列"></a>最长上升子序列</h3><p>给定数组 arr ,设长度为 n ,输出 arr 的最长上升子序列。(如果有多个答案,请输出其中 按数值(注:区别于按单个字符的ASCII码值)进行比较的 字典序最小的那个)</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LIS</span>(<span class="hljs-params"> arr </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> n = arr.length<br> <span class="hljs-keyword">let</span> d = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(n+<span class="hljs-number">1</span>).fill(-<span class="hljs-number">1</span>), p = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(n).fill(<span class="hljs-number">0</span>)<br> <span class="hljs-keyword">let</span> len = <span class="hljs-number">1</span><br> d[len] = arr[<span class="hljs-number">0</span>]<br> p[<span class="hljs-number">0</span>] = <span class="hljs-number">1</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">1</span>; i<n; i++) {<br> <span class="hljs-keyword">if</span>(arr[i] > d[len]) {<br> d[++len] = arr[i]<br> p[i] = len<br> }<span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">let</span> left = <span class="hljs-number">1</span>, right = len, pos = <span class="hljs-number">0</span><br> <span class="hljs-keyword">while</span>(left <= right) {<br> <span class="hljs-keyword">let</span> mid = <span class="hljs-built_in">Math</span>.floor((left + right)/<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">if</span>(d[mid] < arr[i]) {<br> pos = mid<br> left = mid + <span class="hljs-number">1</span><br> } <span class="hljs-keyword">else</span> {<br> right = mid - <span class="hljs-number">1</span><br> }<br> }<br> d[pos + <span class="hljs-number">1</span>] = arr[i]<br> p[i] = pos + <span class="hljs-number">1</span><br> }<br> }<br> <br> <span class="hljs-keyword">let</span> ans = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(len)<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=n-<span class="hljs-number">1</span>; i>=<span class="hljs-number">0</span>; i--) {<br> <span class="hljs-keyword">if</span>(p[i] == len) {<br> ans[--len] = arr[i]<br> }<br> }<br> <span class="hljs-keyword">return</span> ans<br>}<br></code></pre></td></tr></table></figure><h3 id="在旋转过的有序数组中寻找目标值"><a href="#在旋转过的有序数组中寻找目标值" class="headerlink" title="在旋转过的有序数组中寻找目标值"></a><strong>在旋转过的有序数组中寻找目标值</strong></h3><p>有一个长度为 n 的按严格升序排列的整数数组 nums ,在实行 search 函数之前,在某个下标 k 上进行旋转,使数组变为[nums[k],nums[k+1],…..,nums[nums.length-1],nums[0],nums[1],…….,nums[k-1]]。</p><p>给定旋转后的数组 nums 和一个整型 target ,请你查找 target 是否存在于 nums 数组中并返回其下标(从0开始计数),如果不存在请返回-1。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params"> nums , target </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> left = <span class="hljs-number">0</span>, right = nums.length-<span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(left <= right) {<br> <span class="hljs-keyword">let</span> mid = <span class="hljs-built_in">Math</span>.floor((left+right)/<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">if</span>(nums[mid] == target) {<br> <span class="hljs-keyword">return</span> mid<br> }<br> <br> <span class="hljs-keyword">if</span>(nums[mid] >= nums[left]) {<br> <span class="hljs-comment">// left 到 mid 有序</span><br> <span class="hljs-keyword">if</span>(target > nums[mid] || (target<nums[mid] && target < nums[left])) {<br> <span class="hljs-comment">// 右</span><br> left = mid + <span class="hljs-number">1</span><br> }<span class="hljs-keyword">else</span> {<br> right = mid<br> }<br> <br> }<br> <br> <span class="hljs-keyword">if</span>(nums[mid] < nums[right]) {<br> <span class="hljs-comment">// mid 到 right 有序</span><br> <span class="hljs-keyword">if</span>(target < nums[mid] || (target>nums[mid] && target > nums[right])) {<br> right = mid<br> }<span class="hljs-keyword">else</span> {<br> left = mid + <span class="hljs-number">1</span><br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span><br>}<br></code></pre></td></tr></table></figure><h3 id="矩阵的最小路径和"><a href="#矩阵的最小路径和" class="headerlink" title="矩阵的最小路径和"></a><strong>矩阵的最小路径和</strong></h3><p>给定一个 n * m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。</p><p>数据范围: 1 \le n,m\le 5001≤<em>n</em>,<em>m</em>≤500,矩阵中任意值都满足 0 \le a_{i,j} \le 1000≤<em>a**i</em>,<em>j</em>≤100</p><p>要求:时间复杂度 O(nm)<em>O</em>(<em>n**m</em>)</p><p>例如:当输入[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]时,对应的返回值为12,</p><p>所选择的最小累加和路径如下图所示:</p><p><img src="https://uploadfiles.nowcoder.com/images/20220122/423483716_1642823916509/06EB123C153852AF55ED51448BEAD1BA" alt="img"></p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minPathSum</span>(<span class="hljs-params"> matrix </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> m = matrix.length, n = matrix[<span class="hljs-number">0</span>].length<br> <span class="hljs-keyword">let</span> dp = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(m).fill(<span class="hljs-number">0</span>)<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<m; i++) {<br> dp[i] = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(n).fill(<span class="hljs-number">0</span>)<br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<m; i++) {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=<span class="hljs-number">0</span>; j<n; j++) {<br> <span class="hljs-keyword">if</span>(i==<span class="hljs-number">0</span> && j==<span class="hljs-number">0</span>) {<br> dp[i][j] = matrix[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(i==<span class="hljs-number">0</span> && j!=<span class="hljs-number">0</span>) {<br> dp[i][j] = dp[i][j-<span class="hljs-number">1</span>] + matrix[i][j]<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(i!=<span class="hljs-number">0</span> && j==<span class="hljs-number">0</span>) {<br> dp[i][j] = dp[i-<span class="hljs-number">1</span>][j] + matrix[i][j]<br> }<span class="hljs-keyword">else</span> {<br> dp[i][j] = <span class="hljs-built_in">Math</span>.min(dp[i-<span class="hljs-number">1</span>][j], dp[i][j-<span class="hljs-number">1</span>]) + matrix[i][j]<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> dp[m-<span class="hljs-number">1</span>][n-<span class="hljs-number">1</span>]<br>}<br></code></pre></td></tr></table></figure><h3 id="求路径"><a href="#求路径" class="headerlink" title="求路径"></a><strong>求路径</strong></h3><p>一个机器人在m×n大小的地图的左上角(起点)。</p><p>机器人每次可以向下或向右移动。机器人要到达地图的右下角(终点)。</p><p>可以有多少种不同的路径从起点走到终点?</p><p><img src="https://uploadfiles.nowcoder.com/images/20201210/999991351_1607596327517/873CB1F2327F70DA0CA0FDC797F894A7" alt="img"></p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">uniquePaths</span>(<span class="hljs-params"> m , n </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> dp = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(m).fill(<span class="hljs-number">1</span>)<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<m; i++) {<br> dp[i] = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(n).fill(<span class="hljs-number">1</span>)<br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<m; i++) {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=<span class="hljs-number">0</span>; j<n; j++) {<br> <span class="hljs-keyword">if</span>(i==<span class="hljs-number">0</span> || j==<span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">continue</span><br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(i !==<span class="hljs-number">0</span> && j!==<span class="hljs-number">0</span>){<br> dp[i][j] = dp[i-<span class="hljs-number">1</span>][j] + dp[i][j-<span class="hljs-number">1</span>]<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> dp[m-<span class="hljs-number">1</span>][n-<span class="hljs-number">1</span>]<br>}<br></code></pre></td></tr></table></figure><h3 id="合并区间"><a href="#合并区间" class="headerlink" title="合并区间"></a><strong>合并区间</strong></h3><p>给出一组区间,请合并所有重叠的区间。</p><p>请保证合并后的区间按区间起点升序排列。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">merge</span>(<span class="hljs-params"> intervals </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(intervals.length <=<span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> intervals<br> }<br> <span class="hljs-comment">// 按区间的第一个值排序</span><br> intervals.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =></span> {<br> <span class="hljs-keyword">return</span> a.start - b.start<br> })<br> <span class="hljs-keyword">let</span> res = [], i=<span class="hljs-number">0</span>, len = intervals.length<br> <span class="hljs-keyword">while</span>(i < len) {<br> <span class="hljs-keyword">let</span> left = intervals[i].start<br> <span class="hljs-keyword">let</span> right = intervals[i].end<br> <span class="hljs-keyword">while</span>(i<len-<span class="hljs-number">1</span> && intervals[i+<span class="hljs-number">1</span>].start <= right) {<br> right = <span class="hljs-built_in">Math</span>.max(right, intervals[i+<span class="hljs-number">1</span>].end)<br> i++<br> }<br> res.push(<span class="hljs-keyword">new</span> Interval(left, right))<br> i++<br> }<br> <br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="矩阵元素查找"><a href="#矩阵元素查找" class="headerlink" title="矩阵元素查找"></a><strong>矩阵元素查找</strong></h3><p>已知一个有序矩阵<strong>mat</strong>,同时给定矩阵的大小<strong>n</strong>和<strong>m</strong>以及需要查找的元素<strong>x</strong>,且矩阵的行和列都是从小到大有序的。设计查找算法返回所查找元素的二元数组,代表该元素的行号和列号(均从零开始)。保证元素互异。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findElement</span>(<span class="hljs-params"> mat , n , m , x </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<n; i++) {<br> <span class="hljs-keyword">if</span>(x > mat[i][m-<span class="hljs-number">1</span>] || x < mat[i][<span class="hljs-number">0</span>]) <span class="hljs-keyword">continue</span><br> <span class="hljs-keyword">let</span> l = <span class="hljs-number">0</span>, r = m-<span class="hljs-number">1</span>, mid = <span class="hljs-number">0</span><br> <span class="hljs-keyword">while</span>(l <= r) {<br> mid = <span class="hljs-built_in">Math</span>.floor((l+r)/<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">if</span>(x == mat[i][mid]) {<br> <span class="hljs-keyword">return</span> [i, mid]<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(x > mat[i][mid]) {<br> l = mid + <span class="hljs-number">1</span><br> }<span class="hljs-keyword">else</span> {<br> r = mid - <span class="hljs-number">1</span><br> }<br> }<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="缺失的第一个正整数"><a href="#缺失的第一个正整数" class="headerlink" title="缺失的第一个正整数"></a><strong>缺失的第一个正整数</strong></h3><p>给定一个无重复元素的整数数组nums,请你找出其中没有出现的最小的正整数</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">minNumberDisappeared</span>(<span class="hljs-params"> nums </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(nums.length === <span class="hljs-number">0</span> ) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">let</span> map = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">let</span> minNum = <span class="hljs-built_in">Number</span>.MAX_SAFE_INTEGER<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<nums.length; i++) {<br> <span class="hljs-keyword">if</span>(nums[i] > <span class="hljs-number">0</span>) {<br> minNum = <span class="hljs-built_in">Math</span>.min(minNum, nums[i])<br> map.set(nums[i], nums[i] + <span class="hljs-number">1</span>)<br> }<br> }<br> <span class="hljs-keyword">let</span> res = <span class="hljs-number">0</span><br> <span class="hljs-keyword">let</span> min = <span class="hljs-built_in">Number</span>.MAX_SAFE_INTEGER<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> [key, value] <span class="hljs-keyword">of</span> map) {<br> <span class="hljs-keyword">if</span>(!map.has(value)) {<br> min = <span class="hljs-built_in">Math</span>.min(min, key)<br> }<br> }<br> <span class="hljs-keyword">if</span>(minNum - <span class="hljs-number">1</span> > <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span><br> } <br> <span class="hljs-keyword">return</span> map.get(min)<br>}<br></code></pre></td></tr></table></figure><h3 id="最大正方形"><a href="#最大正方形" class="headerlink" title="最大正方形"></a><strong>最大正方形</strong></h3><p>给定一个由’0’和’1’组成的2维矩阵,返回该矩阵中最大的由’1’组成的正方形的面积,输入的矩阵是字符形式而非数字形式。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">solve</span>(<span class="hljs-params"> matrix </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br><span class="hljs-keyword">const</span> rows = matrix.length;<br> <span class="hljs-keyword">const</span> cols = matrix[<span class="hljs-number">0</span>] ? matrix[<span class="hljs-number">0</span>].length : <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">if</span>(rows===<span class="hljs-number">0</span> || cols===<span class="hljs-number">0</span> ) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">let</span> dp = []<br> <span class="hljs-keyword">let</span> max = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<rows; ++i){<br> dp.push([])<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=<span class="hljs-number">0</span>; j<cols; ++j){<br> <span class="hljs-keyword">if</span>( matrix[i][j] === <span class="hljs-string">'1'</span> ){<br> <span class="hljs-keyword">if</span>(i===<span class="hljs-number">0</span> || j===<span class="hljs-number">0</span>) {<br> dp[i][j] = <span class="hljs-number">1</span>;<br> }<span class="hljs-keyword">else</span>{<br> dp[i][j] = <span class="hljs-built_in">Math</span>.min(dp[i-<span class="hljs-number">1</span>][j], dp[i][j-<span class="hljs-number">1</span>], dp[i-<span class="hljs-number">1</span>][j-<span class="hljs-number">1</span>]) + <span class="hljs-number">1</span>;<br> }<br> }<span class="hljs-keyword">else</span>{<br> dp[i][j] = <span class="hljs-number">0</span>;<br> }<br> <br> <span class="hljs-keyword">if</span>(dp[i][j] > max ){<br> max = dp[i][j]<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> max*max;<br>}<br></code></pre></td></tr></table></figure><h3 id="连续子数组的最大乘积"><a href="#连续子数组的最大乘积" class="headerlink" title="连续子数组的最大乘积"></a><strong>连续子数组的最大乘积</strong></h3><p>输入一个长度为n的整型数组nums,数组中的一个或连续多个整数组成一个子数组。求所有子数组的乘积的最大值。</p><p>1.子数组是连续的,且最小长度为1,最大长度为n</p><p>2.长度为1的子数组,乘积视为其本身,比如[4]的乘积为4</p><p>3.该题的数据保证最大的乘积不会超过int的范围,即不超过2^{32}-1232−1</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxProduct</span>(<span class="hljs-params"> nums </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> n = nums.length<br> <span class="hljs-keyword">let</span> p1 = [].concat(nums)<br> <span class="hljs-keyword">let</span> p2 = [].concat(nums)<br> <span class="hljs-keyword">let</span> max = nums[<span class="hljs-number">0</span>]<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">1</span>; i<nums.length; i++) {<br> p1[i] = <span class="hljs-built_in">Math</span>.max(nums[i], <span class="hljs-built_in">Math</span>.max(nums[i]*p1[i-<span class="hljs-number">1</span>], nums[i]*p2[i-<span class="hljs-number">1</span>]))<br> p2[i] = <span class="hljs-built_in">Math</span>.min(nums[i], <span class="hljs-built_in">Math</span>.min(nums[i]*p1[i-<span class="hljs-number">1</span>], nums[i]*p2[i-<span class="hljs-number">1</span>]))<br> max = <span class="hljs-built_in">Math</span>.max(max, p1[i])<br> }<br> <span class="hljs-keyword">return</span> max<br>}<br></code></pre></td></tr></table></figure><h3 id="和为K的连续子数组"><a href="#和为K的连续子数组" class="headerlink" title="和为K的连续子数组"></a><strong>和为K的连续子数组</strong></h3><p>给定一个无序数组 arr , 其中元素可正、可负、可0。给定一个整数 k ,求 arr 所有连续子数组中累加和为k的最长连续子数组长度。保证至少存在一个合法的连续子数组。</p><p>[1,2,3]的连续子数组有[1,2],[2,3],[1,2,3] ,但是[1,3]不是</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxlenEqualK</span>(<span class="hljs-params"> arr , k </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(arr.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">let</span> map = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">let</span> n = arr.length<br> <span class="hljs-keyword">let</span> preNums = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(n+<span class="hljs-number">1</span>)<br> preNums[<span class="hljs-number">0</span>] = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">1</span>; i<=n; i++) {<br> preNums[i] = preNums[i-<span class="hljs-number">1</span>] + arr[i-<span class="hljs-number">1</span>]<br> <span class="hljs-keyword">if</span>(!map.has(preNums[i])) {<br> map.set(preNums[i], i)<br> }<br> }<br> <span class="hljs-keyword">let</span> res = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=n; i>=<span class="hljs-number">0</span>; i--) {<br> <span class="hljs-keyword">let</span> target = preNums[i] - k <br> <span class="hljs-keyword">if</span>(map.has(target)) {<br> res = <span class="hljs-built_in">Math</span>.max(res, i - map.get(target))<br> }<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="岛屿数量"><a href="#岛屿数量" class="headerlink" title="岛屿数量"></a><strong>岛屿数量</strong></h3><p>给一个01矩阵,1代表是陆地,0代表海洋, 如果两个1相邻,那么这两个1属于同一个岛。我们只考虑上下左右为相邻。</p><p>岛屿: 相邻陆地可以组成一个岛屿(相邻:上下左右) 判断岛屿个数。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">solve</span>(<span class="hljs-params"> grid </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!grid || grid[<span class="hljs-number">0</span>] === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">let</span> res = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<grid.length; i++) {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=<span class="hljs-number">0</span>; j<grid[<span class="hljs-number">0</span>].length; j++) {<br> <span class="hljs-keyword">if</span>(grid[i][j] === <span class="hljs-string">'1'</span>) {<br> res++<br> dfs(grid, i, j)<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dfs</span>(<span class="hljs-params">grid, i, j</span>) </span>{<br> <span class="hljs-keyword">if</span>(i<<span class="hljs-number">0</span> || i>=grid.length || j<<span class="hljs-number">0</span> || j>=grid[<span class="hljs-number">0</span>].length || grid[i][j] === <span class="hljs-string">'0'</span>) {<br> <span class="hljs-keyword">return</span><br> }<br> grid[i][j] = <span class="hljs-string">'0'</span><br> dfs(grid, i-<span class="hljs-number">1</span>, j)<br> dfs(grid, i+<span class="hljs-number">1</span>, j)<br> dfs(grid, i, j+<span class="hljs-number">1</span>)<br> dfs(grid, i, j-<span class="hljs-number">1</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="最长无重复子数组"><a href="#最长无重复子数组" class="headerlink" title="最长无重复子数组"></a><strong>最长无重复子数组</strong></h3><p>给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。</p><p>子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxLength</span>(<span class="hljs-params"> arr </span>) </span>{<br> <span class="hljs-keyword">if</span>(arr.length <= <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> arr.length<br> }<br> <span class="hljs-keyword">let</span> start=<span class="hljs-number">0</span>,end =<span class="hljs-number">0</span>,max=<span class="hljs-number">0</span><br> <span class="hljs-keyword">const</span> map = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">while</span>(end < arr.length) {<br> <span class="hljs-keyword">if</span>(map.has(arr[end])) {<br> start = <span class="hljs-built_in">Math</span>.max(start, map.get(arr[end]) + <span class="hljs-number">1</span>)<br> }<br> map.set(arr[end], end)<br> max = <span class="hljs-built_in">Math</span>.max(max, end-start+<span class="hljs-number">1</span>)<br> end ++<br> }<br> <span class="hljs-keyword">return</span> max<br>}<br></code></pre></td></tr></table></figure><h3 id="顺时针旋转矩阵"><a href="#顺时针旋转矩阵" class="headerlink" title="顺时针旋转矩阵"></a><strong>顺时针旋转矩阵</strong></h3><p>有一个NxN整数矩阵,请编写一个算法,将矩阵顺时针旋转90度。</p><p>给定一个NxN的矩阵,和矩阵的阶数N,请返回旋转后的NxN矩阵。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rotateMatrix</span>(<span class="hljs-params"> mat , n </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> arr = <span class="hljs-built_in">Array</span>(n).fill(<span class="hljs-number">0</span>).map(<span class="hljs-function"><span class="hljs-params">x</span> =></span> <span class="hljs-built_in">Array</span>(n).fill(<span class="hljs-number">0</span>));<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>;i < n;i++){<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j = <span class="hljs-number">0</span>;j < n;j++){<br> arr[j][n - i - <span class="hljs-number">1</span>] = mat[i][j];<br> }<br> }<br> <span class="hljs-keyword">return</span> arr;<br>}<br></code></pre></td></tr></table></figure><h3 id="二分查找-I"><a href="#二分查找-I" class="headerlink" title="二分查找-I"></a><strong>二分查找-I</strong></h3><p>请实现无重复数字的升序数组的二分查找</p><p>给定一个 元素升序的、无重复数字的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标(下标从 0 开始),否则返回 -1</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params"> nums , target </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(nums.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">let</span> left = <span class="hljs-number">0</span>, right = nums.length - <span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(left <= right) {<br> <span class="hljs-keyword">let</span> mid = <span class="hljs-built_in">Math</span>.floor((left+right)/<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">if</span>(nums[mid] === target) {<br> <span class="hljs-keyword">return</span> mid<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(nums[mid] < target) {<br> left = mid + <span class="hljs-number">1</span><br> }<span class="hljs-keyword">else</span> {<br> right = mid - <span class="hljs-number">1</span><br> }<br> }<br> <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span><br>}<br></code></pre></td></tr></table></figure><h3 id="二维数组中的查找"><a href="#二维数组中的查找" class="headerlink" title="二维数组中的查找"></a><strong>二维数组中的查找</strong></h3><p>在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。</p><p>[</p><p>[1,2,8,9],<br>[2,4,9,12],<br>[4,7,10,13],<br>[6,8,11,15]</p><p>]</p><p>给定 target = 7,返回 true。</p><p>给定 target = 3,返回 false。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Find</span>(<span class="hljs-params">target, array</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(array.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">let</span> m = array.length, n = array[<span class="hljs-number">0</span>].length<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<m; i++) {<br> <span class="hljs-keyword">if</span>(target < array[i][<span class="hljs-number">0</span>] || target > array[i][n-<span class="hljs-number">1</span>]) <br> <span class="hljs-keyword">continue</span><br> <span class="hljs-keyword">let</span> l = <span class="hljs-number">0</span>, r = n - <span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(l <= r) {<br> <span class="hljs-keyword">let</span> mid = <span class="hljs-built_in">Math</span>.floor((l+r)/<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">if</span>(array[i][mid] === target) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(target > array[i][mid]) {<br> l = mid + <span class="hljs-number">1</span><br> }<span class="hljs-keyword">else</span> {<br> r = mid - <span class="hljs-number">1</span><br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br>}<br></code></pre></td></tr></table></figure><h3 id="寻找峰值"><a href="#寻找峰值" class="headerlink" title="寻找峰值"></a><strong>寻找峰值</strong></h3><p>给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。</p><p>1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于</p><p>2.假设 nums[-1] = nums[n] = -\infty−∞</p><p>3.对于所有有效的 i 都有 nums[i] != nums[i + 1]</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findPeakElement</span>(<span class="hljs-params"> nums </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(nums.length <= <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">if</span>(nums[<span class="hljs-number">0</span>] > nums[<span class="hljs-number">1</span>]) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">if</span>(nums[nums.length-<span class="hljs-number">1</span>] > nums[nums.length-<span class="hljs-number">2</span>]) {<br> <span class="hljs-keyword">return</span> nums.length - <span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">let</span> l = <span class="hljs-number">0</span>, r = nums.length - <span class="hljs-number">1</span><br> <span class="hljs-keyword">let</span> mid = <span class="hljs-built_in">Math</span>.floor((l+r)/<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">if</span>(nums[mid] > nums[mid-<span class="hljs-number">1</span>] && nums[mid] > nums[mid+<span class="hljs-number">1</span>]) {<br> <span class="hljs-keyword">return</span> mid<br> }<br> <span class="hljs-keyword">let</span> n1 = findPeakElement(nums.slice(<span class="hljs-number">0</span>, mid-<span class="hljs-number">1</span>))<br> <span class="hljs-keyword">let</span> n2 = findPeakElement(nums.slice(mid+<span class="hljs-number">1</span>, nums.length))<br> <span class="hljs-keyword">if</span>(n1 !== -<span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> n1<br> }<br> <span class="hljs-keyword">if</span>(n2 !== -<span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> n2<br> }<br> <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span><br>}<br></code></pre></td></tr></table></figure><h3 id="没有重复项数字的全排列"><a href="#没有重复项数字的全排列" class="headerlink" title="没有重复项数字的全排列"></a><strong>没有重复项数字的全排列</strong></h3><p>给出一组数字,返回该组数字的所有排列</p><p>例如:</p><p>[1,2,3]的所有排列如下<br>[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2], [3,2,1].<br>(以数字在数组中的位置靠前为优先级,按字典序排列输出。)</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">permute</span>(<span class="hljs-params"> num </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(num.length <= <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> [num]<br> }<br> <span class="hljs-keyword">let</span> res = [], path = []<br> backTracking(num, path, res)<br> <span class="hljs-keyword">return</span> res<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">backTracking</span>(<span class="hljs-params">num, path, res</span>) </span>{<br> <span class="hljs-keyword">if</span>(path.length === num.length) {<br> res.push([].concat(path))<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<num.length; i++) {<br> <span class="hljs-keyword">if</span>(path.indexOf(num[i]) > -<span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">continue</span><br> }<br> path.push(num[i])<br> backTracking(num, path, res)<br> path.pop()<br> }<br> }<br></code></pre></td></tr></table></figure><h3 id="有重复项数字的全排列"><a href="#有重复项数字的全排列" class="headerlink" title="有重复项数字的全排列"></a><strong>有重复项数字的全排列</strong></h3><p>给出一组可能包含重复项的数字,返回该组数字的所有排列。结果以字典序升序排列。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">permuteUnique</span>(<span class="hljs-params"> num </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(num.length <= <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> [num]<br> }<br> <span class="hljs-keyword">let</span> res = [], path = [], mark=<span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(num.length)<br> num.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =></span> a-b)<br> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">backTracking</span>(<span class="hljs-params">num, path, res</span>) </span>{<br> <span class="hljs-keyword">if</span>(path.length === num.length) {<br> res.push([].concat(path))<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<num.length; i++) {<br> <span class="hljs-keyword">if</span>(i><span class="hljs-number">0</span> && num[i] == num[i-<span class="hljs-number">1</span>] && !mark[i-<span class="hljs-number">1</span>] || mark[i]) {<br> <span class="hljs-keyword">continue</span><br> }<br> path.push(num[i])<br> mark[i] = <span class="hljs-literal">true</span><br> backTracking(num, path, res)<br> path.pop()<br> mark[i] = <span class="hljs-literal">false</span><br> }<br> }<br> <br> backTracking(num, path, res)<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h2 id="链表"><a href="#链表" class="headerlink" title="链表"></a>链表</h2><h3 id="重排链表"><a href="#重排链表" class="headerlink" title="重排链表"></a>重排链表</h3><p>将给定的单链表L: L_0→L_1→…→L_{n-1}→L_ n<em>L</em>0→<em>L</em>1→…→Ln−1→Ln<br>重新排序为:L_0→L_n →L_1→L_{n-1}→L_2→L_{n-2}→…<em>L</em>0→Ln→L1→Ln<em>−1→</em>L<em>2→</em>L*<em>n</em>−2→…<br>要求使用原地算法,不能只改变节点内部的值,需要对实际的节点进行交换。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reorderList</span>(<span class="hljs-params"> head </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!head) {<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">const</span> res = []<br> <span class="hljs-keyword">while</span>(head) {<br> res.push(head)<br> head = head.next<br> }<br> <span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>,j=res.length -<span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(i<j) {<br> res[i].next = res[j]<br> i++<br> <span class="hljs-keyword">if</span>(i===j){<br> <span class="hljs-keyword">break</span><br> }<br> res[j].next = res[i]<br> j--<br> }<br> res[i].next = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">return</span> res[i]<br>}<br></code></pre></td></tr></table></figure><h3 id="链表中环的入口结点"><a href="#链表中环的入口结点" class="headerlink" title="链表中环的入口结点"></a>链表中环的入口结点</h3><p>给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">EntryNodeOfLoop</span>(<span class="hljs-params">pHead</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(pHead === <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span><br> }<br> <span class="hljs-keyword">let</span> p1 = pHead,p2=pHead<br> <span class="hljs-keyword">while</span>(p2 !== <span class="hljs-literal">null</span> && p2.next !== <span class="hljs-literal">null</span>) {<br> p1 = p1.next<br> p2 = p2.next.next<br> <span class="hljs-keyword">if</span>(p1.val === p2.val) {<br> <span class="hljs-keyword">let</span> p3 = pHead<br> <span class="hljs-keyword">while</span>(p2 !== p3) {<br> p2 = p2.next<br> p3 = p3.next<br> }<br> <span class="hljs-keyword">return</span> p3<br> }<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="合并两个排序的链表"><a href="#合并两个排序的链表" class="headerlink" title="合并两个排序的链表"></a><strong>合并两个排序的链表</strong></h3><p>输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ListNode</span>(<span class="hljs-params">x</span>) </span>{<br> <span class="hljs-built_in">this</span>.val = x<br> <span class="hljs-built_in">this</span>.next = <span class="hljs-literal">null</span><br><br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Merge</span>(<span class="hljs-params">pHead1, pHead2</span>) </span>{<br> <span class="hljs-keyword">if</span>(pHead1 === <span class="hljs-literal">null</span> || pHead2 === <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> pHead1 || pHead2<br> }<br> <span class="hljs-keyword">let</span> newList = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">if</span>(pHead1.val < pHead2.val) {<br> newList = pHead1<br> newList.next = Merge(pHead1.next, pHead2)<br> }<span class="hljs-keyword">else</span> {<br> newList = pHead2<br> newList.next = Merge(pHead1, pHead2.next)<br> }<br> <span class="hljs-keyword">return</span> newList<br>}<br></code></pre></td></tr></table></figure><h3 id="-2"><a href="#-2" class="headerlink" title=""></a></h3><h3 id="两个链表生成相加链表"><a href="#两个链表生成相加链表" class="headerlink" title="两个链表生成相加链表"></a><strong>两个链表生成相加链表</strong></h3><p>假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。</p><p>给定两个这种链表,请生成代表两个整数相加值的结果链表。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addInList</span>(<span class="hljs-params"> head1 , head2 </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!head1 || !head2) {<br> <span class="hljs-keyword">return</span> head1 || head2<br> }<br> <span class="hljs-comment">// 反转</span><br> head1 = reverse(head1)<br> head2 = reverse(head2)<br> <span class="hljs-comment">// 相加</span><br> <span class="hljs-keyword">let</span> carry = <span class="hljs-number">0</span><br> <span class="hljs-keyword">let</span> head = <span class="hljs-keyword">new</span> ListNode(<span class="hljs-literal">null</span>)<br> <span class="hljs-keyword">let</span> nHead = head<br> <span class="hljs-keyword">while</span>(head1 || head2) {<br> <span class="hljs-keyword">let</span> val = carry<br> <span class="hljs-keyword">if</span>(head1) {<br> val += head1.val<br> head1 = head1.next<br> }<br> <span class="hljs-keyword">if</span>(head2) {<br> val += head2.val<br> head2 = head2.next<br> }<br> <br> carry = <span class="hljs-built_in">Math</span>.floor(val/<span class="hljs-number">10</span>)<br> nHead.next = <span class="hljs-keyword">new</span> ListNode(val%<span class="hljs-number">10</span>)<br> nHead = nHead.next<br> }<br> <br> <span class="hljs-keyword">if</span>(carry === <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">const</span> node = <span class="hljs-keyword">new</span> ListNode(<span class="hljs-number">1</span>)<br> nHead.next = node<br> }<br> <span class="hljs-keyword">return</span> reverse(head.next)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reverse</span>(<span class="hljs-params">head</span>) </span>{<br> <span class="hljs-keyword">let</span> pre = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">while</span>(head) {<br> <span class="hljs-keyword">const</span> node = head.next<br> head.next = pre<br> pre = head<br> head = node<br> }<br> <span class="hljs-keyword">return</span> pre<br>}<br></code></pre></td></tr></table></figure><h3 id="链表中的节点每k个一组翻转"><a href="#链表中的节点每k个一组翻转" class="headerlink" title="链表中的节点每k个一组翻转"></a><strong>链表中的节点每k个一组翻转</strong></h3><p>将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表<br>如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样<br>你不能更改节点中的值,只能更改节点本身。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reverseKGroup</span>(<span class="hljs-params"> head , k </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> node = head<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<k; i++) {<br> <span class="hljs-keyword">if</span>(!node) {<br> <span class="hljs-keyword">return</span> head<br> }<br> node = node.next<br> }<br> <span class="hljs-keyword">const</span> res = reverse(head, node)<br> head.next = reverseKGroup(node, k)<br> <span class="hljs-keyword">return</span> res<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reverse</span>(<span class="hljs-params">left, right</span>) </span>{<br> <span class="hljs-keyword">let</span> pre = right<br> <span class="hljs-keyword">while</span>(left != right) {<br> <span class="hljs-keyword">let</span> node = left.next<br> left.next = pre<br> pre = left<br> left = node<br> }<br> <span class="hljs-keyword">return</span> pre<br>}<br></code></pre></td></tr></table></figure><h3 id="删除链表的倒数第n个节点"><a href="#删除链表的倒数第n个节点" class="headerlink" title="删除链表的倒数第n个节点"></a><strong>删除链表的倒数第n个节点</strong></h3><p>给定一个链表,删除链表的倒数第 n 个节点并返回链表的头指针<br>例如,</p><p>给出的链表为: 1\to 2\to 3\to 4\to 51→2→3→4→5, n= 2<em>n</em>=2.<br>删除了链表的倒数第 n<em>n</em> 个节点之后,链表变为1\to 2\to 3\to 51→2→3→5.</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">removeNthFromEnd</span>(<span class="hljs-params"> head , n </span>) </span>{<br> <span class="hljs-keyword">if</span>(head == <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> head<br> }<br> <span class="hljs-keyword">let</span> slower = head<br> <span class="hljs-keyword">let</span> faster = head<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<n; i++) {<br> faster = faster.next<br> }<br> <span class="hljs-comment">// 判断 n 是否大于 head 的长度</span><br> <span class="hljs-keyword">if</span>(faster == <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> head.next<br> }<br> <span class="hljs-keyword">while</span>(faster.next) {<br> faster = faster.next<br> slower = slower.next<br> }<br> slower.next = slower.next.next<br> <span class="hljs-keyword">return</span> head<br>}<br></code></pre></td></tr></table></figure><h3 id="两个链表的第一个公共结点"><a href="#两个链表的第一个公共结点" class="headerlink" title="两个链表的第一个公共结点"></a><strong>两个链表的第一个公共结点</strong></h3><p>输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FindFirstCommonNode</span>(<span class="hljs-params">pHead1, pHead2</span>) </span>{<br> <span class="hljs-keyword">if</span> (pHead1 === <span class="hljs-literal">null</span> || pHead2 === <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span>;<br> }<br> <span class="hljs-keyword">const</span> temp = pHead2;<br> <span class="hljs-keyword">while</span> (pHead1) {<br> <span class="hljs-keyword">while</span> (pHead2) {<br> <span class="hljs-keyword">if</span> (pHead1.val === pHead2.val) {<br> <span class="hljs-keyword">return</span> pHead1;<br> }<span class="hljs-keyword">else</span> {<br> pHead2 = pHead2.next;<br> }<br> }<br> pHead1 = pHead1.next;<br> pHead2 = temp;<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="链表中倒数最后k个结点"><a href="#链表中倒数最后k个结点" class="headerlink" title="链表中倒数最后k个结点"></a><strong>链表中倒数最后k个结点</strong></h3><p>输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。</p><p>如果该链表长度小于k,请返回一个长度为 0 的链表。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FindKthToTail</span>(<span class="hljs-params"> pHead , k </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> fast = pHead, slow = pHead,n=<span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span>(fast) {<br> fast = fast.next<br> n++<br> <span class="hljs-keyword">if</span>(n===k){<br> slow = slow.next<br> }<br> }<br> <br> <span class="hljs-keyword">return</span> n<k? <span class="hljs-literal">null</span> : slow<br>}<br></code></pre></td></tr></table></figure><h3 id="-3"><a href="#-3" class="headerlink" title=""></a></h3><h3 id="反转链表"><a href="#反转链表" class="headerlink" title="反转链表"></a><strong>反转链表</strong></h3><p>给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/*function ListNode(x){</span><br><span class="hljs-comment"> this.val = x;</span><br><span class="hljs-comment"> this.next = null;</span><br><span class="hljs-comment">}*/</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ReverseList</span>(<span class="hljs-params">pHead</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!pHead) {<br> <span class="hljs-keyword">return</span> pHead<br> }<br> <span class="hljs-keyword">let</span> pre = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">while</span>(pHead) {<br> <span class="hljs-keyword">let</span> next = pHead.next<br> pHead.next = pre<br> pre=pHead<br> pHead = next<br> }<br> <span class="hljs-keyword">return</span> pre<br>}<br></code></pre></td></tr></table></figure><h3 id="单链表的排序"><a href="#单链表的排序" class="headerlink" title="单链表的排序"></a><strong>单链表的排序</strong></h3><p>给定一个节点数为n的无序单链表,对其按升序排序。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sortInList</span>(<span class="hljs-params"> head </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!head || !head.next) {<br> <span class="hljs-keyword">return</span> head<br> }<br> <span class="hljs-comment">// 归并排序</span><br> <span class="hljs-keyword">let</span> slower = head, faster = head.next<br> <span class="hljs-keyword">while</span>(faster && faster.next) {<br> slower = slower.next<br> faster = faster.next.next<br> }<br> <span class="hljs-keyword">let</span> tmp = slower.next<br> slower.next = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">let</span> left = sortInList(head)<br> <span class="hljs-keyword">let</span> right = sortInList(tmp)<br> <br> <span class="hljs-keyword">let</span> res = <span class="hljs-keyword">new</span> ListNode(<span class="hljs-number">0</span>)<br> <span class="hljs-keyword">let</span> cur = res<br> <span class="hljs-keyword">while</span>(left && right) {<br> <span class="hljs-keyword">if</span>(left.val < right.val) {<br> res.next = left<br> left = left.next<br> }<span class="hljs-keyword">else</span> {<br> res.next = right<br> right = right.next<br> }<br> res = res.next<br> }<br> res.next = left != <span class="hljs-literal">null</span> ? left : right<br> <span class="hljs-keyword">return</span> cur.next<br>}<br></code></pre></td></tr></table></figure><h3 id="判断一个链表是否为回文结构"><a href="#判断一个链表是否为回文结构" class="headerlink" title="判断一个链表是否为回文结构"></a><strong>判断一个链表是否为回文结构</strong></h3><p>给定一个链表,请判断该链表是否为回文结构。</p><p>回文是指该字符串正序逆序完全一致。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isPail</span>(<span class="hljs-params"> head </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!head || !head.next) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> }<br> <span class="hljs-keyword">let</span> slower = head, faster = head<br> <span class="hljs-keyword">while</span>(faster && faster.next) {<br> slower = slower.next<br> faster = faster.next.next<br> }<br> <span class="hljs-keyword">if</span>(faster) {<br> slower = slower.next<br> }<br> <span class="hljs-keyword">let</span> tmp = reverse(slower)<br> <br> <span class="hljs-keyword">while</span>(tmp) {<br> <span class="hljs-keyword">if</span>(tmp.val == head.val) {<br> tmp = tmp.next<br> head = head.next<br> }<span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reverse</span>(<span class="hljs-params">head</span>) </span>{<br> <span class="hljs-keyword">let</span> pre = <span class="hljs-literal">null</span><br> <span class="hljs-keyword">while</span>(head) {<br> <span class="hljs-keyword">let</span> node = head.next<br> head.next = pre<br> pre = head<br> head = node<br> }<br> <span class="hljs-keyword">return</span> pre<br>}<br></code></pre></td></tr></table></figure><h3 id="链表内指定区间反转"><a href="#链表内指定区间反转" class="headerlink" title="链表内指定区间反转"></a><strong>链表内指定区间反转</strong></h3><p>将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)<em>O</em>(<em>n</em>),空间复杂度 O(1)<em>O</em>(1)。<br>例如:<br>给出的链表为 1\to 2 \to 3 \to 4 \to 5 \to NULL1→2→3→4→5→<em>N<strong>U</strong>L**L</em>, m=2,n=4<em>m</em>=2,<em>n</em>=4,<br>返回 1\to 4\to 3\to 2\to 5\to NULL1→4→3→2→5→<em>N<strong>U</strong>L**L</em>.</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reverseBetween</span>(<span class="hljs-params"> head , m , n </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> newHead=<span class="hljs-keyword">new</span> ListNode(<span class="hljs-number">0</span>)<br> newHead.next=head<br> head=newHead<br> <span class="hljs-keyword">let</span> p=head,q=head.next<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">1</span>;i<m;i++){<br> p=p.next<br> }<br> q=p.next<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=m;i<n;i++){<br> <span class="hljs-keyword">let</span> temp=p.next<br> p.next=q.next<br> q.next=q.next.next<br> p.next.next=temp<br> }<br> <span class="hljs-keyword">return</span> head.next<br>}<br></code></pre></td></tr></table></figure><h3 id="删除有序链表中重复的元素-I"><a href="#删除有序链表中重复的元素-I" class="headerlink" title="删除有序链表中重复的元素-I"></a><strong>删除有序链表中重复的元素-I</strong></h3><p>删除给出链表中的重复元素(链表中元素从小到大有序),使链表中的所有元素都只出现一次</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteDuplicates</span>(<span class="hljs-params"> head </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!head) {<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">let</span> dumy = <span class="hljs-keyword">new</span> ListNode(<span class="hljs-number">0</span>)<br> dumy.next = head<br> <span class="hljs-keyword">while</span>(head.next) {<br> <span class="hljs-keyword">if</span>(head.val === head.next.val) {<br> <span class="hljs-comment">// 下个元素删除</span><br> head.next = head.next.next<br> }<span class="hljs-keyword">else</span> {<br> head = head.next<br> }<br> }<br> <span class="hljs-keyword">return</span> dumy.next<br>}<br></code></pre></td></tr></table></figure><h3 id="删除有序链表中重复的元素-II"><a href="#删除有序链表中重复的元素-II" class="headerlink" title="删除有序链表中重复的元素-II"></a><strong>删除有序链表中重复的元素-II</strong></h3><p>给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。<br>例如:<br>给出的链表为1 \to 2\to 3\to 3\to 4\to 4\to51→2→3→3→4→4→5, 返回1\to 2\to51→2→5.<br>给出的链表为1\to1 \to 1\to 2 \to 31→1→1→2→3, 返回2\to 32→3.</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteDuplicates</span>(<span class="hljs-params"> head </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!head || !head.next) {<br> <span class="hljs-keyword">return</span> head<br> }<br> <span class="hljs-keyword">let</span> dumy = <span class="hljs-keyword">new</span> ListNode(-<span class="hljs-number">1</span>)<br> dumy.next = head<br> <span class="hljs-keyword">let</span> pre = dumy, flag = dumy, cur = head<br> <span class="hljs-keyword">while</span>(cur.next) {<br> <span class="hljs-keyword">if</span>(cur.val !== cur.next.val && cur.val !== pre.val) {<br> flag.next = cur<br> flag = flag.next<br> }<br> pre = cur<br> cur = cur.next<br> }<br> <span class="hljs-keyword">if</span>(flag != pre) {<br> flag.next = cur.next<br> }<br> <span class="hljs-keyword">if</span>(pre.val != cur.val) {<br> flag.next = cur<br> }<br> <span class="hljs-keyword">return</span> dumy.next<br>}<br></code></pre></td></tr></table></figure><h3 id="链表的奇偶重排"><a href="#链表的奇偶重排" class="headerlink" title="链表的奇偶重排"></a><strong>链表的奇偶重排</strong></h3><p>给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。</p><p>注意是节点的编号而非节点的数值。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">oddEvenList</span>(<span class="hljs-params"> head </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(!head) {<br> <span class="hljs-keyword">return</span> head<br> }<br> <br> <span class="hljs-keyword">let</span> p = head, q = head.next<br> <span class="hljs-keyword">let</span> dumy = p,<br> dumy2 = q<br> <span class="hljs-keyword">while</span>(p.next && q.next) {<br> <span class="hljs-keyword">if</span>(p.next) {<br> p.next = p.next.next<br> p = p.next<br> }<br> <span class="hljs-keyword">if</span>(q.next) {<br> q.next = q.next.next<br> q = q.next<br> }<br> }<br> p.next = dumy2<br> <span class="hljs-keyword">return</span> dumy<br>}<br></code></pre></td></tr></table></figure><h3 id="判断链表中是否有环"><a href="#判断链表中是否有环" class="headerlink" title="判断链表中是否有环"></a>判断链表中是否有环</h3><p>判断给定的链表中是否有环。如果有环则返回true,否则返回false。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hasCycle</span>(<span class="hljs-params"> head </span>) </span>{<br> <span class="hljs-keyword">if</span> (!head || !head.next) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">let</span> faster = head,slower = head<br> <span class="hljs-keyword">while</span>(faster && slower) {<br> slower = slower.next<br> <span class="hljs-keyword">if</span>(faster.next) {<br> faster = faster.next.next<br> }<span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">if</span>(faster === slower) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br>}<br></code></pre></td></tr></table></figure><h2 id="数学"><a href="#数学" class="headerlink" title="数学"></a>数学</h2><h3 id="斐波那契数列"><a href="#斐波那契数列" class="headerlink" title="斐波那契数列"></a>斐波那契数列</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> deepCache = {}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fibonacci2</span>(<span class="hljs-params">num</span>) </span>{<br> <span class="hljs-keyword">if</span> (num < <span class="hljs-number">2</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">if</span> (deepCache[num]) {<br> <span class="hljs-keyword">return</span> deepCache<br> }<br> <span class="hljs-keyword">return</span> deepCache[num] = fibonacci2(num - <span class="hljs-number">1</span>) + fibonacci2(num - <span class="hljs-number">2</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="大数加法"><a href="#大数加法" class="headerlink" title="大数加法"></a>大数加法</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">solve</span>(<span class="hljs-params"> s , t </span>) </span>{<br> <span class="hljs-keyword">if</span>(s===<span class="hljs-string">''</span> || t===<span class="hljs-string">''</span>) {<br> <span class="hljs-keyword">return</span> s+t<br> }<br> <span class="hljs-keyword">let</span> m=s.length, n=t.length,res=[]<br> <span class="hljs-keyword">while</span>(m<n) {<br> s = <span class="hljs-string">'0'</span> + s<br> m = s.length<br> }<br> <span class="hljs-keyword">while</span>(m>n) {<br> t = <span class="hljs-string">'0'</span> + t<br> n = t.length<br> }<br> <span class="hljs-keyword">let</span> carry = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-built_in">Math</span>.max(m,n)-<span class="hljs-number">1</span>; i>=<span class="hljs-number">0</span>; i--) {<br> <span class="hljs-keyword">let</span> temp = <span class="hljs-built_in">parseInt</span>(s[i]) + <span class="hljs-built_in">parseInt</span>(t[i]) + carry<br> carry = <span class="hljs-built_in">Math</span>.floor(temp/<span class="hljs-number">10</span>) > <span class="hljs-number">0</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span><br> res.unshift(temp % <span class="hljs-number">10</span>)<br> }<br> <span class="hljs-keyword">if</span>(carry == <span class="hljs-number">1</span>) {<br> res.unshift(<span class="hljs-number">1</span>)<br> }<br> <span class="hljs-keyword">return</span> res.join(<span class="hljs-string">''</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="螺旋矩阵"><a href="#螺旋矩阵" class="headerlink" title="螺旋矩阵"></a><strong>螺旋矩阵</strong></h3><p>给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">spiralOrder</span>(<span class="hljs-params"> matrix </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(matrix.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> []<br> }<br> <span class="hljs-keyword">let</span> m = matrix.length, n = matrix[<span class="hljs-number">0</span>].length<br> <span class="hljs-keyword">let</span> top = <span class="hljs-number">0</span>, left = <span class="hljs-number">0</span>, right = n-<span class="hljs-number">1</span>, bottom = m-<span class="hljs-number">1</span><br> <span class="hljs-keyword">let</span> res = []<br> <span class="hljs-keyword">while</span>(top < <span class="hljs-built_in">Math</span>.floor((m+<span class="hljs-number">1</span>)/<span class="hljs-number">2</span>) && left < <span class="hljs-built_in">Math</span>.floor((n+<span class="hljs-number">1</span>)/<span class="hljs-number">2</span>)) {<br> <span class="hljs-comment">// 上面</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=left; i<=right; i++) {<br> res.push(matrix[top][i])<br> }<br> <span class="hljs-comment">// 右边</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=top+<span class="hljs-number">1</span>; i<=bottom; i++) {<br> res.push(matrix[i][right])<br> }<br> <span class="hljs-comment">// 下边</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=right-<span class="hljs-number">1</span>; top != bottom && i>=left; i--) {<br> res.push(matrix[bottom][i])<br> }<br> <span class="hljs-comment">// 左边</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=bottom-<span class="hljs-number">1</span>; left !=right && i>=top+<span class="hljs-number">1</span>; i--) {<br> res.push(matrix[i][left])<br> }<br> top ++<br> left ++<br> right --<br> bottom --<br> }<br> <span class="hljs-keyword">return</span> res<br>}<br></code></pre></td></tr></table></figure><h3 id="有效括号序列"><a href="#有效括号序列" class="headerlink" title="有效括号序列"></a><strong>有效括号序列</strong></h3><p>给出一个仅包含字符’(‘,’)’,’{‘,’}’,’[‘和’]’,的字符串,判断给出的字符串是否是合法的括号序列<br>括号必须以正确的顺序关闭,”()”和”()[]{}”都是合法的括号序列,但”(]”和”([)]”不合法。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isValid</span>(<span class="hljs-params"> s </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(s.length == <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">let</span> stack = []<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<s.length; i++) {<br> <span class="hljs-keyword">if</span>(stack.length == <span class="hljs-number">0</span>) {<br> stack.push(s[i])<br> }<span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">if</span>(stack[stack.length-<span class="hljs-number">1</span>] == <span class="hljs-string">'{'</span> && s[i] == <span class="hljs-string">'}'</span>) {<br> stack.pop()<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(stack[stack.length-<span class="hljs-number">1</span>] == <span class="hljs-string">'('</span> && s[i] == <span class="hljs-string">')'</span>) {<br> stack.pop()<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(stack[stack.length-<span class="hljs-number">1</span>] == <span class="hljs-string">'['</span> && s[i] == <span class="hljs-string">']'</span>) {<br> stack.pop()<br> }<span class="hljs-keyword">else</span> {<br> stack.push(s[i])<br> }<br> } <br> }<br> <span class="hljs-keyword">return</span> stack.length == <span class="hljs-number">0</span><br>}<br></code></pre></td></tr></table></figure><h3 id="两数之和"><a href="#两数之和" class="headerlink" title="两数之和"></a><strong>两数之和</strong></h3><p>给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">twoSum</span>(<span class="hljs-params"> numbers , target </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(numbers.length ===<span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <br> }<br> <span class="hljs-keyword">const</span> map = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<numbers.length; i++) {<br> <span class="hljs-keyword">if</span>(map.has(target-numbers[i])) {<br> <span class="hljs-keyword">return</span> [map.get(target-numbers[i]) + <span class="hljs-number">1</span>, i + <span class="hljs-number">1</span>]<br> }<span class="hljs-keyword">else</span> {<br> map.set(numbers[i], i)<br> }<br> }<br> <br>}<br></code></pre></td></tr></table></figure><h3 id="扑克牌顺子"><a href="#扑克牌顺子" class="headerlink" title="扑克牌顺子"></a><strong>扑克牌顺子</strong></h3><p>现在有2副扑克牌,从扑克牌中随机五张扑克牌,我们需要来判断一下是不是顺子。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">IsContinuous</span>(<span class="hljs-params">numbers</span>) </span>{<br><br> numbers = numbers.sort()<br> <span class="hljs-keyword">let</span> zeroNum = <span class="hljs-number">0</span><br> <span class="hljs-keyword">let</span> nums = []<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {<br> <span class="hljs-keyword">if</span> (numbers[i] === <span class="hljs-number">0</span>) {<br> zeroNum++<br> } <span class="hljs-keyword">else</span> {<br> nums.push(numbers[i])<br> }<br> }<br> <span class="hljs-keyword">const</span> len = nums.length<br> <span class="hljs-keyword">const</span> numSet = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Set</span>(nums)<br> <span class="hljs-keyword">if</span> (len !== numSet.size) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">let</span> differ = nums[len-<span class="hljs-number">1</span>] - nums[<span class="hljs-number">0</span>];<br> <span class="hljs-keyword">switch</span> (zeroNum) {<br> <span class="hljs-keyword">case</span> <span class="hljs-number">0</span>:<br> <span class="hljs-keyword">return</span> differ === <span class="hljs-number">4</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:<br> <span class="hljs-keyword">return</span> (differ >= <span class="hljs-number">3</span> && differ <= <span class="hljs-number">4</span>) ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:<br> <span class="hljs-keyword">return</span> (differ >= <span class="hljs-number">2</span> && differ <= <span class="hljs-number">4</span>) ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">3</span>:<br> <span class="hljs-keyword">return</span> (differ >= <span class="hljs-number">1</span> && differ <= <span class="hljs-number">4</span>) ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span><br> <span class="hljs-attr">default</span>:<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> }<br>}<br><br></code></pre></td></tr></table></figure><h3 id="跳台阶"><a href="#跳台阶" class="headerlink" title="跳台阶"></a><strong>跳台阶</strong></h3><p>一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">jumpFloor</span>(<span class="hljs-params">number</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span>(number<=<span class="hljs-number">2</span>){<br> <span class="hljs-keyword">return</span> number<br> }<br> <span class="hljs-keyword">return</span> jumpFloor(number-<span class="hljs-number">1</span>) + jumpFloor(number-<span class="hljs-number">2</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="设计LRU缓存结构"><a href="#设计LRU缓存结构" class="headerlink" title="设计LRU缓存结构"></a><strong>设计LRU缓存结构</strong></h3><p>设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 k ,并有如下两个功能</p><ol><li><p>set(key, value):将记录(key, value)插入该结构</p></li><li><p>get(key):返回key对应的value值</p></li></ol><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LRU</span>(<span class="hljs-params"> operators , k </span>) </span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">const</span> result = []<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>, n=operators.length; i<n; i++) {<br> <span class="hljs-keyword">const</span> item = operators[i]<br> <span class="hljs-comment">// set</span><br> <span class="hljs-keyword">if</span>(item[<span class="hljs-number">0</span>] === <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">if</span>(cache.size<k) {<br> <span class="hljs-comment">// map 结构里有这个值,删除,添加新值到最后</span><br> <span class="hljs-keyword">if</span>(cache.has(item[<span class="hljs-number">1</span>])) {<br> cache.delete(item[<span class="hljs-number">1</span>])<br> cache.set(item[<span class="hljs-number">1</span>], item[<span class="hljs-number">2</span>])<br> }<span class="hljs-keyword">else</span> {<br> cache.set(item[<span class="hljs-number">1</span>], item[<span class="hljs-number">2</span>])<br> }<br> }<span class="hljs-keyword">else</span>{<br> <span class="hljs-keyword">if</span>(cache.has(item[<span class="hljs-number">1</span>])) {<br> cache.delete(item[<span class="hljs-number">1</span>])<br> cache.set(item[<span class="hljs-number">1</span>], item[<span class="hljs-number">2</span>])<br> }<span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">// 删除第一个数,然后添加到末尾</span><br> <span class="hljs-keyword">const</span> firstKey = cache.entries().next().value[<span class="hljs-number">0</span>]<br> cache.delete(firstKey)<br> cache.set(item[<span class="hljs-number">1</span>], item[<span class="hljs-number">2</span>])<br> }<br> }<br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(item[<span class="hljs-number">0</span>] === <span class="hljs-number">2</span>) {<br> <span class="hljs-keyword">if</span>(cache.has(item[<span class="hljs-number">1</span>])) {<br> <span class="hljs-keyword">const</span> value = cache.get(item[<span class="hljs-number">1</span>])<br> result.push(value)<br> <span class="hljs-comment">// 把值放到最后</span><br> cache.delete(item[<span class="hljs-number">1</span>])<br> cache.set(item[<span class="hljs-number">1</span>], value)<br> }<span class="hljs-keyword">else</span> {<br> result.push(-<span class="hljs-number">1</span>)<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> result<br>}<br></code></pre></td></tr></table></figure><h3 id="二分查找-II"><a href="#二分查找-II" class="headerlink" title="二分查找-II"></a><strong>二分查找-II</strong></h3><p>请实现有重复数字的升序数组的二分查找</p><p>给定一个 元素有序的(升序)长度为n的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params"> nums , target </span>) </span>{<br> <span class="hljs-keyword">if</span>(nums.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">let</span> left=<span class="hljs-number">0</span>, right=nums.length -<span class="hljs-number">1</span>;<br> <span class="hljs-keyword">let</span> mid;<br> <span class="hljs-keyword">let</span> res = -<span class="hljs-number">1</span>;<br> <span class="hljs-keyword">while</span>(left<=right) {<br> mid = <span class="hljs-built_in">Math</span>.floor((right+left)/<span class="hljs-number">2</span>);<br> <span class="hljs-keyword">if</span>(nums[mid] === target) {<br> right = mid - <span class="hljs-number">1</span><br> res = mid<br> }<br> <span class="hljs-keyword">if</span>(nums[mid] < target) {<br> left = mid + <span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">if</span>(nums[mid] > target) {<br> right = mid - <span class="hljs-number">1</span><br> }<br> }<br> <span class="hljs-keyword">return</span> res;<br>}<br></code></pre></td></tr></table></figure><h3 id="二进制中1的个数"><a href="#二进制中1的个数" class="headerlink" title="二进制中1的个数"></a><strong>二进制中1的个数</strong></h3><p>输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">NumberOf1</span>(<span class="hljs-params">n</span>) </span>{<br> <span class="hljs-keyword">if</span> (n === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<br> <span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span><br> <span class="hljs-keyword">while</span> (n != <span class="hljs-number">0</span>) {<br> n = n & (n - <span class="hljs-number">1</span>);<br> count++;<br> }<br> <span class="hljs-keyword">return</span> count<br>}<br></code></pre></td></tr></table></figure><h3 id="数据流中的中位数"><a href="#数据流中的中位数" class="headerlink" title="数据流中的中位数"></a><strong>数据流中的中位数</strong></h3><p>如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">let</span> nums = []<br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Insert</span>(<span class="hljs-params">num</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">if</span>(nums.length === <span class="hljs-number">0</span>) {<br> nums.push(num)<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">let</span> len = nums.length<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<len; i++) {<br> <span class="hljs-keyword">if</span>(nums[i]>num) {<br> nums.splice(i, <span class="hljs-number">0</span>, num)<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">if</span>(i === len-<span class="hljs-number">1</span>) {<br> nums.push(num)<br> }<br> }<br> <br>}<br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetMedian</span>(<span class="hljs-params"></span>)</span>{<br><span class="hljs-comment">// write code here</span><br> <span class="hljs-keyword">let</span> len = nums.length<br> <span class="hljs-keyword">if</span>((len & <span class="hljs-number">1</span>) === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">let</span> mid = <span class="hljs-built_in">Math</span>.floor(len/<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">return</span> (nums[mid-<span class="hljs-number">1</span>] + nums[mid])/<span class="hljs-number">2</span><br> }<span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">return</span> nums[<span class="hljs-built_in">Math</span>.floor(len/<span class="hljs-number">2</span>)]<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="孩子们的游戏-圆圈中最后剩下的数"><a href="#孩子们的游戏-圆圈中最后剩下的数" class="headerlink" title="孩子们的游戏(圆圈中最后剩下的数)"></a><strong>孩子们的游戏(圆圈中最后剩下的数)</strong></h3><p>每年六一儿童节,牛客都会准备一些小礼物和小游戏去看望孤儿院的孩子们。其中,有个游戏是这样的:首先,让 n 个小朋友们围成一个大圈,小朋友们的编号是0~n-1。然后,随机指定一个数 m ,让编号为0的小朋友开始报数。每次喊到 m-1 的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0… m-1报数….这样下去….直到剩下最后一个小朋友,可以不用表演,并且拿到牛客礼品,请你试着想下,哪个小朋友会得到这份礼品呢?</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LastRemaining_Solution</span>(<span class="hljs-params">n, m</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span> (n <= <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;<br> <span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i=<span class="hljs-number">2</span>; i<=n; ++i) {<br> index = (index + m) % i;<br> }<br> <span class="hljs-keyword">return</span> index;<br>}<br></code></pre></td></tr></table></figure><h3 id="求1-2-3-…-n"><a href="#求1-2-3-…-n" class="headerlink" title="求1+2+3+…+n"></a><strong>求1+2+3+…+n</strong></h3><p>求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Sum_Solution</span>(<span class="hljs-params">n</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">let</span> ans = n<br> ans && (ans += Sum_Solution(n-<span class="hljs-number">1</span>))<br> <span class="hljs-keyword">return</span> ans<br>}<br></code></pre></td></tr></table></figure><h3 id="不用加减乘除做加法"><a href="#不用加减乘除做加法" class="headerlink" title="不用加减乘除做加法"></a><strong>不用加减乘除做加法</strong></h3><p>写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Add</span>(<span class="hljs-params">num1, num2</span>) </span>{<br> <span class="hljs-keyword">while</span> (num2 != <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">let</span> temp = (num1 & num2) << <span class="hljs-number">1</span>;<br> num1 = num1 ^ num2;<br> num2 = temp;<br> }<br> <span class="hljs-keyword">return</span> num1;<br>}<br></code></pre></td></tr></table></figure><h3 id="和为S的连续正数序列"><a href="#和为S的连续正数序列" class="headerlink" title="和为S的连续正数序列"></a><strong>和为S的连续正数序列</strong></h3><p>小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FindContinuousSequence</span>(<span class="hljs-params">sum</span>) </span>{<br> <span class="hljs-keyword">let</span> tempSum, result = [];<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i < sum; i++) {<br> tempSum = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">let</span> tempArr = []<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = i; j < sum; j++) {<br> tempSum += j;<br> <span class="hljs-keyword">if</span> (tempSum < sum) {<br> tempArr.push(j);<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (tempSum === sum) {<br> tempArr.push(j);<br> result.push(tempArr)<br> <span class="hljs-keyword">break</span>;<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">break</span>;<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> result;<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">FindContinuousSequence</span> : FindContinuousSequence<br>};<br></code></pre></td></tr></table></figure><h3 id="跳台阶扩展问题"><a href="#跳台阶扩展问题" class="headerlink" title="跳台阶扩展问题"></a><strong>跳台阶扩展问题</strong></h3><p>一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶(n为正整数)总共有多少种跳法。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">jumpFloorII</span>(<span class="hljs-params">number</span>) </span>{<br><br> <span class="hljs-keyword">if</span> (number <= <span class="hljs-number">1</span>) {<br><br> <span class="hljs-keyword">return</span> number;<br><br> } <span class="hljs-keyword">else</span> {<br><br> <span class="hljs-keyword">return</span> <span class="hljs-number">2</span> * jumpFloorII(number - <span class="hljs-number">1</span>)<br><br> }<br><br>}<br></code></pre></td></tr></table></figure><h3 id="整数中1出现的次数(从1到n整数中1出现的次数)"><a href="#整数中1出现的次数(从1到n整数中1出现的次数)" class="headerlink" title="整数中1出现的次数(从1到n整数中1出现的次数)"></a><strong>整数中1出现的次数(从1到n整数中1出现的次数)</strong></h3><p>输入一个整数 n ,求 1~n 这 n 个整数的十进制表示中 1 出现的次数<br>例如, 1~13 中包含 1 的数字有 1 、 10 、 11 、 12 、 13 因此共出现 6 次</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">NumberOf1Between1AndN_Solution</span>(<span class="hljs-params">n</span>) </span>{<br> <span class="hljs-keyword">if</span> (n < <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span>;<br> }<br> <span class="hljs-keyword">let</span> sum = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i <= n; i++) {<br> <span class="hljs-keyword">let</span> nStr = i.toString(),<br> len = nStr.length;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = <span class="hljs-number">0</span>; j < len; j++) {<br> <span class="hljs-keyword">let</span> index = nStr.indexOf(<span class="hljs-string">'1'</span>);<br> <span class="hljs-keyword">if</span> (index > -<span class="hljs-number">1</span>) {<br> sum++;<br> nStr = nStr.slice(index + <span class="hljs-number">1</span>, nStr.length);<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> sum;<br>}<br></code></pre></td></tr></table></figure><h3 id="数值的整数次方"><a href="#数值的整数次方" class="headerlink" title="数值的整数次方"></a><strong>数值的整数次方</strong></h3><p>实现函数 double Power(double base, int exponent),求base的exponent次方。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Power</span>(<span class="hljs-params">base, exponent</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.pow(base, exponent)<br>}<br></code></pre></td></tr></table></figure><h3 id="矩形覆盖"><a href="#矩形覆盖" class="headerlink" title="矩形覆盖"></a><strong>矩形覆盖</strong></h3><p>我们可以用 2<em>1 的小矩形横着或者竖着去覆盖更大的矩形。请问用 n 个 2</em>1 的小矩形无重叠地覆盖一个 2*n 的大矩形,从同一个方向看总共有多少种不同的方法?</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rectCover</span>(<span class="hljs-params">number</span>) </span>{<br> <span class="hljs-keyword">if</span> (number <= <span class="hljs-number">2</span>) {<br> <span class="hljs-keyword">return</span> number<br> }<br> <span class="hljs-keyword">let</span> n1 = <span class="hljs-number">1</span>,<br> n2 = <span class="hljs-number">2</span>,<br> sum = <span class="hljs-number">3</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < number - <span class="hljs-number">2</span>; i++) {<br> sum = n1 + n2<br> n1 = n2<br> n2 = sum<br> }<br> <span class="hljs-keyword">return</span> sum<br>}<br></code></pre></td></tr></table></figure><h3 id="和为S的两个数字"><a href="#和为S的两个数字" class="headerlink" title="和为S的两个数字"></a><strong>和为S的两个数字</strong></h3><p>输入一个递增排序的数组array和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,返回任意一组即可,如果无法找出这样的数字,返回一个空数组即可。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FindNumbersWithSum</span>(<span class="hljs-params">array, sum</span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">let</span> len = array.length<br> <span class="hljs-keyword">let</span> result = []<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>; i<len; i++) {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=<span class="hljs-number">0</span>; j<len; j++) {<br> <span class="hljs-keyword">if</span>(array[i] + array[j] === sum) {<br> result.push([array[i], array[j]])<br> }<br> }<br> }<br> <span class="hljs-keyword">if</span>(result.length < <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(result.length === <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> result<br> }<span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">const</span> temp = result[<span class="hljs-number">0</span>]<br> <span class="hljs-keyword">const</span> tempVal = temp[<span class="hljs-number">0</span>] * temp[<span class="hljs-number">1</span>]<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> k=<span class="hljs-number">1</span>,n=result.length; k<n; k++){<br> <span class="hljs-keyword">if</span>(result[k][<span class="hljs-number">0</span>] * result[k][<span class="hljs-number">1</span>] < tempVal) {<br> tempVal = result[k][<span class="hljs-number">0</span>] * result[k][<span class="hljs-number">1</span>]<br> temp = result[k]<br> }<br> }<br> <span class="hljs-keyword">return</span> temp<br> }<br> <br>}<br></code></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>面试题汇总</title>
<link href="/2022/02/16/face-subjects/"/>
<url>/2022/02/16/face-subjects/</url>
<content type="html"><![CDATA[<h2 id="项目相关"><a href="#项目相关" class="headerlink" title="项目相关"></a>项目相关</h2><h3 id="什么是快应用"><a href="#什么是快应用" class="headerlink" title="什么是快应用"></a>什么是快应用</h3><p>快应用是一种新的应用形态,快应用就是希望能够让用户无需下载安装,并且还能流畅的体验应用内容。</p><p>开发者主要利用前端知识与技能,以及对应的 IDE,手机设备就可以做原型的开发。快应用使用前端技术栈开发,原生渲染,同时具备 H5 与原生应用的双重优点。</p><h2 id="网络知识"><a href="#网络知识" class="headerlink" title="网络知识"></a>网络知识</h2><h3 id="https"><a href="#https" class="headerlink" title="https"></a>https</h3><ol><li>客户端使用 https url 访问服务器,要求 web 服务器建立 ssl 链接</li><li>服务端接收到请求之后,将网络的证书返回给客户端</li><li>协商加密等级</li><li>建立会话密钥</li><li>服务端用私钥解密</li><li>两者通过密钥加密通信</li></ol><h3 id="http1-1"><a href="#http1-1" class="headerlink" title="http1.1"></a>http1.1</h3><ol><li><strong>缓存处理</strong>:引入了更多的缓存控制策略</li><li><strong>带宽优化及网络连接的使用</strong></li><li><strong>错误通知的管理</strong></li><li><strong>host 头处理</strong></li><li><strong>长链接</strong></li></ol><h3 id="http2"><a href="#http2" class="headerlink" title="http2"></a>http2</h3><ol><li><p><strong>多路复用</strong>:所有请求都是通过一个 TCP 连接并发完成。</p><ul><li>同域名下所有通信都在单个连接上完成</li><li>单个连接可以承载任意数量的双向数据流</li><li>数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送</li></ul></li><li><p><strong>头部压缩</strong>:对消息头采用 HPACK 进行压缩传输,能够节省消息头占用的网络流量</p><ul><li>在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送</li><li>首部表在 htpp2 的链接存续期内始终存在,由客户端和服务器共同渐进地更新</li><li>每个新的首部键值对要么被追加到当前标的末尾,要么替换表中之前的值</li></ul></li><li><p><strong>服务端推送</strong>:服务端可以在发送页面 html 时主动推送其他资源,而不用等到浏览器解析到相应位置,发起请求再响应。</p></li><li><p><strong>二进制分帧</strong>:http2 采用二进制格式传输数据,解析起来更高效。</p></li></ol><h3 id="http-缓存"><a href="#http-缓存" class="headerlink" title="http 缓存"></a>http 缓存</h3><p><strong>强制缓存</strong></p><p>服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。</p><p><strong>Expires</strong>: Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。</p><p><strong>Cache-Control</strong> 是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。<br>private: 客户端可以缓存<br>public: 客户端和代理服务器都可缓存(前端的同学,可以认为public和private是一样的)<br>max-age=xxx: 缓存的内容将在 xxx 秒后失效<br>no-cache: 需要使用对比缓存来验证缓存数据<br>no-store: 所有内容都不会缓存,强制缓存,对比缓存都不会触发(对于前端开发来说,缓存越多越好,so…基本上和它说886)</p><p><strong>协商缓存</strong></p><p><strong>Last-Modified</strong>: 服务器在响应请求时,告诉浏览器资源的最后修改时间。</p><p><strong>If-Modified-Since</strong>: 再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。</p><p><strong>Etag</strong>: 服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。</p><p><strong>If-None-Match</strong>: 再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。</p><p>将缓存信息中的 Etag 和 Last-Modified 通过请求发送给服务器,由服务器校验,返回 304 状态码时,浏览器直接使用缓存。</p><p><img src="https://images2015.cnblogs.com/blog/632130/201702/632130-20170210141453338-1263276228.png" alt="缓存"></p><h3 id="TCP和UDP的区别"><a href="#TCP和UDP的区别" class="headerlink" title="TCP和UDP的区别"></a>TCP和UDP的区别</h3><p>TCP:连接,需要通过三次握手,可靠,流模式</p><p>UDP:无连接,不可靠,数据报模式</p><h3 id="TCP-三次握手"><a href="#TCP-三次握手" class="headerlink" title="TCP 三次握手"></a>TCP 三次握手</h3><ol><li>主机 A通过向主机 B发送一个含有同步序列号的标志位的数据给主机 B,向主机 B请求建立连接</li><li>主机 B 收到主机 A 的请求后,用一个带有确认应答(ACK)和同步序列好(SYN)标志位的数据段响应主机 A</li><li>主机 A 收到这个数据段后,再发送一个确认应答,确认已经收到主机 B 的数据段</li></ol><h3 id="TCP-断开连接-4-次握手"><a href="#TCP-断开连接-4-次握手" class="headerlink" title="TCP 断开连接 4 次握手"></a>TCP 断开连接 4 次握手</h3><ol><li>当主机 A 完成数据传输后,将控制位FIN 置1,提出停止 TCP连接的请求</li><li>当主机 B收到 FIN后对其作出响应,确认这一方向的TCP 连接将关闭,将 ACK 置 1</li><li>有 B 端再提出反向的关闭请求,将 FIN 置 1</li><li>主机 A对主机 B的请求进行确认,将 ACK 置 1.双方向的关闭结束</li></ol><h3 id="TCP-IP-四层网络模型"><a href="#TCP-IP-四层网络模型" class="headerlink" title="TCP/IP 四层网络模型"></a>TCP/IP 四层网络模型</h3><p><img src="https://www.zutuanxue.com:8000/static/media/images/2020/9/25/1601024106315.png" alt="tcp/ip"></p><p>网络访问层:主要是管理物理网络准备所需要的数据</p><p>网际层:主要是解决数据由一个计算机的IP如何路由到目标计算机的过程规范,MAC 地址、IP 地址、域名</p><p>传输层:提供应用程序接口,为网络应用程序提供网络访问的途径;提供从多个应用层接收消息的功能(多路复用),同时也提供可以把消息分发给应用程序的功能(多路分解);对数据进行错误检测、流量控制——TCP/UDP</p><p>应用层:为用户的应用提供服务并支持网络访问</p><h3 id="DNS-递归查找的弊端"><a href="#DNS-递归查找的弊端" class="headerlink" title="DNS 递归查找的弊端"></a>DNS 递归查找的弊端</h3><p>开放的DNS服务器上允许递归DNS查询会造成安全漏洞,因为此配置可使攻击者执行DNS放大攻击和DNS缓存中毒</p><h3 id="怎么判断是否返回给用户一个webp格式的资源"><a href="#怎么判断是否返回给用户一个webp格式的资源" class="headerlink" title="怎么判断是否返回给用户一个webp格式的资源"></a>怎么判断是否返回给用户一个webp格式的资源</h3><p>HTTP request header 中有个 accept 字段,为 image/webp 时,返回 webp 格式资源</p><h3 id="HTTP-head"><a href="#HTTP-head" class="headerlink" title="HTTP head"></a>HTTP head</h3><table><thead><tr><th align="left">request</th><th>response</th></tr></thead><tbody><tr><td align="left">Accept:能够接受的回应内容类型</td><td>Access-Control-Allow-Origin:指定哪些网站可参与到跨来源资源共享过程中</td></tr><tr><td align="left">Accept-Charset:能够接受的字符集</td><td>Age:这个对象在代理缓存中存在的时间,以秒为单位</td></tr><tr><td align="left">Accept-Encoding:能够接受的编码方式列表</td><td>Allow:对于特定资源有效的动作</td></tr><tr><td align="left">Accept-Language:能够接受的回应内容的自然语言列表</td><td>Content-Encoding:在数据上使用的编码类型</td></tr><tr><td align="left">Accept-Datetime:能够接受的按照时间来表示的版本</td><td>Content-Language:内容所使用的预览</td></tr><tr><td align="left">Authorization:用于超文本传输协议的认证的认证信息</td><td>Etag:对于某个资源的特定版本的一个标识符,通常是一个消息散列</td></tr><tr><td align="left">Cache-Control:用来指定在这次的请求/响应链中的所有缓存机制</td><td>Cache-Control:向从服务器直到客户端在内的所有缓存机制告知,它们是否可用缓存这个对象</td></tr><tr><td align="left">Connection:该浏览器想要优先使用的连接类型</td><td>Connection:针对改连接所预期的选项</td></tr><tr><td align="left">Cookie:之前由服务器通过 Set-Cookie 发送的一个超文本传输协议cookie</td><td>Expires:指定一个日期/时间,超过该时间则认为此回应已经过期</td></tr><tr><td align="left">Content-Length:以八位字节数组表示的请求体的长度</td><td>Content-Length:回应消息体的长度</td></tr><tr><td align="left">Content-Type:请求体的 MIME 类型</td><td>Content-Type:当前内容的 MIME 类型</td></tr><tr><td align="left">Date:发送该消息的日期和时间</td><td>Date:此条消息被发送时的日期和时间</td></tr><tr><td align="left">Expect:表明客户端要求服务器做出的特定行为</td><td>Last-Modified:所请求的对象的最后修改日期</td></tr><tr><td align="left">From:发起此请求的用户的邮件地址</td><td>Proxy-Authenticate:要求在访问代理时提供身份认证信息</td></tr><tr><td align="left">Host:服务器的域名</td><td>Set-Cookie:设置 cookie</td></tr><tr><td align="left">If-Match:</td><td>Server:服务器的名字</td></tr><tr><td align="left">If-Modified-Since:允许在对应的内容未被修改的情况下返回 304 未修改</td><td>Status:通用网关接口 协议头字段,用来说明当前这个超文本传输协议会有的状态</td></tr><tr><td align="left">If-None-Match:允许在对应的内容未被修改的情况下返回 304 未修改</td><td>X-Frame-Options:劫持保护</td></tr><tr><td align="left">Origin:发起一个针对跨来源资源共享的请求</td><td>Upgrade:要求客户端升级到另一个协议</td></tr><tr><td align="left">Referer:表示浏览器所访问的前一个页面,正是那个页面上的某个链接将浏览器带到了当前所请求的这个页面</td><td></td></tr><tr><td align="left">User-Agent:浏览器的浏览器身份标识字符串</td><td></td></tr></tbody></table><h3 id="content-type"><a href="#content-type" class="headerlink" title="content-type"></a>content-type</h3><p>application/json:用来告诉服务端消息主体是序列化后的 json 字符串</p><p>application/x-www-form-urlencoded:post 提交数据方式,url 对 key value 进行编码,然后用 & 连接</p><p>multipart/form-data:表单上传文件时</p><h3 id="web-push"><a href="#web-push" class="headerlink" title="web push"></a>web push</h3><p>web push 协议是发送推送消息到浏览器的协议标准。</p><figure class="highlight bash"><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><code class="hljs bash">+-------+ +--------------+ +-------------+<br>| UA | | Push Service | | Application |<br>+-------+ +--------------+ | Server |<br> | | +-------------+<br> | Subscribe | |<br> |--------------------->| |<br> | Monitor | |<br> |<====================>| |<br> | | |<br> | Distribute Push Resource |<br> |-------------------------------------------->|<br> | | |<br> : : :<br> | | Push Message |<br> | Push Message |<---------------------|<br> |<---------------------| |<br> | | |<br></code></pre></td></tr></table></figure><p>网络推送的建立涉及到三端的相互配合:</p><ol><li>UA(User Agent),浏览器</li><li>Push Service,推送服务器,用于管理推送订阅、消息推送等功能的第三方服务器。该服务器是浏览器决定的</li><li>Application Server,网站应用的后端服务</li></ol><p>订阅推送:</p><ol><li>Subscribe,浏览器需要向推送服务器发起推送订阅的请求</li><li>Monitor,订阅成功之后,浏览器与推送服务器之间会进行通信,同时推送服务器会生成并维护相关订阅信息,在后续的消息推送流程将基于该订阅信息与浏览器保持通信</li><li>Distribute Push Resource,浏览器将推送服务器返回的订阅信息发送给网站后端服务进行保存,服务端将基于改订阅信息像推送服务器发起消息推送</li></ol><p>推送部分主要分为两步:</p><ol><li>后端服务通过 web push 向推送服务器发送消息通知,发送时会将前面提到的订阅消息带上,以告知推送服务器这条消息推送的目的地</li><li>推送服务器接收到消息之后,再根据订阅信息将消息推送给对应的浏览器</li></ol><h2 id="Vue"><a href="#Vue" class="headerlink" title="Vue"></a>Vue</h2><h3 id="双向绑定原理"><a href="#双向绑定原理" class="headerlink" title="双向绑定原理"></a>双向绑定原理</h3><p>使用 defineProperty 改写 getter 和 setter 方法</p><ol><li>实现一个监听器 Observer,使用 Object.defineProperty 改写 getter 和 setter 方法,getter 时收集依赖,setter 时通知订阅者更新数据</li><li>实现一个解析器 Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器</li><li>实现一个订阅者 Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图,Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: ①在自身实例化时往属性订阅器(dep)里面添加自己 ②自身必须有一个update()方法 ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调</li></ol><h3 id="Vue-3-使用-proxy-的原因"><a href="#Vue-3-使用-proxy-的原因" class="headerlink" title="Vue 3 使用 proxy 的原因"></a>Vue 3 使用 proxy 的原因</h3><p>Object.defineProperty 缺陷:</p><ol><li>监控到数组下标的变化时,开销很大</li><li>Object.defineProperty 只能劫持对象的属性,而 Proxy 是直接代理对象。Object.defineProperty 需要遍历对象的每个属性,如果属性值也是对象,则需要深度遍历。而 Proxy 直接代理对象,不需要遍历操作</li><li>Object.defineProperty 对新增属性需要手动进行 Observe,vue2 时需要使用 vm.$set 才能保证新增的属性也是响应式</li><li>Proxy 支持 13种拦截操作</li><li>Proxy 作为新标准,长远来看,js 引擎会继续优化 proxy,但 getter 和 setter 基本不会再有针对性优化</li></ol><h3 id="Computed-和-watch-的区别"><a href="#Computed-和-watch-的区别" class="headerlink" title="Computed 和 watch 的区别"></a>Computed 和 watch 的区别</h3><ol><li>Computed 计算属性:依赖其它属性值,并且 computed 的值有缓存,只是他的依赖的属性值发生改变,下一次获取 computed 的值才会重新计算 computed 的值</li><li>watch 侦听器:更多的是观察的作用,无缓存性,类似某些数据的监听回调,每当监听的数据变化时,都会执行回调进行后续操作</li></ol><p>运用场景:</p><ol><li>当我们需要进行数值计算,并且依赖于其他数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都需要重新计算</li><li>当我们需要再数据变化时执行异步或者开销比较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作,限制我们执行操作的频率,并在我们得到最终结果钱,设置中间状态</li><li>多个因素影响一个显示,用 computed,一个因素的变化影响多个其他因素显示,用 watch。</li></ol><h3 id="为什么需要-Virtual-Dom"><a href="#为什么需要-Virtual-Dom" class="headerlink" title="为什么需要 Virtual Dom"></a>为什么需要 Virtual Dom</h3><ol><li>具备跨平台的优势</li><li>操作 dom 慢,js 运行效率高,我们可以将 dom 对比操作放在 js 层,提高效率</li><li>提升渲染性能</li></ol><h3 id="过滤器filter"><a href="#过滤器filter" class="headerlink" title="过滤器filter"></a>过滤器filter</h3><p>在 vue 中使用 filter 来过滤数据,filters 不会修改数据,而是过滤数据,改变用户看到的输出。使用场景:比如需要处理时间、数字的显示格式</p><h3 id="常见的事件修饰符及其作用"><a href="#常见的事件修饰符及其作用" class="headerlink" title="常见的事件修饰符及其作用"></a>常见的事件修饰符及其作用</h3><ol><li>.stop: 等用于 js 中的 event.stopPropagation(), 防止事件冒泡</li><li>.prevebt: 等同于 js 中的 event.preventDefault,防止执行预设的行为</li><li>.capture:当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。如 div1 中嵌套 div2 中嵌套 div3.capture 中嵌套 div4,那么执行顺序为: div3 => div4 => div2 => div1</li><li>.self:只会触发自己范围内的事件,不包含子元素</li><li>.once:只会触发一次</li></ol><h3 id="V-model-是如何实现的,语法糖实际是什么"><a href="#V-model-是如何实现的,语法糖实际是什么" class="headerlink" title="V-model 是如何实现的,语法糖实际是什么"></a>V-model 是如何实现的,语法糖实际是什么</h3><ol><li>作用在表单元素上 <code>v-model="message" </code>等同于<code> v-bind:value="message" v-on:input="message=$event.target.value"</code></li><li>作用在组件上,本质是一个父子组件通信的语法糖,通过 prop 和$emit 实现,等同于<code>:value="message" @input="$emit('input', $event.target.value)"</code></li></ol><h3 id="data-为什么必须是函数"><a href="#data-为什么必须是函数" class="headerlink" title="data 为什么必须是函数"></a>data 为什么必须是函数</h3><p>因为组件是可以复用的,js 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染。</p><h3 id="vue-data-中某个属性的值发生改变后,视图会立即同步执行重新渲染吗"><a href="#vue-data-中某个属性的值发生改变后,视图会立即同步执行重新渲染吗" class="headerlink" title="vue data 中某个属性的值发生改变后,视图会立即同步执行重新渲染吗"></a>vue data 中某个属性的值发生改变后,视图会立即同步执行重新渲染吗</h3><p>不会。</p><p>vue 实现响应式并不是数据发生变化之后 dom 立即变化,而是按一定的策略进行 dom 的更新。</p><p>vue 在更新 dom 时是异步执行的,只要侦听到数据变化,vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更</p><p>如果同一个 watcher 被多次触发,只会被推入队列一次,这种缓冲时去除重复数据对于避免不必要的计算和 dom 操作是非常重要的</p><p>然后,在下一个事件循环的 tick 中,vue 刷新队列并执行实际(已去重的)工作。</p><h3 id="数据层级结构太深问题"><a href="#数据层级结构太深问题" class="headerlink" title="数据层级结构太深问题"></a>数据层级结构太深问题</h3><p>使用 vm.$set手动定义一层数据</p><h3 id="v-if和v-for一起使用的弊端及解决办法"><a href="#v-if和v-for一起使用的弊端及解决办法" class="headerlink" title="v-if和v-for一起使用的弊端及解决办法"></a>v-if和v-for一起使用的弊端及解决办法</h3><p>由于v-for的优先级比v-if高,所以导致每循环一次就会去v-if一次,而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,造成页面卡顿,性能下降。</p><p>解决办法:</p><ol><li>在v-for的外层或内层包裹一个元素来使用v-if</li><li>用computed处理</li></ol><h3 id="vue常用指令"><a href="#vue常用指令" class="headerlink" title="vue常用指令"></a>vue常用指令</h3><ol><li>v-model 多用于表单元素实现双向数据绑定(同angular中的ng-model)</li><li>v-bind 动态绑定 作用: 及时对页面的数据进行更改</li><li>v-on:click 给标签绑定函数,可以缩写为@,例如绑定一个点击函数 函数必须写在methods里面</li><li>v-for 格式: v-for=”字段名 in(of) 数组json” 循环数组或json(同angular中的ng-repeat)</li><li>v-show 显示内容 (同angular中的ng-show)</li><li>v-hide 隐藏内容(同angular中的ng-hide)</li><li>v-if 显示与隐藏 (dom元素的删除添加 同angular中的ng-if 默认值为false)</li><li>v-else-if 必须和v-if连用</li><li>v-else 必须和v-if连用 不能单独使用 否则报错 模板编译错误</li><li>v-text 解析文本</li><li>v-html 解析html标签</li><li>v-bind:class 三种绑定方法 1、对象型 ‘{red:isred}’ 2、三元型 ‘isred?”red”:”blue”‘ 3、数组型 ‘[{red:”isred”},{blue:”isblue”}]’</li><li>v-once 进入页面时 只渲染一次 不在进行渲染</li><li>v-cloak 防止闪烁</li><li>v-pre 把标签内部的元素原位输出</li></ol><h3 id="Keep-alive"><a href="#Keep-alive" class="headerlink" title="Keep-alive"></a>Keep-alive</h3><p>如果需要在组件切换时,保存一些组件的状态防止多次渲染,就可以使用 keep-alive 组件包裹需要保存的组件</p><p>两个重要属性,include 缓存组件名称,exclude 不需要缓存的组件名称</p><h3 id="父子组件的生命周期顺序"><a href="#父子组件的生命周期顺序" class="headerlink" title="父子组件的生命周期顺序"></a>父子组件的生命周期顺序</h3><ol><li>加载渲染过程:<br>父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted</li><li>子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated</li><li>父组件更新过程:父beforeUpdate->父updated</li><li>销毁过程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed</li></ol><h3 id="vue-router有哪几种导航钩子?"><a href="#vue-router有哪几种导航钩子?" class="headerlink" title="vue-router有哪几种导航钩子?"></a>vue-router有哪几种导航钩子?</h3><ol><li>全局导航钩子:router.beforeEach(to,from,next)</li><li>组件内的钩子beforeRouteEnter (to, from, next) beforeRouteUpdate (to, from, next) beforeRouteLeave (to, from, next)</li><li>单独路由独享组件 beforeEnter: (to, from, next)</li></ol><h3 id="route和-router的区别"><a href="#route和-router的区别" class="headerlink" title="$route和$router的区别"></a>$route和$router的区别</h3><ol><li>$route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。</li><li>$router是“路由实例”对象包括了路由的跳转方法,钩子函数等</li></ol><h3 id="Vue-数组改变原理"><a href="#Vue-数组改变原理" class="headerlink" title="Vue 数组改变原理"></a>Vue 数组改变原理</h3><p>在数组和 Array.property 上的原型链上插入一个自定义的对象,拦截原来的 push 等方法,在自定义对象中的同名方法中先执行原本的方法,再去人为的调用 <strong>ob</strong>.dep.notify() 去执行之前收集的回调。</p><h3 id="computed-和-watch-区别"><a href="#computed-和-watch-区别" class="headerlink" title="computed 和 watch 区别"></a>computed 和 watch 区别</h3><ol><li><p>computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。</p></li><li><p>watch 侦听器 : 更多的是<strong>观察</strong>的作用,<strong>无缓存性</strong>,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。</p></li></ol><h3 id="Vue3-性能提升主要是通过哪几方面体现"><a href="#Vue3-性能提升主要是通过哪几方面体现" class="headerlink" title="Vue3 性能提升主要是通过哪几方面体现"></a>Vue3 性能提升主要是通过哪几方面体现</h3><ol><li>响应式系统提升:proxy 的性能本来就比 defineProperty 好,proxy 可以拦截属性的访问、赋值、删除等操作,不需要初始化的时候遍历所有属性,另外有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性。</li></ol><p>优势:</p><ul><li>可以监听动态新增的属性</li><li>可以监听删除的属性</li><li>可以监听数组的索引和 length 属性</li></ul><ol start="2"><li>编译优化</li></ol><p> 优化编译和重写虚拟 dom,让首次渲染和更新 dom 性能有更大的提升。vue2 通过标记静态根节点,优化 diff 算法,vue3标记和提升所有静态根节点,diff 的时候只比较动态节点内容 fragments,模板里面不用创建唯一根节点,可以直接放同级标签和文本内容</p><ol start="3"><li>源码体积的优化</li></ol><p> vue3 移除了一些不常用的 api,例如:inline-template、filter 等 使用 tree-shaking</p><h3 id="composition-Api-与-vue2-使用的-options-api-有什么区别"><a href="#composition-Api-与-vue2-使用的-options-api-有什么区别" class="headerlink" title="composition Api 与 vue2 使用的 options api 有什么区别"></a>composition Api 与 vue2 使用的 options api 有什么区别</h3><p>options api:</p><p>包含一个描述组件选项(data、methods、props等)的对象 options;api 开发复杂组件,同一个功能逻辑的代码被拆分到不同的选项;使用 mixin 重用公用代码,也有问题;命名冲突,数据来源不清晰</p><p>composition api:</p><p>vue3 新增的一组 api,他是基于函数的 api,可以更灵活的组织组件的逻辑。解决 options api 在大型项目中,options api 不好拆分和重用的问题</p><h3 id="proxy-相对于-Object-defineProperty"><a href="#proxy-相对于-Object-defineProperty" class="headerlink" title="proxy 相对于 Object.defineProperty"></a>proxy 相对于 Object.defineProperty</h3><ul><li>可以监听数组的变化</li><li>可以劫持整个对象</li><li>操作时不是对原对象的操作,是 new Proxy 返回的一个新对象</li><li>可以劫持的操作有 13 种</li></ul><h3 id="Vue3-在编译方面有哪些优化"><a href="#Vue3-在编译方面有哪些优化" class="headerlink" title="Vue3 在编译方面有哪些优化"></a>Vue3 在编译方面有哪些优化</h3><p>vue3 中标记和提升所有的静态节点,diff 的时候只需要对比动态节点内容</p><p>fragments:</p><p>template 中不需要唯一根节点,可以直接放文本或者同级标签静态提升,当使用静态提升时,所有的静态节点都被提升到 render 方法之外,只会在应用启动的时候被创建一次,之后使用只需要应用提取的静态节点,随着每次的渲染被不停地复用。patch flag,在动态标签末尾加上相应的标记,只能带 patch flpg 的节点才被认为是动态的元素,会被追踪属性的修改,能快速的找到动态节点,而不用逐个逐层遍历,提高了虚拟 dom diff 的性能。缓存事件处理函数 cacheHandler,避免每次触发都要重新生成全新的 function 区更新之前的函数 。tree shaking优化核心库体积,减少不必要的代码量</p><p>vue3 响应式系统的实现原理</p><ol><li><strong>reactive</strong></li></ol><p> 设置对象为响应式对象。接收一个参数,判断这参数是否是对象。不是对象则直接返回这个参数,不做响应式处理。创建拦截器 handerler,设置 get。sey、deleteProperty</p><ol start="2"><li><p><strong>get</strong></p><ul><li>收集依赖</li><li>如果当前 key 的值是对象,则为当前 key 的对象创建拦截器 handler,设置 get、set、deleteProperty</li><li>如果当前 key 的值不是对象,则返回当前 key 的值</li></ul></li><li><p><strong>set</strong></p><p>设置的新值和老值不相等时,更新为新值,并触发更新(trigger)。deleteProperty 当前对象有这个 key 的时候,删除这个 key 并触发更新(trigger)</p></li><li><p><strong>effect</strong></p></li></ol><p> 接收一个函数作为参数。作用是:访问响应式对象属性时去收集依赖</p><ol start="4"><li><strong>track</strong></li></ol><p> 接收两个参数:target 和 key</p><p> 如果没有 activeEffect,则说明没有创建 effect 依赖—如果有 activeEffect,则去判断 weakMap 集合中是否有 target 属性,weakMap 集合中没有 target 属性,则 <code>set(target, (depsMap = new Map()))</code>,weakMap 集合中有 target 属性,则判断 target 属性的 map 值的 depsMap 中是否有 key 属性—depsMap 中没有 key 属性,则 <code>set(key, (dep = new Set()))</code>—depsMap 中有key 属性,则添加这个 activeEffect</p><ol start="5"><li>trigger</li></ol><p> 判断 weakMap 中是否有 target 属性,weakMap 中有 target 属性,则判断 target 属性的 map 值中是否有 key 属性,有的话触发手机的 effect()</p><h3 id="虚拟-Dom"><a href="#虚拟-Dom" class="headerlink" title="虚拟 Dom"></a>虚拟 Dom</h3><ol><li>用 js 对象模拟 dom 树,得到一棵虚拟 dom 树。</li><li>当页面数据变更时,生成新的 Dom 树,比较新旧两棵虚拟 Dom 树的差异。</li><li>把差异应用到真正的 Dom 树上。</li></ol><h3 id="react-diff-和-vue-diff-的差别"><a href="#react-diff-和-vue-diff-的差别" class="headerlink" title="react diff 和 vue diff 的差别"></a>react diff 和 vue diff 的差别</h3><p>相同点:都是忽略跨级比较,只做同级比较。<br>不同点:</p><ol><li>vue 比对节点,当节点元素类型相同,但是 className 不同,认为是不同类型元素,删除重建,而 react 会认为是同类型节点,只是修改节点属性。</li><li>vue 的列表比对,采用从两端到中间的比对方式,而 react 而采用从左到右依次比对的方式。当一个集合,只是把最后一个节点移动到了第一个,react 会把前面的节点依次移动,而 vue 只会把最后一个节点移动到第一个。<br>总体上而言,vue 的形式会更高效。</li></ol><h3 id="React-和-vue-的区别"><a href="#React-和-vue-的区别" class="headerlink" title="React 和 vue 的区别"></a>React 和 vue 的区别</h3><ol><li>监听数据变化的实现原理不同</li><li>数据绑定:vue 双向绑定、react 单项数据流</li><li>组件通信不同</li><li>框架本质不同:vue 是 MVVM,react 是前端组件化框架</li></ol><h3 id="key-的作用"><a href="#key-的作用" class="headerlink" title="key 的作用"></a>key 的作用</h3><p>key 的作用就是高效的更新虚拟 Dom</p><h3 id="vm-set-的实现原理"><a href="#vm-set-的实现原理" class="headerlink" title="vm.$set 的实现原理"></a>vm.<code>$set</code> 的实现原理</h3><ol><li><p>如果目标是数组,直接使用数组的 splice 方法触发相应式;</p></li><li><p>如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用 defineReactive 方法进行响应式处理( defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 的功能所调用的方法)</p></li></ol><h3 id="什么是-mixin"><a href="#什么是-mixin" class="headerlink" title="什么是 mixin"></a>什么是 mixin</h3><ol><li><p>Mixin 使我们能够为 Vue 组件编写可插拔和可重用的功能。</p></li><li><p>如果希望在多个组件之间重用一组组件选项,例如生命周期 hook、 方法等,则可以将其编写为 mixin,并在组件中简单的引用它。</p></li><li><p>然后将 mixin 的内容合并到组件中。如果你要在 mixin 中定义生命周期 hook,那么它在执行时将优化于组件自已的 hook。</p></li></ol><h3 id="Vue的性能优化"><a href="#Vue的性能优化" class="headerlink" title="Vue的性能优化"></a>Vue的性能优化</h3><ol><li><p><strong>编码阶段</strong></p><ul><li><p>尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher</p></li><li><p>v-if和v-for不能连用</p></li><li><p>如果需要使用v-for给每项元素绑定事件时使用事件代理</p></li><li><p>SPA 页面采用keep-alive缓存组件</p></li><li><p>在更多的情况下,使用v-if替代v-show</p></li><li><p>key保证唯一</p></li><li><p>使用路由懒加载、异步组件</p></li><li><p>防抖、节流</p></li><li><p>第三方模块按需导入</p></li><li><p>长列表滚动到可视区域动态加载</p></li><li><p>图片懒加载</p></li></ul></li></ol><p> </p><ol start="2"><li><p><strong>SEO优化</strong></p><ul><li>预渲染</li><li>服务端渲染SSR</li></ul></li><li><p><strong>打包优化</strong></p><ul><li>压缩代码</li><li>Tree Shaking/Scope Hoisting</li><li>使用cdn加载第三方模块</li><li>多线程打包happypack</li><li>splitChunks抽离公共文件</li><li>sourceMap优化</li></ul></li><li><p><strong>用户体验</strong></p><ul><li>骨架屏</li><li>PWA</li><li>还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等</li></ul></li></ol><h3 id="Vue的生命周期"><a href="#Vue的生命周期" class="headerlink" title="Vue的生命周期"></a>Vue的生命周期</h3><p>Vue 实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载 等⼀系列过程,称这是Vue的⽣命周期。</p><ol><li><p><strong>beforeCreate(创建前)</strong>:数据观测和初始化事件还未开始,此时 data 的响应式追踪、event/watcher 都还没有被设置,也就是说不能访问到data、computed、watch、methods上的方法和数据。</p></li><li><p><strong>created(创建后)</strong> :实例创建完成,实例上配置的 options 包括 data、computed、watch、methods 等都配置完成,但是此时渲染得节点还未挂载到 DOM,所以不能访问到 <code>$el</code> 属性。</p></li><li><p><strong>beforeMount(挂载前)</strong>:在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。此时还没有挂载html到页面上。</p></li><li><p><strong>mounted(挂载后)</strong>:在el被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html 页面中。此过程中进行ajax交互。</p></li><li><p><strong>beforeUpdate(更新前)</strong>:响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM 还没有被渲染。</p></li><li><p><strong>updated(更新后)</strong> :在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。</p></li><li><p><strong>beforeDestroy(销毁前)</strong>:实例销毁之前调用。这一步,实例仍然完全可用,<code>this</code> 仍能获取到实例。</p></li><li><p><strong>destroyed(销毁后)</strong>:实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染期间不被调用。</p></li></ol><h3 id="组件间通信"><a href="#组件间通信" class="headerlink" title="组件间通信"></a>组件间通信</h3><ol><li><p><strong>父子组件间通信</strong></p><ul><li><p>子组件通过 props 属性来接受父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事件来向父组件发送数据。</p></li><li><p>通过 ref 属性给子组件设置一个名字。父组件通过 <code>$refs</code> 组件名来获得子组件,子组件通过 <code>$parent</code> 获得父组件,这样也可以实现通信。</p></li><li><p>使用 provide/inject,在父组件中通过 provide提供变量,在子组件中通过 inject 来将变量注入到组件中。不论子组件有多深,只要调用了 inject 那么就可以注入 provide中的数据。</p></li></ul></li><li><p><strong>兄弟组件间通信</strong></p><ul><li>使用 eventBus 的方法,它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。</li><li>通过 <code>$parent/$refs</code> 来获取到兄弟组件,也可以进行通信。</li></ul></li><li><p><strong>任意组件之间</strong></p><ul><li>使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件</li></ul></li></ol><h3 id="Vue-Router-的懒加载"><a href="#Vue-Router-的懒加载" class="headerlink" title="Vue-Router 的懒加载"></a>Vue-Router 的懒加载</h3><p>非懒加载:</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">import</span> List <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/list.vue'</span><br><span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({<br> <span class="hljs-attr">routes</span>: [<br> { <span class="hljs-attr">path</span>: <span class="hljs-string">'/list'</span>, <span class="hljs-attr">component</span>: List }<br> ]<br>})<br></code></pre></td></tr></table></figure><p>方案一(常用):使用箭头函数+import动态加载</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">const</span> List = <span class="hljs-function">() =></span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'@/components/list.vue'</span>)<br><span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({<br> <span class="hljs-attr">routes</span>: [<br> { <span class="hljs-attr">path</span>: <span class="hljs-string">'/list'</span>, <span class="hljs-attr">component</span>: List }<br> ]<br>})<br><br></code></pre></td></tr></table></figure><p>方案二:使用箭头函数+require动态加载</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> Router({<br> <span class="hljs-attr">routes</span>: [<br> {<br> <span class="hljs-attr">path</span>: <span class="hljs-string">'/list'</span>,<br> <span class="hljs-attr">component</span>: <span class="hljs-function"><span class="hljs-params">resolve</span> =></span> <span class="hljs-built_in">require</span>([<span class="hljs-string">'@/components/list'</span>], resolve)<br> }<br> ]<br>})<br><br></code></pre></td></tr></table></figure><p>方案三:使用webpack的require.ensure技术,也可以实现按需加载。 这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">// r就是resolve</span><br><span class="hljs-keyword">const</span> List = <span class="hljs-function"><span class="hljs-params">r</span> =></span> <span class="hljs-built_in">require</span>.ensure([], <span class="hljs-function">() =></span> r(<span class="hljs-built_in">require</span>(<span class="hljs-string">'@/components/list'</span>)), <span class="hljs-string">'list'</span>);<br><span class="hljs-comment">// 路由也是正常的写法 这种是官方推荐的写的 按模块划分懒加载 </span><br><span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> Router({<br> <span class="hljs-attr">routes</span>: [<br> {<br> <span class="hljs-attr">path</span>: <span class="hljs-string">'/list'</span>,<br> <span class="hljs-attr">component</span>: List,<br> <span class="hljs-attr">name</span>: <span class="hljs-string">'list'</span><br> }<br> ]<br>}))<br><br></code></pre></td></tr></table></figure><h3 id="路由的hash和history模式的区别"><a href="#路由的hash和history模式的区别" class="headerlink" title="路由的hash和history模式的区别"></a>路由的hash和history模式的区别</h3><p><strong>hash模式:</strong></p><p><strong>简介:</strong> hash模式是开发中默认的模式,它的URL带着一个#,例如:<a href="https://link.juejin.cn/?target=http://www.abc.com/%23/vue">www.abc.com/#/vue</a>,它的hash值就是<code>#/vue</code>。</p><p><strong>特点</strong>:hash值会出现在URL里面,但是不会出现在HTTP请求中,对后端完全没有影响。所以改变hash值,不会重新加载页面。这种模式的浏览器支持度很好,低版本的IE浏览器也支持这种模式。hash路由被称为是前端路由,已经成为SPA(单页面应用)的标配。</p><p><strong>原理:</strong> hash模式的主要原理就是<strong>onhashchange()事件</strong>:</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></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-built_in">window</span>.onhashchange = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">event</span>)</span>{<br><span class="hljs-built_in">console</span>.log(event.oldURL, event.newURL);<br><span class="hljs-keyword">let</span> hash = location.hash.slice(<span class="hljs-number">1</span>);<br>}<br></code></pre></td></tr></table></figure><p>使用onhashchange()事件的好处就是,在页面的hash值发生变化时,无需向后端发起请求,window就可以监听事件的改变,并按规则加载相应的代码。除此之外,hash值变化对应的URL都会被浏览器记录下来,这样浏览器就能实现页面的前进和后退。虽然是没有请求后端服务器,但是页面的hash值和对应的URL关联起来了。</p><p><strong>history模式</strong></p><p><strong>简介:</strong> history模式的URL中没有#,它使用的是传统的路由分发模式,即用户在输入一个URL时,服务器会接收这个请求,并解析这个URL,然后做出相应的逻辑处理。 <strong>特点:</strong> 当使用history模式时,URL就像这样:<a href="https://link.juejin.cn/?target=http://abc.com/user/id">abc.com/user/id</a>。相比hash模式更加好看。但是,history模式需要后台配置支持。如果后台没有正确配置,访问时会返回404。 <strong>API:</strong> history api可以分为两大部分,切换历史状态和修改历史状态:</p><ul><li><strong>修改历史状态</strong>:包括了 HTML5 History Interface 中新增的 <code>pushState()</code> 和 <code>replaceState()</code> 方法,这两个方法应用于浏览器的历史记录栈,提供了对历史记录进行修改的功能。只是当他们进行修改时,虽然修改了url,但浏览器不会立即向后端发送请求。如果要做到改变url但又不刷新页面的效果,就需要前端用上这两个API。</li><li><strong>切换历史状态:</strong> 包括<code>forward()</code>、<code>back()</code>、<code>go()</code>三个方法,对应浏览器的前进,后退,跳转操作。</li></ul><p>虽然history模式丢弃了丑陋的#。但是,它也有自己的缺点,就是在刷新页面的时候,如果没有相应的路由或资源,就会刷出404来。</p><p>如果想要切换到history模式,就要进行以下配置(后端也要进行配置):</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></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({<br> <span class="hljs-attr">mode</span>: <span class="hljs-string">'history'</span>,<br> <span class="hljs-attr">routes</span>: [...]<br>})<br></code></pre></td></tr></table></figure><h3 id="vue-config-js-打包优化配置"><a href="#vue-config-js-打包优化配置" class="headerlink" title="vue.config.js 打包优化配置"></a>vue.config.js 打包优化配置</h3><ol><li><p>Gzip 压缩</p></li><li><p>代码压缩</p></li><li><p>cdn 配置</p></li><li><p>公共代码抽离</p></li><li><p>css loader 处理</p></li><li><p>添加分析工具</p></li></ol><h2 id="Node"><a href="#Node" class="headerlink" title="Node"></a>Node</h2><h3 id="事件循环"><a href="#事件循环" class="headerlink" title="事件循环"></a>事件循环</h3><p><strong>Timers(计时器阶段)</strong>:初次进入事件循环,会从计时器阶段开始。此阶段会判断是否存在过期的计时器回调。如果存在则会执行所有过期的计时器回调,执行完毕后,如果回调中触发了相应的微任务,会接着执行所有微任务,执行完微任务后再进入 Pending callbacks 阶段。</p><p><strong>Pending callbacks</strong>:执行推迟到下一个循环迭代的I / O回调(系统调用相关的回调)</p><p><strong>Idle/Prepare</strong>:仅供内部使用。</p><p><strong>Poll(轮询阶段)</strong>:当回调队列不为空时:会执行回调,若回调中触发了相应的微任务,这里的微任务执行时机和其他地方有所不同,不会等到所有回调执行完毕后才执行,而是针对每一个回调执行完毕后,就执行相应微任务。执行完所有的回调后,变为下面的情况:<br>当回调队列为空时,但如果存在有计时器(setTimeout、setInterval和setImmediate)没有执行,会结束轮询阶段,进入 Check 阶段。否则会阻塞并等待任何正在执行的 I/O 操作完成,并马上执行相应的回调,直到所有回调执行完毕。</p><p><strong>Check(查询阶段)</strong>:会检查是否存在 setImmediate 相关的回调,如果存在则执行所有回调,执行完毕后,如果回调中触发了相应的微任务,会接着执行所有微任务,执行完微任务后再进入 Close callbacks 阶段。</p><p><strong>Close callbacks</strong>:执行一些关闭回调</p><h3 id="V8-垃圾回收"><a href="#V8-垃圾回收" class="headerlink" title="V8 垃圾回收"></a>V8 垃圾回收</h3><p>新生代:32->16MB 64->32MB<br>老生代:32->700MB 64->1.4G<br>新生代分 From To 两个空间,From 是使用状态,To 是闲置状态,主要是通过引用标记的方式,如果有引用,则从 From 到 To,并清除 From 的内容<br>当一个对象经过多次复制仍然存活时,就会被认为是生命周期较长的对象,移到老生代中<br>老生代用标记清除和标记整理算法</p><h2 id="安全"><a href="#安全" class="headerlink" title="安全"></a>安全</h2><h3 id="安全问题"><a href="#安全问题" class="headerlink" title="安全问题"></a>安全问题</h3><p>XSS: 跨域脚本攻击,向网站注入 js 代码,然后执行 js 里的代码,篡改网站的内容<br>CSRF:跨站请求伪造,在用户登录了信任网站A,并生成了本地 cookie,在不登出 A 的情况下,访问了危险网站 B,利用 A 的 cookie 来伪造请求。</p><p>如何防范:<br>XSS:</p><ol><li>对敏感字符进行转义</li><li>HttpOnly 防止劫取 cookie</li></ol><p>CSRF:</p><ol><li>同源检测(Origin 和 Referer)</li><li>token 验证</li></ol><h3 id="防止运行商劫持,前端解决办法"><a href="#防止运行商劫持,前端解决办法" class="headerlink" title="防止运行商劫持,前端解决办法"></a>防止运行商劫持,前端解决办法</h3><p>常见的劫持方式:</p><ul><li>跳转型劫持:输入地址 A,跳转到地址 B</li><li>注入型劫持:在正常网页中注入广告代码(js、iframe 等)</li></ul><ol><li>针对注入js,添加资源过滤,不是自身的 js 不执行。</li><li>针对加载资源,添加白名单控制,在 meta 中设置。</li><li>针对 iframe 嵌套,判断当前窗口有没有被嵌入到别的窗口中。</li></ol><h3 id="跨域问题"><a href="#跨域问题" class="headerlink" title="跨域问题"></a>跨域问题</h3><p>url 的组成是:协议、域名、端口,当一个请求url 的协议、域名、端口三者之间任意一个与当前页面 url 不同时即为跨域。<br>解决方案:</p><ol><li>document.domain + iframe</li><li>动态创建js</li><li>location.hash + iframe</li><li>postMessage</li><li>cors:使用自定义的 http 头部与服务器沟通</li><li>jsonp</li><li>Nginx</li></ol><h2 id="设计模式"><a href="#设计模式" class="headerlink" title="设计模式"></a>设计模式</h2><ol><li>工厂模式</li><li>装饰器模式</li><li>主从模式</li><li>生产者消费者模式</li><li>单例模式</li><li>代理模式</li><li>MVC 模式</li></ol><h2 id="前端优化"><a href="#前端优化" class="headerlink" title="前端优化"></a>前端优化</h2><h3 id="防抖和节流"><a href="#防抖和节流" class="headerlink" title="防抖和节流"></a>防抖和节流</h3><p>防抖:短时间内大量触发同一事件,只会执行一次函数。debounce<br>节流:短时间内大量触发同一事件,函数只会执行一次,该函数在指定的时间期限内不在工作。throttle</p><h3 id="性能优化"><a href="#性能优化" class="headerlink" title="性能优化"></a>性能优化</h3><ol><li>减少 http 请求</li><li>使用 http2</li><li>使用服务端渲染</li><li>静态资源使用 CDN</li><li>将 css 放在文件头部、js 文件放在底部</li><li>使用字体图标 iconfont 代替图片图标</li><li>善用缓存,不重复加载相同的资源</li><li>压缩文件</li><li>图片优化:图片延迟加载、响应式图片、调整图片大小、降低图片质量、尽可能用 css3 效果代替图片</li><li>使用 webp 格式图片</li><li>通过 webpack 按需加载代码,提取第三方库,减少es6转为 es5 的冗余代码</li><li>减少重绘重排</li><li>使用事件委托</li><li>使用 web workers</li><li>降低 CSS 选择器的复杂性</li></ol><h3 id="减少请求数"><a href="#减少请求数" class="headerlink" title="减少请求数"></a>减少请求数</h3><ol><li>删除不必要的图像</li><li>使用雪碧图:把多个图合并到一个图片文件,通过css控制输出。</li><li>实施延迟加载技术</li><li>缩小 css 和 js 文件</li><li>合并 css 和 js 文件</li><li>减少外部脚本数量</li><li>使用 CDN</li></ol><h3 id="骨架屏"><a href="#骨架屏" class="headerlink" title="骨架屏"></a>骨架屏</h3><p>在需要等待加载内容的位置提供一个占位图形组合</p><h3 id="SEO"><a href="#SEO" class="headerlink" title="SEO"></a>SEO</h3><ol><li><p>title 和 meta 设置:包含品牌词和业务词,提升页面排名</p></li><li><p>页面内容优化:网页代码语义化调整,多使用语义化便签,便于爬虫检索;页面内容关键词强化,在页面大小标题和文案中重复关键词,以达到内容强化目的;img 添加 alt 属性,用 h1 便签去写内容关键字</p></li><li><p>引导链接:网站底部推荐部分保留产品介绍、常见问题汇总等降低跳出率的引导,提高页面留存与转化;或者与所推荐页面形成互链形式,以稳定页面流量权重</p></li><li><p>移动端优化:设置移动页面,或将 pc 页面设置为自适应,增加移动端搜索的体验和留存转化</p></li><li><p>站外优化:</p><ul><li>在搜索引擎排名较高的公众平台发布正面网站信息,以建设良好口碑,负面信息排名较高的需要删除或者屏蔽处理。</li><li>百度,互动,搜狗等百科的创建更新与维护</li><li>公关舆情传播</li><li>站外推广与外链建设</li></ul></li></ol><h3 id="SPA-单页面的理解"><a href="#SPA-单页面的理解" class="headerlink" title="SPA 单页面的理解"></a>SPA 单页面的理解</h3><p>仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。</p><p><strong>优点:</strong></p><ul><li>用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;</li><li>基于上面一点,SPA 相对对服务器压力小;</li><li>前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;</li></ul><p><strong>缺点:</strong></p><ul><li>初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;</li><li>前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;</li><li>SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。</li></ul><h3 id="前端工程化"><a href="#前端工程化" class="headerlink" title="前端工程化"></a>前端工程化</h3><ol><li><p>使用 webpack 实现项目构建</p><ul><li><p>将前端开发中的所有源代码转化为宿主浏览器可以执行的代码</p></li><li><p>前端的构建还应该考虑到Web应用的性能优化。这些优化主要是为了减少HTTP请求,提升用户体验</p><ul><li><p>依赖打包,将同步依赖的文件打包在一起,减少HTTP请求数量;</p></li><li><p>资源嵌入,例如将小于10kb的图片编译为base64格式嵌入文档,减少HTTP请求;</p></li><li><p>文件压缩,减少文件体积,缩短请求时间;</p></li><li><p>为文件加入hash指纹,以应对浏览器缓存策略;</p></li></ul></li></ul></li></ol><p> </p><ol start="2"><li><p>使用 babel 完成 JavaScript 的编译</p></li><li><p>css 预编译</p></li><li><p>模块化开发</p><ul><li>避免命名冲突;</li><li>便于依赖管理;</li><li>利于性能优化;</li><li>提高可维护性;</li><li>提高代码可复用性;</li></ul></li><li><p>组件化开发</p></li><li><p>开发环境的本地服务器与 mock 服务</p></li><li><p>规范化约束(eslint + prettier)</p></li><li><p>项目部署流程化</p></li></ol><h2 id="浏览器"><a href="#浏览器" class="headerlink" title="浏览器"></a>浏览器</h2><h3 id="浏览器渲染过程"><a href="#浏览器渲染过程" class="headerlink" title="浏览器渲染过程"></a>浏览器渲染过程</h3><ol><li>解析HTML生成DOM树。</li><li>解析CSS生成CSSOM规则树。</li><li>将DOM树与CSSOM规则树合并在一起生成渲染树。</li><li>遍历渲染树开始布局,计算每个节点的位置大小信息。</li><li>将渲染树每个节点绘制到屏幕。</li></ol><h3 id="从输入Url到页面渲染"><a href="#从输入Url到页面渲染" class="headerlink" title="从输入Url到页面渲染"></a>从输入Url到页面渲染</h3><p>网络阶段:构建请求行、查询强缓存、DNS解析、建立TCP连接、发送HTTP请求、响应请求 </p><p>解析阶段:解析html、构建dom树、计算样式、生成布局树 </p><p>渲染阶段:生成图层树、生成绘制列表、生成图块、优先选择视口附近的图块生成位图数据、展示内容</p><h2 id="webpack"><a href="#webpack" class="headerlink" title="webpack"></a>webpack</h2><h3 id="webpack-原理"><a href="#webpack-原理" class="headerlink" title="webpack 原理"></a>webpack 原理</h3><ol><li>初始化参</li><li>开始编译 用上一步得到的参数初始Compiler对象,加载所有配置的插件,通 过执行对象的run方法开始执行编译</li><li>确定入口 根据配置中的 Entry 找出所有入口文件</li><li>编译模块 从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理</li><li>完成模块编译 在经过第4步使用 Loader 翻译完所有模块后, 得到了每个模块被编译后的最终内容及它们之间的依赖关系</li><li>输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再将每个 Chunk 转换成一个单独的文件加入输出列表中,这是可以修改输出内容的最后机会</li><li>输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,将文件的内容写入文件系统中。</li></ol><h3 id="webpack-如何处理-es-module-现代浏览器怎么写-esmodule"><a href="#webpack-如何处理-es-module-现代浏览器怎么写-esmodule" class="headerlink" title="webpack 如何处理 es module, 现代浏览器怎么写 esmodule"></a>webpack 如何处理 es module, 现代浏览器怎么写 esmodule</h3><p>webpack 对于 es 模块的实现,也是基于自己实现的 <strong>webpack_require</strong> 和 <strong>webpack_exports__,转换成类似于 commonjs 的形式。对于 es 模块和 commonjs混用的情况,则需要通过__webpack_require</strong>.n 的形式做一层包装来实现。</p><p>在 script 标签上添加一个 type=”module”的属性来表示这个文件是作为 module 的方式来运行的。</p><h3 id="treeshaking"><a href="#treeshaking" class="headerlink" title="treeshaking"></a>treeshaking</h3><p>用来尽可能地删除没有被使用过的代码,一些 import了但是其实没有被使用的代码<br>在配置文件中设置 mode 为 production<br>ES6 模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析</p><h3 id="怎么用-webpack-处理图片"><a href="#怎么用-webpack-处理图片" class="headerlink" title="怎么用 webpack 处理图片"></a>怎么用 webpack 处理图片</h3><ol><li>控制图片质量,压缩图片大小</li><li>配置<img/>标签的 srcset 来适应不同的屏幕</li><li>合成雪碧图,减少图片资源请求数</li><li>使用占位图</li></ol><h2 id="css"><a href="#css" class="headerlink" title="css"></a>css</h2><h3 id="icon-图标怎么引入"><a href="#icon-图标怎么引入" class="headerlink" title="icon 图标怎么引入"></a>icon 图标怎么引入</h3><ol><li>引入外部 css,在icon网站上生成 css 导入</li><li>下载文件,导入 css</li></ol><h3 id="position-的值"><a href="#position-的值" class="headerlink" title="position 的值"></a>position 的值</h3><p>relative:相对定位,相对于元素的原本位置进行定位<br>absolute:相对于position 值不是 static 的父容器进行定位<br>fixed:固定定位,相对于浏览器窗口进行定位<br>static:默认值,表示无定位</p><h3 id="position-fixed-失效的原因"><a href="#position-fixed-失效的原因" class="headerlink" title="position:fixed 失效的原因"></a>position:fixed 失效的原因</h3><p>父元素有 transform 属性,值不为 none</p><h3 id="flex-布局中-flex-1-代表什么"><a href="#flex-布局中-flex-1-代表什么" class="headerlink" title="flex 布局中 flex:1 代表什么"></a>flex 布局中 flex:1 代表什么</h3><p>flex-grow: 放大比例,默认为 0<br>flex-shrink: 缩小比例,默认为 1<br>flex-basic: 给上面两个属性分配多余空间之前,计算项目是否有多余空间,默认值为 auto,即项目本身的大小</p><h2 id="js"><a href="#js" class="headerlink" title="js"></a>js</h2><h3 id="var-let-const的差别"><a href="#var-let-const的差别" class="headerlink" title="var,let,const的差别"></a>var,let,const的差别</h3><ol><li>var声明的变量会挂载在 window 上,let、const 不会。</li><li>var 声明变量存在变量提升,let、const 不存在</li><li>let、const 声明形成块作用域</li><li>同一作用域下 let 和 const 不能声明同名变量,而 var 可以</li><li>const 一旦声明必须赋值,不能使用 null 占位,不能修改,如果是符合类型数据,可以修改其属性。</li></ol><h3 id="函数的作用域,变量保存在哪里"><a href="#函数的作用域,变量保存在哪里" class="headerlink" title="函数的作用域,变量保存在哪里"></a>函数的作用域,变量保存在哪里</h3><p>在 js 中每声明一个函数就会创建一个函数作用域,同时这个函数的所有变量在整个函数的范围内都可以访问。</p><h3 id="常见的作用域有哪些"><a href="#常见的作用域有哪些" class="headerlink" title="常见的作用域有哪些"></a>常见的作用域有哪些</h3><p>全局作用域、函数作用域、块状作用域、动态作用域</p><h3 id="作用域链什么时候确定的"><a href="#作用域链什么时候确定的" class="headerlink" title="作用域链什么时候确定的"></a>作用域链什么时候确定的</h3><p>变量的作用域是在定义时决定的,通过静态分析就能确定,叫做静态作用域<br>要开启动态作用域的话,要使用 bind、with、eval</p><h3 id="js-执行上下文"><a href="#js-执行上下文" class="headerlink" title="js 执行上下文"></a>js 执行上下文</h3><ol><li>全局执行上下文:只有一个,由浏览器创建,即 window 对象</li><li>函数执行上下文:可以有无数个,每当一个函数被调用时都会创建一个函数上下文。</li><li>执行上下文:执行栈用于存储代码执行期间创建的所有上下文,具有先进后出的特点,执行上下文创建阶段分为绑定this,创建词法环境,变量环境三步。</li></ol><h3 id="js-在-new-的过程中发生了什么"><a href="#js-在-new-的过程中发生了什么" class="headerlink" title="js 在 new 的过程中发生了什么"></a>js 在 new 的过程中发生了什么</h3><ol><li>创建新对象</li><li>这个对象的原型指向函数的 propertype</li><li>让函数的 this 指向这个对象,执行构造函数</li><li>判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。</li></ol><h3 id="call-、-apply-和-bind"><a href="#call-、-apply-和-bind" class="headerlink" title="call 、 apply 和 bind"></a>call 、 apply 和 bind</h3><p>改变函数的 this 指向,call 和 apply 的第一个参数都是表示要改变指向的对象,第二个参数,apply 是数组,call 是…args 的形式,通过 bind 改变的 this 作用域会返回一个新函数,这个函数不会马上执行。</p><h3 id="重绘与回流,如何优化"><a href="#重绘与回流,如何优化" class="headerlink" title="重绘与回流,如何优化"></a>重绘与回流,如何优化</h3><ol><li>批量修改 dom 或者样式 :class</li><li>脱离文档流</li><li>先把元素隐藏再改变</li></ol><h3 id="margin重叠,如何解决"><a href="#margin重叠,如何解决" class="headerlink" title="margin重叠,如何解决"></a>margin重叠,如何解决</h3><p>BFC:加个 div 使其触发 bfc</p><h3 id="清除浮动,伪元素清除浮动加在哪里"><a href="#清除浮动,伪元素清除浮动加在哪里" class="headerlink" title="清除浮动,伪元素清除浮动加在哪里"></a>清除浮动,伪元素清除浮动加在哪里</h3><p>正常:加一个新元素 class=”clear:both”<br>伪元素:,如.test:after{clear:both}</p><h3 id="常见的网络协议"><a href="#常见的网络协议" class="headerlink" title="常见的网络协议"></a>常见的网络协议</h3><p>TCP/IP 协议、HTTP 协议、HTTPS 协议、UDP</p><h3 id="事件委托(事件代理)"><a href="#事件委托(事件代理)" class="headerlink" title="事件委托(事件代理)"></a>事件委托(事件代理)</h3><p>只指定一个事件处理程序,就可以管理某一类型的所有事件</p><h3 id="事件冒泡和捕获"><a href="#事件冒泡和捕获" class="headerlink" title="事件冒泡和捕获"></a>事件冒泡和捕获</h3><p>事件冒泡:事件会从最内层的元素开始发生,一直向上传播,直到document对象。</p><p>事件捕获:事件会从最外层开始发生,直到最具体的元素。</p><h3 id="e-target-和-e-currentTarget-的区别"><a href="#e-target-和-e-currentTarget-的区别" class="headerlink" title="e.target 和 e.currentTarget 的区别"></a>e.target 和 e.currentTarget 的区别</h3><p><code>e.target</code> 指向触发事件监听的对象。</p><p><code>e.currentTarget</code> 指向添加监听事件的对象。</p><p>addEventListener 的第三个参数是 true 时,是捕获;是 false 时是冒泡</p><h3 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h3><p>promise 解决了什么问题:</p><ol><li>消灭嵌套调用</li><li>合并多个任务的请求结果</li></ol><p>Promise 的 API</p><ul><li>Promise.resolve():默认产生一个成功的 promise</li><li>Promise.reject():默认产生一个失败的 promise,Promise.reject 是直接将值变成错误结果</li><li>Promise.prototype.catch():用来捕获 promise 的异常,就相当于一个没有成功的 then</li><li>Promise.prototype.finally():最后执行</li><li>Promise.all():解决并发问题,多个异步并发获取最终结果,一个失败则全部失败</li><li>Promise.race():用来处理多个请求,采用最快返回的结果</li></ul><h3 id="常用的正则表达式"><a href="#常用的正则表达式" class="headerlink" title="常用的正则表达式"></a>常用的正则表达式</h3><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">// (1)匹配 16 进制颜色值</span><br><span class="hljs-keyword">var</span> regex = <span class="hljs-regexp">/#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g</span>;<br><br><span class="hljs-comment">// (2)匹配日期,如 yyyy-mm-dd 格式</span><br><span class="hljs-keyword">var</span> regex = <span class="hljs-regexp">/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/</span>;<br><br><span class="hljs-comment">// (3)匹配 qq 号</span><br><span class="hljs-keyword">var</span> regex = <span class="hljs-regexp">/^[1-9][0-9]{4,10}$/g</span>;<br><br><span class="hljs-comment">// (4)手机号码正则</span><br><span class="hljs-keyword">var</span> regex = <span class="hljs-regexp">/^1[34578]\d{9}$/g</span>;<br><br><span class="hljs-comment">// (5)用户名正则</span><br><span class="hljs-keyword">var</span> regex = <span class="hljs-regexp">/^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/</span>;<br><br></code></pre></td></tr></table></figure><h3 id="相等运算符"><a href="#相等运算符" class="headerlink" title="相等运算符"></a>相等运算符</h3><ol><li>原始类型值:原始类型的值会转换成数值再进行比较:boolean、string</li><li>对象与原始类型值比较:对象转换成原始类型的值,在进行比较,先调用对象的 valueOf 方法,如果得到原始类型的值,就进行比较;如果得到的还是对象,则再调用 toString 方法,得到字符串形式,在进行比较</li><li>undefined 和 null:undefined 和 null 只有与自身比较,或者互相比较时,才会返回 true;与其他类型的值比较时,结果都为 false</li></ol><h3 id="JS-不同数据类型相加"><a href="#JS-不同数据类型相加" class="headerlink" title="JS 不同数据类型相加"></a>JS 不同数据类型相加</h3><ol><li>string + number<ul><li>数字在前,字符串在后:从左到右计算,先计算数字表达式,再把计算结果转化为字符串和后面的字符串相加</li><li>字符串在前,数字在后:数字转化为字符串相加</li><li>空文本加数字,有多少空格就显示多少空格</li></ul></li><li>number + boolean:布尔值为 true 转化为 1,布尔值为 false 转化为 0,与数字相加</li><li>string + boolean:布尔值转换为字符串相加</li><li>null + number/string<ul><li>null + number:null 转为为 0,与数字相加</li><li>null + string:null 转为字符串,与数字相加</li></ul></li><li>null + boolean:null 转为 0,true 为 1,false 为 0,相加</li><li>undefined 与其余数据类型相加:undefined 只与字符串进行累加时有效,其他情况皆返回 NaN</li></ol><h3 id="js-如何执行代码"><a href="#js-如何执行代码" class="headerlink" title="js 如何执行代码"></a>js 如何执行代码</h3><p><img src="https://segmentfault.com/img/remote/1460000023133332" alt="js 如何执行代码"></p><h2 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h2><h3 id="排序有哪些,时间复杂度、空间复杂度"><a href="#排序有哪些,时间复杂度、空间复杂度" class="headerlink" title="排序有哪些,时间复杂度、空间复杂度"></a>排序有哪些,时间复杂度、空间复杂度</h3><p>快速排序、归并排序、堆排序:时间复杂度O(nlogn)<br>冒泡、选择、插入O(n2)</p><h2 id="计算机知识"><a href="#计算机知识" class="headerlink" title="计算机知识"></a>计算机知识</h2><h3 id="进程与线程"><a href="#进程与线程" class="headerlink" title="进程与线程"></a>进程与线程</h3><p>进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行过程。<br>线程是程序执行流的最小单元</p><p>一个进程是由多个线程组成,线程是进程中代码的不同执行路线</p><h2 id="TS"><a href="#TS" class="headerlink" title="TS"></a>TS</h2><h3 id="Partial"><a href="#Partial" class="headerlink" title="Partial"></a>Partial</h3><p>Partial 作用是将传入的属性变为可选项。</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">type</span> Partial<T> = { [P <span class="hljs-keyword">in</span> keyof T]?: T[P] };<br></code></pre></td></tr></table></figure><h3 id="Required"><a href="#Required" class="headerlink" title="Required"></a>Required</h3><p>Required 的作用是将传入的属性变为必选项</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">type</span> Required<T> = { [P <span class="hljs-keyword">in</span> keyof T]-?: T[P] };<br></code></pre></td></tr></table></figure><h3 id="Mutable"><a href="#Mutable" class="headerlink" title="Mutable"></a>Mutable</h3><p>对 readonly 进行加减。</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-keyword">type</span> Mutable<T> = {<br> -<span class="hljs-keyword">readonly</span> [P <span class="hljs-keyword">in</span> keyof T]: T[P]<br>}<br></code></pre></td></tr></table></figure><h3 id="Readonly"><a href="#Readonly" class="headerlink" title="Readonly"></a>Readonly</h3><p>将传入的属性变为只读选项</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">type</span> Readonly<T> = { <span class="hljs-keyword">readonly</span> [P <span class="hljs-keyword">in</span> keyof T]: T[P] };<br></code></pre></td></tr></table></figure><h3 id="Record"><a href="#Record" class="headerlink" title="Record"></a>Record</h3><p>将 K 中所有的属性的值转化为 T 类型</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">type</span> Record<K <span class="hljs-keyword">extends</span> keyof <span class="hljs-built_in">any</span>, T> = { [P <span class="hljs-keyword">in</span> K]: T };<br></code></pre></td></tr></table></figure><h3 id="Pick"><a href="#Pick" class="headerlink" title="Pick"></a>Pick</h3><p>从 T 中取出 一系列 K 的属性</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">type</span> Pick<T, K <span class="hljs-keyword">extends</span> keyof T> = { [P <span class="hljs-keyword">in</span> K]: T[P] };<br></code></pre></td></tr></table></figure><h3 id="Exclude"><a href="#Exclude" class="headerlink" title="Exclude"></a>Exclude</h3><p>从 T 中找出 U 中没有的元素, 换种更加贴近语义的说法其实就是从T 中排除 U</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">type</span> Exclude<T, U> = T <span class="hljs-keyword">extends</span> U ? <span class="hljs-built_in">never</span> : T;<br></code></pre></td></tr></table></figure><h3 id="Extract"><a href="#Extract" class="headerlink" title="Extract"></a>Extract</h3><p>提取出 T 包含在 U 中的元素</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">type</span> Extract<T, U> = T <span class="hljs-keyword">extends</span> U ? T : <span class="hljs-built_in">never</span>;<br></code></pre></td></tr></table></figure><h3 id="Omit"><a href="#Omit" class="headerlink" title="Omit"></a>Omit</h3><p>用之前的 Pick 和 Exclude 进行组合, 实现忽略对象某些属性功能</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">type</span> Omit<T, K> = Pick<T, Exclude<keyof T, K>><br><br><span class="hljs-comment">// 使用</span><br><span class="hljs-keyword">type</span> Foo = Omit<{<span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span>, <span class="hljs-attr">age</span>: <span class="hljs-built_in">number</span>}, <span class="hljs-string">'name'</span>> <span class="hljs-comment">// -> { age: number }</span><br></code></pre></td></tr></table></figure><h1 id="前端新技术"><a href="#前端新技术" class="headerlink" title="前端新技术"></a>前端新技术</h1><h3 id="PWA"><a href="#PWA" class="headerlink" title="PWA"></a>PWA</h3><p>PWA 指的是使用指定技术和标准模式来开发的 Web 应用,这同时赋予它们 Web 应用和原生应用的特性。</p><h3 id="Electron"><a href="#Electron" class="headerlink" title="Electron"></a>Electron</h3>]]></content>
</entry>
<entry>
<title>最长回文子串</title>
<link href="/2021/11/27/algorithm-test-11273/"/>
<url>/2021/11/27/algorithm-test-11273/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>给你一个字符串 s,找到 s 中最长的回文子串。</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight nix"><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><code class="hljs nix">输入:<span class="hljs-attr">s</span> = <span class="hljs-string">"babad"</span><br>输出:<span class="hljs-string">"bab"</span><br>解释:<span class="hljs-string">"aba"</span> 同样是符合题意的答案。<br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs nix">输入:<span class="hljs-attr">s</span> = <span class="hljs-string">"cbbd"</span><br>输出:<span class="hljs-string">"bb"</span><br></code></pre></td></tr></table></figure><h3 id="示例-3"><a href="#示例-3" class="headerlink" title="示例 3"></a>示例 3</h3><figure class="highlight nix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs nix">输入:<span class="hljs-attr">s</span> = <span class="hljs-string">"ac"</span><br>输出:<span class="hljs-string">"a"</span><br></code></pre></td></tr></table></figure><h3 id="示例-4"><a href="#示例-4" class="headerlink" title="示例 4"></a>示例 4</h3><figure class="highlight smalltalk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs smalltalk">输入:s = <span class="hljs-comment">"a"</span><br>输出:<span class="hljs-comment">"a"</span><br></code></pre></td></tr></table></figure><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param <span class="hljs-type">{string}</span> <span class="hljs-variable">s</span></span></span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return <span class="hljs-type">{string}</span></span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">var</span> longestPalindrome = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">s</span>) </span>{<br> <span class="hljs-keyword">if</span> (!s) {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">""</span><br> }<br> <span class="hljs-keyword">let</span> start = <span class="hljs-number">0</span>, end = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < s.length; i++) {<br> <span class="hljs-keyword">let</span> len1 = expandAroundCenter(s, i, i)<br> <span class="hljs-keyword">let</span> len2 = expandAroundCenter(s, i, i + <span class="hljs-number">1</span>)<br> <span class="hljs-keyword">let</span> len = <span class="hljs-built_in">Math</span>.max(len1, len2)<br> <span class="hljs-keyword">if</span> (len > end - start) {<br> start = i - <span class="hljs-built_in">Math</span>.floor((len - <span class="hljs-number">1</span>) / <span class="hljs-number">2</span>)<br> end = i + <span class="hljs-built_in">Math</span>.floor(len / <span class="hljs-number">2</span>)<br> }<br> }<br> <span class="hljs-keyword">return</span> s.substring(start, end + <span class="hljs-number">1</span>);<br>};<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">expandAroundCenter</span>(<span class="hljs-params">s, left, right</span>) </span>{<br> <span class="hljs-keyword">while</span> (left >= <span class="hljs-number">0</span> && right < s.length && s[left] === s[right]) {<br> --left<br> ++right<br> }<br> <span class="hljs-keyword">return</span> right - left - <span class="hljs-number">1</span><br>}<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>字符串转换整数 (atoi)</title>
<link href="/2021/11/27/algorithm-test-11272/"/>
<url>/2021/11/27/algorithm-test-11272/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。</p><p>函数 myAtoi(string s) 的算法如下:</p><ul><li>读入字符串并丢弃无用的前导空格</li><li>检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。</li><li>读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。<br>将前面步骤读入的这些数字转换为整数(即,”123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。</li><li>如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。</li><li>返回整数作为最终结果。</li></ul><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight prolog"><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></pre></td><td class="code"><pre><code class="hljs prolog">输入:s = <span class="hljs-string">"42"</span><br>输出:<span class="hljs-number">42</span><br>解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。<br>第 <span class="hljs-number">1</span> 步:<span class="hljs-string">"42"</span>(当前没有读入字符,因为没有前导空格)<br> ^<br>第 <span class="hljs-number">2</span> 步:<span class="hljs-string">"42"</span>(当前没有读入字符,因为这里不存在 <span class="hljs-string">'-'</span> 或者 <span class="hljs-string">'+'</span>)<br> ^<br>第 <span class="hljs-number">3</span> 步:<span class="hljs-string">"42"</span>(读入 <span class="hljs-string">"42"</span>)<br> ^<br>解析得到整数 <span class="hljs-number">42</span> 。<br>由于 <span class="hljs-string">"42"</span> 在范围 [<span class="hljs-number">-231</span>, <span class="hljs-number">231</span> - <span class="hljs-number">1</span>] 内,最终结果为 <span class="hljs-number">42</span> 。<br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight subunit"><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></pre></td><td class="code"><pre><code class="hljs subunit">输入:s = " <span class="hljs-string">-42</span>"<br>输出:<span class="hljs-string">-42</span><br>解释:<br>第 1 步:" <span class="hljs-string">-42</span>"(读入前导空格,但忽视掉)<br> ^<br>第 2 步:" <span class="hljs-string">-42</span>"(读入 '-' 字符,所以结果应该是负数)<br> ^<br>第 3 步:" <span class="hljs-string">-42</span>"(读入 "42")<br> ^<br>解析得到整数 <span class="hljs-string">-42</span> 。<br>由于 "<span class="hljs-string">-42</span>" 在范围 [<span class="hljs-string">-231</span>, 231 - 1] 内,最终结果为 <span class="hljs-string">-42</span> 。<br></code></pre></td></tr></table></figure><h3 id="示例-3"><a href="#示例-3" class="headerlink" title="示例 3"></a>示例 3</h3><figure class="highlight prolog"><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><code class="hljs prolog">输入:s = <span class="hljs-string">"4193 with words"</span><br>输出:<span class="hljs-number">4193</span><br>解释:<br>第 <span class="hljs-number">1</span> 步:<span class="hljs-string">"4193 with words"</span>(当前没有读入字符,因为没有前导空格)<br> ^<br>第 <span class="hljs-number">2</span> 步:<span class="hljs-string">"4193 with words"</span>(当前没有读入字符,因为这里不存在 <span class="hljs-string">'-'</span> 或者 <span class="hljs-string">'+'</span>)<br> ^<br>第 <span class="hljs-number">3</span> 步:<span class="hljs-string">"4193 with words"</span>(读入 <span class="hljs-string">"4193"</span>;由于下一个字符不是一个数字,所以读入停止)<br> ^<br>解析得到整数 <span class="hljs-number">4193</span> 。<br>由于 <span class="hljs-string">"4193"</span> 在范围 [<span class="hljs-number">-231</span>, <span class="hljs-number">231</span> - <span class="hljs-number">1</span>] 内,最终结果为 <span class="hljs-number">4193</span> 。<br><br></code></pre></td></tr></table></figure><h3 id="示例-4"><a href="#示例-4" class="headerlink" title="示例 4"></a>示例 4</h3><figure class="highlight prolog"><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><code class="hljs prolog">输入:s = <span class="hljs-string">"words and 987"</span><br>输出:<span class="hljs-number">0</span><br>解释:<br>第 <span class="hljs-number">1</span> 步:<span class="hljs-string">"words and 987"</span>(当前没有读入字符,因为没有前导空格)<br> ^<br>第 <span class="hljs-number">2</span> 步:<span class="hljs-string">"words and 987"</span>(当前没有读入字符,因为这里不存在 <span class="hljs-string">'-'</span> 或者 <span class="hljs-string">'+'</span>)<br> ^<br>第 <span class="hljs-number">3</span> 步:<span class="hljs-string">"words and 987"</span>(由于当前字符 <span class="hljs-string">'w'</span> 不是一个数字,所以读入停止)<br> ^<br>解析得到整数 <span class="hljs-number">0</span> ,因为没有读入任何数字。<br>由于 <span class="hljs-number">0</span> 在范围 [<span class="hljs-number">-231</span>, <span class="hljs-number">231</span> - <span class="hljs-number">1</span>] 内,最终结果为 <span class="hljs-number">0</span> 。<br><br></code></pre></td></tr></table></figure><h3 id="示例-5"><a href="#示例-5" class="headerlink" title="示例 5"></a>示例 5</h3><figure class="highlight subunit"><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></pre></td><td class="code"><pre><code class="hljs subunit">输入:s = "<span class="hljs-string">-91283472332</span>"<br>输出:<span class="hljs-string">-2147483648</span><br>解释:<br>第 1 步:"<span class="hljs-string">-91283472332</span>"(当前没有读入字符,因为没有前导空格)<br> ^<br>第 2 步:"<span class="hljs-string">-91283472332</span>"(读入 '-' 字符,所以结果应该是负数)<br> ^<br>第 3 步:"<span class="hljs-string">-91283472332</span>"(读入 "91283472332")<br> ^<br>解析得到整数 <span class="hljs-string">-91283472332</span> 。<br>由于 <span class="hljs-string">-91283472332</span> 小于范围 [<span class="hljs-string">-231</span>, 231 - 1] 的下界,最终结果被截断为 <span class="hljs-string">-231</span> = <span class="hljs-string">-2147483648</span> 。<br></code></pre></td></tr></table></figure><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param <span class="hljs-type">{string}</span> <span class="hljs-variable">s</span></span></span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return <span class="hljs-type">{number}</span></span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">var</span> myAtoi = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">s</span>) </span>{<br> <span class="hljs-keyword">let</span> start = <span class="hljs-number">0</span>,<br> startFlag = <span class="hljs-literal">true</span>,<br> strStack = []<br> <span class="hljs-keyword">while</span> (start <= s.length - <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">if</span> (s[start] === <span class="hljs-string">' '</span> && strStack.length === <span class="hljs-number">0</span>) {<br> start++<br> <span class="hljs-keyword">continue</span><br> }<br><br> <span class="hljs-keyword">if</span> ((s[start] === <span class="hljs-string">'-'</span> || s[start] === <span class="hljs-string">'+'</span>) && startFlag && strStack.length === <span class="hljs-number">0</span>) {<br> startFlag = <span class="hljs-literal">false</span><br> strStack.push(s[start])<br> start++<br> <span class="hljs-keyword">continue</span><br> }<br> <span class="hljs-keyword">if</span> (s[start] === <span class="hljs-string">' '</span>) {<br> <span class="hljs-keyword">break</span><br> }<br><br> <span class="hljs-keyword">let</span> temp = s.charAt(start) - <span class="hljs-string">'0'</span><br> <span class="hljs-keyword">if</span> (temp === <span class="hljs-number">0</span> && !strStack) {<br> start++<br> <span class="hljs-keyword">continue</span><br> }<br> <span class="hljs-keyword">if</span> (temp >= <span class="hljs-number">0</span> && temp <= <span class="hljs-number">9</span>) {<br> strStack.push(s[start])<br> start++<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">break</span><br> }<br> }<br> <span class="hljs-keyword">let</span> ans = !strStack.length ? <span class="hljs-number">0</span> : <span class="hljs-built_in">Number</span>(strStack.join(<span class="hljs-string">''</span>)) || <span class="hljs-number">0</span><br> <span class="hljs-keyword">if</span> (ans < -<span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">2</span>, <span class="hljs-number">31</span>)) {<br> <span class="hljs-keyword">return</span> -<span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">2</span>, <span class="hljs-number">31</span>)<br> }<br> <span class="hljs-keyword">if</span> (ans > <span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">2</span>, <span class="hljs-number">31</span>) - <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">2</span>, <span class="hljs-number">31</span>) - <span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">return</span> ans<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>三数之和</title>
<link href="/2021/11/27/algorithm-test-11271/"/>
<url>/2021/11/27/algorithm-test-11271/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight subunit"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs subunit">输入:nums = [<span class="hljs-string">-1</span>,0,1,2,<span class="hljs-string">-1</span>,<span class="hljs-string">-4</span>]<br>输出:[[<span class="hljs-string">-1</span>,<span class="hljs-string">-1</span>,2],[<span class="hljs-string">-1</span>,0,1]]<br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs inform7">输入:nums = <span class="hljs-comment">[]</span><br>输出:<span class="hljs-comment">[]</span><br></code></pre></td></tr></table></figure><h3 id="示例-3"><a href="#示例-3" class="headerlink" title="示例 3"></a>示例 3</h3><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs inform7">输入:nums = <span class="hljs-comment">[0]</span><br>输出:<span class="hljs-comment">[]</span><br></code></pre></td></tr></table></figure><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param <span class="hljs-type">{number[]}</span> <span class="hljs-variable">nums</span></span></span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return <span class="hljs-type">{number[][]}</span></span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">var</span> threeSum = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">nums</span>) </span>{<br> <span class="hljs-keyword">let</span> ans = []<br> nums.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =></span> a - b)<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < nums.length; i++) {<br> <span class="hljs-keyword">if</span> (nums[i] > <span class="hljs-number">0</span>) <span class="hljs-keyword">break</span><br> <span class="hljs-keyword">if</span> (i > <span class="hljs-number">0</span> && nums[i] === nums[i - <span class="hljs-number">1</span>]) <span class="hljs-keyword">continue</span><br> <span class="hljs-keyword">let</span> target = -nums[i]<br> <span class="hljs-keyword">let</span> left = i + <span class="hljs-number">1</span>,<br> right = nums.length - <span class="hljs-number">1</span><br> <span class="hljs-keyword">while</span> (left < right) {<br> <span class="hljs-keyword">if</span> (nums[left] + nums[right] === target) {<br> ans.push([nums[i], nums[left], nums[right]])<br> left++<br> right--<br> <span class="hljs-keyword">while</span> (left < right && nums[left] === nums[left - <span class="hljs-number">1</span>]) {<br> left++<br> }<br> <span class="hljs-keyword">while</span> (left < right && nums[right] === nums[right + <span class="hljs-number">1</span>]) {<br> right--<br> }<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (nums[left] + nums[right] < target) {<br> left++<br> } <span class="hljs-keyword">else</span> {<br> right--<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> ans<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>删除链表的倒数第n个节点</title>
<link href="/2021/11/10/algorithm-test-11042/"/>
<url>/2021/11/10/algorithm-test-11042/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>给定一个链表,删除链表的倒数第 n 个节点并返回链表的头指针<br>例如,<br>给出的链表为: 1→2→3→4→5, n=2<br>删除了链表的倒数第 n 个节点之后, 链表变为1→2→3→5.</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight dust"><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></pre></td><td class="code"><pre><code class="hljs dust"><span class="xml">输入:</span><br><span class="xml"></span><span class="hljs-template-variable">{1,2}</span><span class="xml">,2 </span><br><span class="xml">返回值:</span><br><span class="xml"></span><span class="hljs-template-variable">{2}</span><br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>运用快慢指针的思想</li><li>让 faster 先走 n 步,再让 faster 和 slower 一起走,这样在 faster 走到链表结尾时,假设总的是 x 步,此时 slower走的步数是 x-n 步,那距离链表尾就是 x-(x-n) = n 步</li></ol><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/*</span><br><span class="hljs-comment"> * function ListNode(x){</span><br><span class="hljs-comment"> * this.val = x;</span><br><span class="hljs-comment"> * this.next = null;</span><br><span class="hljs-comment"> * }</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>head ListNode类 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>n int整型 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>ListNode类</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">removeNthFromEnd</span>(<span class="hljs-params">head, n</span>) </span>{<br> <span class="hljs-keyword">if</span> (head == <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> head<br> }<br> <span class="hljs-keyword">let</span> slower = head<br> <span class="hljs-keyword">let</span> faster = head<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < n; i++) {<br> faster = faster.next<br> }<br> <span class="hljs-comment">// 判断 n 是否大于 head 的长度</span><br> <span class="hljs-keyword">if</span> (faster == <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> head.next<br> }<br> <span class="hljs-keyword">while</span> (faster.next) {<br> faster = faster.next<br> slower = slower.next<br> }<br> slower.next = slower.next.next<br> <span class="hljs-keyword">return</span> head<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">removeNthFromEnd</span>: removeNthFromEnd<br>};<br></code></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>表达式求值</title>
<link href="/2021/11/08/algorithm-test-11041/"/>
<url>/2021/11/08/algorithm-test-11041/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>请写一个整数计算器,支持加减乘三种运算和括号。</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight 1c"><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></pre></td><td class="code"><pre><code class="hljs 1c">输入:<br><span class="hljs-string">"1+2"</span><br>返回值:<br><span class="hljs-number">3</span><br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight subunit"><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></pre></td><td class="code"><pre><code class="hljs subunit">输入:<br>"(2*(3<span class="hljs-string">-4</span>))*5"<br>返回值:<br><span class="hljs-string">-10</span><br></code></pre></td></tr></table></figure><h3 id="示例-3"><a href="#示例-3" class="headerlink" title="示例 3"></a>示例 3</h3><figure class="highlight subunit"><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></pre></td><td class="code"><pre><code class="hljs subunit">输入:<br>"3<span class="hljs-string">+2</span>*3*4<span class="hljs-string">-1</span>"<br>返回值:<br>26<br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>对于「任何表达式」而言,我们都使用两个栈 nums 和 ops:</p><ul><li>nums : 存放所有的数字</li><li>ops :存放所有的数字以外的操作</li></ul><p>然后从前往后做,对遍历到的字符做分情况讨论:</p><ul><li>空格 : 跳过</li><li>( : 直接加入 ops 中,等待与之匹配的 )</li><li>) : 使用现有的 nums 和 ops 进行计算,直到遇到左边最近的一个左括号为止,计算结果放到 nums<br>数字 : 从当前位置开始继续往后取,将整一个连续数字整体取出,加入 nums</li><li><code>+ - *</code> : 需要将操作放入 ops 中。在放入之前先把栈内可以算的都算掉(只有「栈内运算符」比「当前运算符」优先级高/同等,才进行运算),使用现有的 nums 和 ops 进行计算,直到没有操作或者遇到左括号,计算结果放到 nums<br>我们可以通过 🌰 来理解 只有「栈内运算符」比「当前运算符」优先级高/同等,才进行运算 是什么意思:</li></ul><p>因为我们是从前往后做的,假设我们当前已经扫描到 2 + 1 了(此时栈内的操作为 + )。</p><p>如果后面出现的 + 2 或者 - 1 的话,满足「栈内运算符」比「当前运算符」优先级高/同等,可以将 2 + 1 算掉,把结果放到 nums 中;<br>如果后面出现的是 * 2 的话,不满足「栈内运算符」比「当前运算符」优先级高/同等,这时候不能计算 2 + 1。</p><p>一些细节:</p><ul><li>由于第一个数可能是负数,为了减少边界判断。一个小技巧是先往 nums 添加一个 0</li><li>为防止 () 内出现的首个字符为运算符,将所有的空格去掉,并将 (- 替换为 (0-,(+ 替换为 (0+(当然也可以不进行这样的预处理,将这个处理逻辑放到循环里去做)</li><li>从理论上分析,nums 最好存放的是 long,而不是 int。因为可能存在 大数 + 大数 + 大数 + … - 大数 - 大数 的表达式导致中间结果溢出,最终答案不溢出的情况</li></ul><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可</span><br><span class="hljs-comment"> * 返回表达式的值</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>s string字符串 待计算的表达式</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>int整型</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">solve</span>(<span class="hljs-params">s</span>) </span>{<br> <span class="hljs-keyword">let</span> opsMap = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>([<br> [<span class="hljs-string">'+'</span>, <span class="hljs-number">1</span>],<br> [<span class="hljs-string">'-'</span>, <span class="hljs-number">1</span>],<br> [<span class="hljs-string">'*'</span>, <span class="hljs-number">2</span>]<br> ])<br> <span class="hljs-comment">// 将所有的空格去掉</span><br> s = s.replace(<span class="hljs-regexp">/^\s+/g</span>, <span class="hljs-string">""</span>)<br> <span class="hljs-comment">// 存放所有的数字</span><br> <span class="hljs-keyword">let</span> nums = []<br> <span class="hljs-comment">// 为了防止第一个数为负数,先往 nums 加个 0</span><br> nums.push(<span class="hljs-number">0</span>)<br> <span class="hljs-comment">// 存放操作符</span><br> <span class="hljs-keyword">let</span> ops = []<br><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < s.length; i++) {<br> <span class="hljs-keyword">if</span> (s[i] == <span class="hljs-string">'('</span>) {<br> ops.push(s[i])<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (s[i] == <span class="hljs-string">')'</span>) {<br> <span class="hljs-comment">// 计算到最近的一个左括号为止</span><br> <span class="hljs-keyword">while</span> (ops.length != <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">const</span> op = ops.pop()<br> <span class="hljs-keyword">if</span> (op != <span class="hljs-string">'('</span>) {<br> calc(nums, ops)<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">break</span><br> }<br> }<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">isNaN</span>(s[i])) {<br> <span class="hljs-keyword">let</span> u = <span class="hljs-number">0</span>,<br> j = i<br> <span class="hljs-comment">// 将从 i 位置开始后面的连续数字整体取出,加入 nums</span><br> <span class="hljs-keyword">while</span> (j < s.length && !<span class="hljs-built_in">isNaN</span>(s[j])) {<br> u = u * <span class="hljs-number">10</span> + <span class="hljs-built_in">Number</span>(s[j++])<br> nums.push(u)<br> i = j - <span class="hljs-number">1</span><br> }<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">if</span> (i > <span class="hljs-number">0</span> && s[i - <span class="hljs-number">1</span>] == <span class="hljs-string">'('</span> || s[i - <span class="hljs-number">1</span>] == <span class="hljs-string">'+'</span> || s[i - <span class="hljs-number">1</span>] == <span class="hljs-string">'-'</span>) {<br> nums.push(<span class="hljs-number">0</span>)<br> }<br> <span class="hljs-comment">// 有一个新操作要入栈时,先把栈内可以算的都算了</span><br> <span class="hljs-comment">// 只有满足「栈内运算符」比「当前运算符」优先级高/同等,才进行运算</span><br> <span class="hljs-keyword">while</span> (!(ops.length == <span class="hljs-number">0</span>) && s[s.length - <span class="hljs-number">1</span>] != <span class="hljs-string">'('</span>) {<br> <span class="hljs-keyword">const</span> prev = ops.pop()<br> <span class="hljs-keyword">if</span> (opsMap.get(prev) >= opsMap.get(s[i])) {<br> calc(nums, ops)<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">break</span><br> }<br> }<br> ops.push(s[i])<br> }<br> }<br> }<br> <span class="hljs-keyword">while</span> ((ops.length !== <span class="hljs-number">0</span>) && ops[ops.length - <span class="hljs-number">1</span>] != <span class="hljs-string">'('</span>) {<br> calc(nums, ops)<br> }<br> <span class="hljs-keyword">return</span> nums.pop()<br>}<br><br><span class="hljs-comment">// 计算逻辑:从 nums 中取出两个操作数,从 ops 中取出运算符,然后根据运算符计算</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calc</span>(<span class="hljs-params">nums, ops</span>) </span>{<br> <span class="hljs-keyword">if</span> (nums.length < <span class="hljs-number">2</span>) <span class="hljs-keyword">return</span><br> <span class="hljs-keyword">if</span> (ops.length == <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span><br> <span class="hljs-keyword">let</span> b = nums.pop(),<br> a = nums.pop()<br> <span class="hljs-keyword">let</span> op = ops.pop()<br> <span class="hljs-keyword">let</span> ans = <span class="hljs-number">0</span><br> <span class="hljs-keyword">if</span> (op == <span class="hljs-string">'+'</span>) {<br> ans = a + b<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (op == <span class="hljs-string">'-'</span>) {<br> ans = a - b<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (op == <span class="hljs-string">'*'</span>) {<br> ans = a * b<br> }<br> nums.push(ans)<br>}<br><br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">solve</span>: solve<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>大数加法</title>
<link href="/2021/11/04/algorithm-test-1104/"/>
<url>/2021/11/04/algorithm-test-1104/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight routeros"><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><code class="hljs routeros">输入:<br><span class="hljs-string">"1"</span>,<span class="hljs-string">"99"</span><br>返回值:<br><span class="hljs-string">"100"</span><br>说明:<br>1+<span class="hljs-attribute">99</span>=100 <br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight 1c"><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></pre></td><td class="code"><pre><code class="hljs 1c">输入:<br><span class="hljs-string">"114514"</span>,<span class="hljs-string">""</span><br>返回值:<br><span class="hljs-string">"114514"</span><br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>先把两个数补全至相同长度,不够长的前面补 0</li><li>从个位开始加,大于 10 的进 1,小于 10 的取余数</li><li>当最后 carry 等于 1 时,需要再进一位</li></ol><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可</span><br><span class="hljs-comment"> * 计算两个数之和</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>s string字符串 表示第一个整数</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>t string字符串 表示第二个整数</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>string字符串</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">solve</span>(<span class="hljs-params">s, t</span>) </span>{<br> <span class="hljs-keyword">if</span> (s === <span class="hljs-string">''</span> || t === <span class="hljs-string">''</span>) {<br> <span class="hljs-keyword">return</span> s + t<br> }<br> <span class="hljs-keyword">let</span> m = s.length,<br> n = t.length,<br> res = []<br> <span class="hljs-keyword">while</span> (m < n) {<br> s = <span class="hljs-string">'0'</span> + s<br> m = s.length<br> }<br> <span class="hljs-keyword">while</span> (m > n) {<br> t = <span class="hljs-string">'0'</span> + t<br> n = t.length<br> }<br> <span class="hljs-keyword">let</span> carry = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-built_in">Math</span>.max(m, n) - <span class="hljs-number">1</span>; i >= <span class="hljs-number">0</span>; i--) {<br> <span class="hljs-keyword">let</span> temp = <span class="hljs-built_in">parseInt</span>(s[i]) + <span class="hljs-built_in">parseInt</span>(t[i]) + carry<br> carry = <span class="hljs-built_in">Math</span>.floor(temp / <span class="hljs-number">10</span>) > <span class="hljs-number">0</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span><br> res.unshift(temp % <span class="hljs-number">10</span>)<br> }<br> <span class="hljs-keyword">if</span> (carry == <span class="hljs-number">1</span>) {<br> res.unshift(<span class="hljs-number">1</span>)<br> }<br> <span class="hljs-keyword">return</span> res.join(<span class="hljs-string">''</span>)<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">solve</span>: solve<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>在二叉树中找到两个节点的最近公共祖先</title>
<link href="/2021/11/03/algorithm-test-1103/"/>
<url>/2021/11/03/algorithm-test-1103/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。</p><p>注:本题保证二叉树中每个节点的val值均不相同。</p><p>如当输入[3,5,1,6,2,0,8,#,#,7,4],5,1时,二叉树{3,5,1,6,2,0,8,#,#,7,4}如下图所示:</p><p><img src="https://uploadfiles.nowcoder.com/images/20211014/423483716_1634206667843/D2B5CA33BD970F64A6301FA75AE2EB22" alt="二叉树"></p><p>所以节点值为5和节点值为1的节点的最近公共祖先节点的节点值为3,所以对应的输出为3。</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight clean"><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></pre></td><td class="code"><pre><code class="hljs clean">输入:<br>[<span class="hljs-number">3</span>,<span class="hljs-number">5</span>,<span class="hljs-number">1</span>,<span class="hljs-number">6</span>,<span class="hljs-number">2</span>,<span class="hljs-number">0</span>,<span class="hljs-number">8</span>,#,#,<span class="hljs-number">7</span>,<span class="hljs-number">4</span>],<span class="hljs-number">5</span>,<span class="hljs-number">1</span><br>返回值:<br><span class="hljs-number">3</span><br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>从头往下找,当 root 为空,或者 root.val 等于 o1 或者 o2 时,返回 root</li><li>当 left 为空时,则这两个节点在 root 节点的右子树上,直接从右子树查找</li><li>当 right 为空时,则这两个节点在 root 节点的左子树上,直接从左子树查找</li><li>当都不为空时,则一个在左子树,一个在右子树上,返回 root 节点即可</li></ol><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/*</span><br><span class="hljs-comment"> * function TreeNode(x) {</span><br><span class="hljs-comment"> * this.val = x;</span><br><span class="hljs-comment"> * this.left = null;</span><br><span class="hljs-comment"> * this.right = null;</span><br><span class="hljs-comment"> * }</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>root TreeNode类 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>o1 int整型 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>o2 int整型 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>int整型</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">lowestCommonAncestor</span>(<span class="hljs-params">root, o1, o2</span>) </span>{<br> <span class="hljs-keyword">return</span> helper(root, o1, o2).val<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">helper</span>(<span class="hljs-params">root, o1, o2</span>) </span>{<br> <span class="hljs-keyword">if</span> (root == <span class="hljs-literal">null</span> || root.val === o1 || root.val === o2) {<br> <span class="hljs-keyword">return</span> root<br> }<br> <span class="hljs-keyword">let</span> left = helper(root.left, o1, o2)<br> <span class="hljs-keyword">let</span> right = helper(root.right, o1, o2)<br> <span class="hljs-keyword">if</span> (left == <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> right<br> }<br> <span class="hljs-keyword">if</span> (right == <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">return</span> left<br> }<br> <span class="hljs-keyword">return</span> root<br>}<br><br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">lowestCommonAncestor</span>: lowestCommonAncestor<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>连续子数组的最大和</title>
<link href="/2021/11/02/algorithm-test-11021/"/>
<url>/2021/11/02/algorithm-test-11021/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>输入一个长度为n的整型数组a,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为 O(n)</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight subunit"><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><code class="hljs subunit">输入:<br>[1,<span class="hljs-string">-2</span>,3,10,<span class="hljs-string">-4</span>,7,2,<span class="hljs-string">-5</span>]<br>返回值:<br>18<br>说明:<br>经分析可知,输入数组的子数组[3,10,<span class="hljs-string">-4</span>,7,2]可以求得最大和为18<br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight angelscript"><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></pre></td><td class="code"><pre><code class="hljs angelscript">输入:<br><span class="hljs-string">[2]</span><br>返回值:<br><span class="hljs-number">2</span><br></code></pre></td></tr></table></figure><h3 id="示例-3"><a href="#示例-3" class="headerlink" title="示例 3"></a>示例 3</h3><figure class="highlight subunit"><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></pre></td><td class="code"><pre><code class="hljs subunit">输入:<br>[<span class="hljs-string">-10</span>]<br>返回值:<br><span class="hljs-string">-10</span><br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>动态规划,动态规划方程:dp[i] = max(dp[i-1]+array[i], array[i])</li></ol><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FindGreatestSumOfSubArray</span>(<span class="hljs-params">array</span>) </span>{<br> <span class="hljs-keyword">if</span> (array.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span><br> }<br> <span class="hljs-keyword">let</span> max = array[<span class="hljs-number">0</span>]<br> <span class="hljs-keyword">let</span> dp = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(array.length).fill(<span class="hljs-number">0</span>)<br> dp[<span class="hljs-number">0</span>] = max<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i < array.length; i++) {<br> dp[i] = <span class="hljs-built_in">Math</span>.max(dp[i - <span class="hljs-number">1</span>] + array[i], array[i])<br> max = <span class="hljs-built_in">Math</span>.max(dp[i], max)<br> }<br> <span class="hljs-keyword">return</span> max<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">FindGreatestSumOfSubArray</span>: FindGreatestSumOfSubArray<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>二分查找-II</title>
<link href="/2021/11/02/algorithm-test-1102/"/>
<url>/2021/11/02/algorithm-test-1102/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>请实现有重复数字的升序数组的二分查找<br>给定一个 元素有序的(升序)长度为n的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight accesslog"><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><code class="hljs accesslog">输入:<br><span class="hljs-string">[1,2,4,4,5]</span>,<span class="hljs-number">4</span><br>返回值:<br><span class="hljs-number">2</span><br>说明:<br>从左到右,查找到第<span class="hljs-number">1</span>个为<span class="hljs-number">4</span>的,下标为<span class="hljs-number">2</span>,返回<span class="hljs-number">2</span> <br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight accesslog"><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></pre></td><td class="code"><pre><code class="hljs accesslog">输入:<br><span class="hljs-string">[1,2,4,4,5]</span>,<span class="hljs-number">3</span><br>返回值:<br>-<span class="hljs-number">1</span><br></code></pre></td></tr></table></figure><h3 id="示例-3"><a href="#示例-3" class="headerlink" title="示例 3"></a>示例 3</h3><figure class="highlight accesslog"><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></pre></td><td class="code"><pre><code class="hljs accesslog">输入:<br><span class="hljs-string">[1,1,1,1,1]</span>,<span class="hljs-number">1</span><br>返回值:<br><span class="hljs-number">0</span><br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>二分法查找</li><li>当中间数是 target 时,res 先等于 mid,但可能左边的数才是第一个,所以要 right = mid - 1。</li><li>当中间数小于 target 时,res 肯定在中间数的右侧,所以 left = mid + 1。</li><li>当中间数大于 target 时,res 肯定在中间数的右侧,所以 right = mid - 1</li></ol><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * 如果目标值存在返回下标,否则返回 -1</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>nums int整型一维数组 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>target int整型 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>int整型</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params">nums, target</span>) </span>{<br> <span class="hljs-keyword">if</span> (nums.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">let</span> left = <span class="hljs-number">0</span>,<br> right = nums.length - <span class="hljs-number">1</span>;<br> <span class="hljs-keyword">let</span> mid;<br> <span class="hljs-keyword">let</span> res = -<span class="hljs-number">1</span>;<br> <span class="hljs-keyword">while</span> (left <= right) {<br> mid = <span class="hljs-built_in">Math</span>.floor((right + left) / <span class="hljs-number">2</span>);<br> <span class="hljs-keyword">if</span> (nums[mid] === target) {<br> right = mid - <span class="hljs-number">1</span><br> res = mid<br> }<br> <span class="hljs-keyword">if</span> (nums[mid] < target) {<br> left = mid + <span class="hljs-number">1</span><br> }<br> <span class="hljs-keyword">if</span> (nums[mid] > target) {<br> right = mid - <span class="hljs-number">1</span><br> }<br> }<br> <span class="hljs-keyword">return</span> res;<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">search</span>: search<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>快应用如何增强语法检查能力</title>
<link href="/2021/10/28/language-check/"/>
<url>/2021/10/28/language-check/</url>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>虽然在快应用开发工具里,已经集成了语法提示、自动补全等能力,但如果您想对项目的代码进行进一步校验,给代码定义一个规范,必须按照这个规范进行代码的编写,可以通过使用 eslint,并结合 husky、lint-staged 插件来增强语法检查。</p><h2 id="使用-eslint"><a href="#使用-eslint" class="headerlink" title="使用 eslint"></a>使用 eslint</h2><h3 id="安装依赖"><a href="#安装依赖" class="headerlink" title="安装依赖"></a>安装依赖</h3><p>需要全局安装 eslint 或者只在当前项目下安装 eslint</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm i eslint -g<br></code></pre></td></tr></table></figure><p>或</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm i eslint --save-dev<br></code></pre></td></tr></table></figure><p>由于会用到 <code>eslint-plugin-vue</code> 的能力,所以我们也要在项目下安装 <code>eslint-plugin-vue</code> 依赖:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm i eslint-plugin-vue --save-dev<br></code></pre></td></tr></table></figure><h3 id="新建-eslint-配置文件"><a href="#新建-eslint-配置文件" class="headerlink" title="新建 eslint 配置文件"></a>新建 eslint 配置文件</h3><p>在项目根目录下,新建 .eslintrc 文件,并编写配置,下面为简单的配置项,若项目中有额外的要求,可根据 vue 的规则自己额外配置。</p><figure class="highlight json"><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></pre></td><td class="code"><pre><code class="hljs json">{<br> <span class="hljs-attr">"env"</span>: {<br> <span class="hljs-attr">"commonjs"</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">"node"</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">"es6"</span>: <span class="hljs-literal">true</span><br> },<br> <span class="hljs-attr">"extends"</span>: [<br> <span class="hljs-string">"eslint:recommended"</span>,<br> <span class="hljs-string">"plugin:vue/base"</span><br> ],<br> <span class="hljs-attr">"globals"</span>: {<br> <span class="hljs-attr">"loadData"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-attr">"saveData"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-attr">"history"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-attr">"console"</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">"setTimeout"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-attr">"clearTimeout"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-attr">"setInterval"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-attr">"clearInterval"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-attr">"TextDecoder"</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">"$utils"</span>: <span class="hljs-literal">true</span><br> },<br> <span class="hljs-attr">"rules"</span>: {<br> <span class="hljs-attr">"vue/html-end-tags"</span>: <span class="hljs-string">"warn"</span>,<br> <span class="hljs-attr">"vue/html-quotes"</span>: <span class="hljs-string">"warn"</span>,<br> <span class="hljs-attr">"vue/comment-directive"</span>: <span class="hljs-string">"off"</span>,<br> <span class="hljs-attr">"no-unused-vars"</span>: [<br> <span class="hljs-string">"warn"</span>,<br> {<br> <span class="hljs-attr">"varsIgnorePattern"</span>: <span class="hljs-string">"prompt"</span><br> }<br> ],<br> <span class="hljs-attr">"quotes"</span>: [<br> <span class="hljs-string">"warn"</span>,<br> <span class="hljs-string">"single"</span>,<br> {<br> <span class="hljs-attr">"avoidEscape"</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">"allowTemplateLiterals"</span>: <span class="hljs-literal">true</span><br> }<br> ],<br> <span class="hljs-attr">"linebreak-style"</span>: [<span class="hljs-string">"warn"</span>, <span class="hljs-string">"unix"</span>],<br> <span class="hljs-attr">"semi"</span>: [<span class="hljs-number">1</span>, <span class="hljs-string">"never"</span>]<br> }<br>}<br></code></pre></td></tr></table></figure><p>注意: 配置中需要关闭 <code>vue/commet/directive</code>。</p><h3 id="增加-script-脚本命令"><a href="#增加-script-脚本命令" class="headerlink" title="增加 script 脚本命令"></a>增加 script 脚本命令</h3><figure class="highlight json"><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><code class="hljs json"><span class="hljs-string">"scripts"</span>: {<br> <span class="hljs-attr">"lint"</span>: <span class="hljs-string">"eslint 'src/**/*.ux'"</span><br>}<br></code></pre></td></tr></table></figure><p>在终端运行 <code>npm run lint</code>,即可用 eslint 对 src 下所有的 ux 文件进行语法检查。</p><h2 id="使用-husky、lint-staged-插件"><a href="#使用-husky、lint-staged-插件" class="headerlink" title="使用 husky、lint-staged 插件"></a>使用 husky、lint-staged 插件</h2><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>执行下面命令</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm i husky lint-staged --save-dev<br></code></pre></td></tr></table></figure><h3 id="husky"><a href="#husky" class="headerlink" title="husky"></a>husky</h3><p>在成功安装之后,我们可以在 git commit 的时候触发 pre-commit 钩子从而触发到 husky,我们在 package.json 文件中配置 husky 的钩子需要执行的命令或操作。</p><figure class="highlight json"><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><code class="hljs json"><span class="hljs-string">"husky"</span>: {<br> <span class="hljs-attr">"hooks"</span>: {<br> <span class="hljs-attr">"pre-commit"</span>: <span class="hljs-string">"yarn run precommit-msg && lint-staged"</span><br> }<br>}<br></code></pre></td></tr></table></figure><p>这样,我们在 git commit 的时候就会看到 pre-commit 执行了。</p><p><img src="https://zhanstatic.vivo.com.cn/wukong/img/23945cdb-8c01-46d6-a14d-956eeebf1747.jpg" alt="pre-commit"></p><p><strong>注意:</strong>新版本的 husky 可能无法生效,降低 husky 版本即可,本文采用的是 <a href="mailto:husky@4.3.8">husky@4.3.8</a> 版本</p><h3 id="lint-staged"><a href="#lint-staged" class="headerlink" title="lint-staged"></a>lint-staged</h3><p>lint-staged 是一个在 git 暂存文件上(也就是被 git add 的文件)运行已配置的 linter(或其他)任务。lint-staged 总是将所有暂存文件的列表传递给任务。</p><p>我们在 package.json 文件中配置</p><figure class="highlight json"><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><code class="hljs json"><span class="hljs-string">"lint-staged"</span>: {<br> <span class="hljs-attr">"**/**.{ux,js,json,less,scss,css,pcss,md,vue}"</span>: [<br> <span class="hljs-string">"prettier --write"</span>,<br> <span class="hljs-string">"eslint 'src/**/*.ux'"</span>,<br> <span class="hljs-string">"git add"</span><br> ]<br>}<br></code></pre></td></tr></table></figure><p>这里 lint-staged 的配置是:在 git 的待提交的文件中,所有 ux,js,json,less,scss,css,pcss,md,vue 文件都要执行两条命令在 commit 之前,将暂存区的内容做一次代码美化和 eslint 格式检查,然后再添加到暂存区。</p><p>结合我们前面介绍的 husky,配合 husky 的 pre-commit 钩子,将会形成一个自动化工具链。</p><h2 id="使用-hap-eslint-插件"><a href="#使用-hap-eslint-插件" class="headerlink" title="使用 hap-eslint 插件"></a>使用 hap-eslint 插件</h2><h3 id="安装插件"><a href="#安装插件" class="headerlink" title="安装插件"></a>安装插件</h3><p>在商店搜索 hap-eslint,点击「安装」,即可安装快应用的 eslint 插件,该插件会检测项目下是否配置了 eslint,从而来对 ux 文件以及 js 文件进行静态语法检查。</p><p><strong>注意:</strong>建议安装 7.x 版本的 eslint。</p><h3 id="启用-eslint"><a href="#启用-eslint" class="headerlink" title="启用 eslint"></a>启用 eslint</h3><p>点击底部状态栏的 eslint 状态,根据提示选择 eslint 的作用范围。至此,您已经可以在项目中使用 eslint 了。</p><p><img src="https://zhanstatic.vivo.com.cn/wukong/img/34e85452-792a-4663-ab4e-cc87bfa568a0.jpg" alt="启用 eslint"></p><h3 id="启用保存时自动-Fix"><a href="#启用保存时自动-Fix" class="headerlink" title="启用保存时自动 Fix"></a>启用保存时自动 Fix</h3><p>在设置中搜索: <code>eslint: auto fix on save</code>,勾选这个选项,则可以在保存文件时,自动根据配置格式化代码。</p><p><img src="https://zhanstatic.vivo.com.cn/wukong/img/49a7ed12-1949-4ead-8546-341016074272.jpg" alt="启用保存时自动fix"></p><h3 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h3><p><img src="https://zhanstatic.vivo.com.cn/wukong/img/c58e0341-255b-47a6-9285-1bfa09b2cdda.gif" alt="效果"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文介绍了在快应用中如何运用 eslint 结合 husky 和 lint-staged 来对代码进行加强语法检查并规定整个项目的代码风格,十分方便,而且能使项目的代码更加规范。</p>]]></content>
<categories>
<category>快应用</category>
</categories>
</entry>
<entry>
<title>判断链表中是否有环</title>
<link href="/2021/10/28/algorithm-test-1027/"/>
<url>/2021/10/28/algorithm-test-1027/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>判断给定的链表中是否有环。如果有环则返回true,否则返回false。</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight subunit"><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><code class="hljs subunit">输入:<br>{3,2,0,<span class="hljs-string">-4</span>},1<br>返回值:<br>true<br>说明:<br>第一部分{3,2,0,<span class="hljs-string">-4</span>}代表一个链表,第二部分的1表示,<span class="hljs-string">-4</span>到位置1,即<span class="hljs-string">-4</span>->2存在一个链接,组成传入的head为一个带环的链表 ,返回true <br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight xquery"><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><code class="hljs xquery">输入:<br>{<span class="hljs-number">1</span>},-<span class="hljs-number">1</span><br>返回值:<span class="hljs-built_in"></span><br><span class="hljs-built_in">false</span><br>说明:<br>第一部分{<span class="hljs-number">1</span>}代表一个链表,-<span class="hljs-number">1</span>代表无环,组成传<span class="hljs-built_in">入head</span>为一个无环的单链表,返<span class="hljs-built_in">回false</span><br></code></pre></td></tr></table></figure><h3 id="示例-3"><a href="#示例-3" class="headerlink" title="示例 3"></a>示例 3</h3><figure class="highlight subunit"><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></pre></td><td class="code"><pre><code class="hljs subunit">输入:<br>{<span class="hljs-string">-1</span>,<span class="hljs-string">-7</span>,7,<span class="hljs-string">-4</span>,19,6,<span class="hljs-string">-9</span>,<span class="hljs-string">-5</span>,<span class="hljs-string">-2</span>,<span class="hljs-string">-5</span>},6<br>返回值:<br>true<br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>运用快慢指针,当两个指针相遇时,就是有环,否则是无环</p><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/*</span><br><span class="hljs-comment"> * function ListNode(x){</span><br><span class="hljs-comment"> * this.val = x;</span><br><span class="hljs-comment"> * this.next = null;</span><br><span class="hljs-comment"> * }</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>head ListNode类 </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>bool布尔型</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hasCycle</span>(<span class="hljs-params">head</span>) </span>{<br> <span class="hljs-keyword">if</span> (!head) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br> }<br> <span class="hljs-keyword">let</span> faster = head,<br> slower = head<br> <span class="hljs-keyword">while</span> (faster && faster.next) {<br> faster = faster.next.next<br> slower = slower.next<br> <span class="hljs-keyword">if</span> (faster = slower) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">hasCycle</span>: hasCycle<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>最长无重复子数组</title>
<link href="/2021/10/26/algorithm-test-1026/"/>
<url>/2021/10/26/algorithm-test-1026/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>给定一个数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。<br>子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight angelscript"><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><code class="hljs angelscript">输入:<br><span class="hljs-string">[2,3,4,5]</span><br>返回值:<br><span class="hljs-number">4</span><br>说明:<br><span class="hljs-string">[2,3,4,5]</span>是最长子数组 <br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight angelscript"><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><code class="hljs angelscript">输入:<br><span class="hljs-string">[2,2,3,4,3]</span><br>返回值:<br><span class="hljs-number">3</span><br>说明:<br><span class="hljs-string">[2,3,4]</span>是最长子数组 <br></code></pre></td></tr></table></figure><h3 id="示例-3"><a href="#示例-3" class="headerlink" title="示例 3"></a>示例 3</h3><figure class="highlight angelscript"><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></pre></td><td class="code"><pre><code class="hljs angelscript">输入:<br><span class="hljs-string">[9]</span><br>返回值:<br><span class="hljs-number">1</span><br></code></pre></td></tr></table></figure><h3 id="示例-4"><a href="#示例-4" class="headerlink" title="示例 4"></a>示例 4</h3><figure class="highlight css"><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><code class="hljs css">输入:<br><span class="hljs-selector-attr">[1,2,3,1,2,3,2,2]</span><br>返回值:<br><span class="hljs-number">3</span><br>说明:<br>最长子数组为<span class="hljs-selector-attr">[1,2,3]</span> <br></code></pre></td></tr></table></figure><h3 id="示例-5"><a href="#示例-5" class="headerlink" title="示例 5"></a>示例 5</h3><figure class="highlight accesslog"><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><code class="hljs accesslog">输入:<br><span class="hljs-string">[2,2,3,4,8,99,3]</span><br>返回值:<br><span class="hljs-number">5</span><br>说明:<br>最长子数组为<span class="hljs-string">[2,3,4,8,99]</span><br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>用双指针 + 哈希来做</li><li>当数组大小小于等于 1 时返回数组大小</li><li>用 map 来存储数组值对应的下标</li><li>当数组中的值在 map 中有时,把 start 指针指向 end 所在的位置,并 end + 1</li><li>当数组中的值在 map 中没有时,只需要把 end 指针向后移动</li><li>当 end 的值到末尾时退出循环</li></ol><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * </span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>arr int整型一维数组 the array</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>int整型</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">maxLength</span>(<span class="hljs-params">arr</span>) </span>{<br> <span class="hljs-keyword">if</span> (arr.length <= <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">return</span> arr.length<br> }<br> <span class="hljs-keyword">let</span> start = <span class="hljs-number">0</span>,<br> end = <span class="hljs-number">0</span>,<br> max = <span class="hljs-number">0</span><br> <span class="hljs-keyword">const</span> cacheMap = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">while</span> (end < arr.length) {<br> cacheMap.set(arr[end], end)<br> <span class="hljs-keyword">if</span> (cacheMap.has(arr[end])) {<br> max = <span class="hljs-built_in">Math</span>.max(end - start, max)<br> start = cacheMap.get(arr[end])<br> end = start + <span class="hljs-number">1</span><br> } <span class="hljs-keyword">else</span> {<br> end++<br> }<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.max(end - start, max)<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">maxLength</span>: maxLength<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>用两个栈实现队列</title>
<link href="/2021/10/25/algorithm-test-1025/"/>
<url>/2021/10/25/algorithm-test-1025/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。</p><p>数据范围: n≤1000<br>要求:存储n个元素的空间复杂度为 O(n)O(n) ,插入与删除的时间复杂度都是 O(1)O(1)</p><h3 id="示例1"><a href="#示例1" class="headerlink" title="示例1"></a>示例1</h3><figure class="highlight 1c"><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></pre></td><td class="code"><pre><code class="hljs 1c">输入:<br>[<span class="hljs-string">"PSH1"</span>,<span class="hljs-string">"PSH2"</span>,<span class="hljs-string">"POP"</span>,<span class="hljs-string">"POP"</span>]<br>返回值:<br><span class="hljs-number">1</span>,<span class="hljs-number">2</span><br>说明:<br><span class="hljs-string">"PSH1"</span>:代表将<span class="hljs-number">1</span>插入队列尾部<br><span class="hljs-string">"PSH2"</span>:代表将<span class="hljs-number">2</span>插入队列尾部<br><span class="hljs-string">"POP“:代表删除一个元素,先进先出=>返回1</span><br><span class="hljs-string">"POP“:代表删除一个元素,先进先出=>返回2 </span><br></code></pre></td></tr></table></figure><h3 id="示例2"><a href="#示例2" class="headerlink" title="示例2"></a>示例2</h3><figure class="highlight csharp"><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></pre></td><td class="code"><pre><code class="hljs csharp">输入:<br>[<span class="hljs-meta"><span class="hljs-meta-string">"PSH2"</span>,<span class="hljs-meta-string">"POP"</span>,<span class="hljs-meta-string">"PSH1"</span>,<span class="hljs-meta-string">"POP"</span></span>]<br>返回值:<br><span class="hljs-number">2</span>,<span class="hljs-number">1</span><br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>两个栈用数组来表示</li><li>push 方法:直接往 stack1 中 push 元素</li><li>pop 方法:把 stack2 当做中转站,当 stack2 中有元素的时候,就直接 pop 出来,当 stack2 中没有元素的时候,要把 stack1 的元素从尾到头放入到 stack2 中,然后再 pop 最后的一个元素,并返回。</li></ol><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">const</span> stack1 = []<br><span class="hljs-keyword">const</span> stack2 = []<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">push</span>(<span class="hljs-params">node</span>)</span><br><span class="hljs-function"></span>{<br> stack1.push(node)<br>}<br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pop</span>(<span class="hljs-params"></span>)</span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span>(stack2.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">while</span>(stack1.length !== <span class="hljs-number">0</span>) {<br> stack2.push(stack1.pop())<br> }<br> }<br> <span class="hljs-keyword">return</span> stack2.pop()<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">push</span> : push,<br> <span class="hljs-attr">pop</span> : pop<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>设计LRU缓存结构</title>
<link href="/2021/10/24/algorithm-test-1024/"/>
<url>/2021/10/24/algorithm-test-1024/</url>
<content type="html"><![CDATA[<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><p>设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 k ,并有如下两个功能</p><ol><li>set(key, value):将记录(key, value)插入该结构</li><li>get(key):返回key对应的value值</li></ol><p>提示:<br>1.某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的,然后都会刷新缓存。<br>2.当缓存的大小超过k时,移除最不经常使用的记录。<br>3.输入一个二维数组与k,二维数组每一维有2个或者3个数字,第1个数字为opt,第2,3个数字为key,value<br>若opt=1,接下来两个整数key, value,表示set(key, value)<br>若opt=2,接下来一个整数key,表示get(key),若key未出现过或已被移除,则返回-1<br>对于每个opt=2,输出一个答案<br>4.为了方便区分缓存里key与value,下面说明的缓存里key用””号包裹</p><p>要求:set和get操作复杂度均为 O(1)O(1)</p><h3 id="示例-1"><a href="#示例-1" class="headerlink" title="示例 1"></a>示例 1</h3><figure class="highlight prolog"><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></pre></td><td class="code"><pre><code class="hljs prolog">输入:<br>[[<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">2</span>],[<span class="hljs-number">1</span>,<span class="hljs-number">3</span>,<span class="hljs-number">2</span>],[<span class="hljs-number">2</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">1</span>,<span class="hljs-number">4</span>,<span class="hljs-number">4</span>],[<span class="hljs-number">2</span>,<span class="hljs-number">2</span>]],<span class="hljs-number">3</span><br>返回值:<br>[<span class="hljs-number">1</span>,<span class="hljs-number">-1</span>]<br>说明:<br>[<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>],第一个<span class="hljs-number">1</span>表示opt=<span class="hljs-number">1</span>,要set(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>),即将(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>)插入缓存,缓存是{<span class="hljs-string">"1"</span>=<span class="hljs-number">1</span>}<br>[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">2</span>],第一个<span class="hljs-number">1</span>表示opt=<span class="hljs-number">1</span>,要set(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>),即将(<span class="hljs-number">2</span>,<span class="hljs-number">2</span>)插入缓存,缓存是{<span class="hljs-string">"1"</span>=<span class="hljs-number">1</span>,<span class="hljs-string">"2"</span>=<span class="hljs-number">2</span>}<br>[<span class="hljs-number">1</span>,<span class="hljs-number">3</span>,<span class="hljs-number">2</span>],第一个<span class="hljs-number">1</span>表示opt=<span class="hljs-number">1</span>,要set(<span class="hljs-number">3</span>,<span class="hljs-number">2</span>),即将(<span class="hljs-number">3</span>,<span class="hljs-number">2</span>)插入缓存,缓存是{<span class="hljs-string">"1"</span>=<span class="hljs-number">1</span>,<span class="hljs-string">"2"</span>=<span class="hljs-number">2</span>,<span class="hljs-string">"3"</span>=<span class="hljs-number">2</span>}<br>[<span class="hljs-number">2</span>,<span class="hljs-number">1</span>],第一个<span class="hljs-number">2</span>表示opt=<span class="hljs-number">2</span>,要get(<span class="hljs-number">1</span>),返回是[<span class="hljs-number">1</span>],因为get(<span class="hljs-number">1</span>)操作,缓存更新,缓存是{<span class="hljs-string">"2"</span>=<span class="hljs-number">2</span>,<span class="hljs-string">"3"</span>=<span class="hljs-number">2</span>,<span class="hljs-string">"1"</span>=<span class="hljs-number">1</span>}<br>[<span class="hljs-number">1</span>,<span class="hljs-number">4</span>,<span class="hljs-number">4</span>],第一个<span class="hljs-number">1</span>表示opt=<span class="hljs-number">1</span>,要set(<span class="hljs-number">4</span>,<span class="hljs-number">4</span>),即将(<span class="hljs-number">4</span>,<span class="hljs-number">4</span>)插入缓存,但是缓存已经达到最大容量<span class="hljs-number">3</span>,移除最不经常使用的{<span class="hljs-string">"2"</span>=<span class="hljs-number">2</span>},插入{<span class="hljs-string">"4"</span>=<span class="hljs-number">4</span>},缓存是{<span class="hljs-string">"3"</span>=<span class="hljs-number">2</span>,<span class="hljs-string">"1"</span>=<span class="hljs-number">1</span>,<span class="hljs-string">"4"</span>=<span class="hljs-number">4</span>}<br>[<span class="hljs-number">2</span>,<span class="hljs-number">2</span>],第一个<span class="hljs-number">2</span>表示opt=<span class="hljs-number">2</span>,要get(<span class="hljs-number">2</span>),查找不到,返回是[<span class="hljs-number">1</span>,<span class="hljs-number">-1</span>] <br></code></pre></td></tr></table></figure><h3 id="示例-2"><a href="#示例-2" class="headerlink" title="示例 2"></a>示例 2</h3><figure class="highlight inform7"><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></pre></td><td class="code"><pre><code class="hljs inform7">输入:<br><span class="hljs-comment">[<span class="hljs-comment">[1,1,1]</span>,<span class="hljs-comment">[1,2,2]</span>,<span class="hljs-comment">[2,1]</span>,<span class="hljs-comment">[1,3,3]</span>,<span class="hljs-comment">[2,2]</span>,<span class="hljs-comment">[1,4,4]</span>,<span class="hljs-comment">[2,1]</span>,<span class="hljs-comment">[2,3]</span>,<span class="hljs-comment">[2,4]</span>]</span>,2<br>返回值:<br><span class="hljs-comment">[1,-1,-1,3,4]</span><br></code></pre></td></tr></table></figure><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><ol><li>用一个 map 来存储 cache 值,result 存储返回值</li><li>遍历所有的 operators,分 set 和 get 操作</li><li>set: 当 cache 的 size 小于 k 时,如果 cache 中有这个值,则删除这个值,并重新添加到 map 的末尾<br>当 cache 的 size 大于等于 k 时,如果 cache 中有这个值,则删除这个值,并重新添加到 map 的末尾;当不存在<br>这个值时,需要删除 map 中第一个元素,然后再添加到 map 的末尾。</li><li>get: 当 cache 中有这个值时,添加到 result 数组中,并把 cache 中这个 key 的值删除,重新添加到末尾(已被使用)。</li></ol><h2 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * lru design</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>operators int整型二维数组 the ops</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param </span>k int整型 the k</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return </span>int整型一维数组</span><br><span class="hljs-comment"> */</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LRU</span>(<span class="hljs-params">operators, k</span>) </span>{<br> <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>()<br> <span class="hljs-keyword">const</span> result = []<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>, n = operators.length; i < n; i++) {<br> <span class="hljs-keyword">const</span> item = operators[i]<br> <span class="hljs-comment">// set</span><br> <span class="hljs-keyword">if</span> (item[<span class="hljs-number">0</span>] === <span class="hljs-number">1</span>) {<br> <span class="hljs-keyword">if</span> (cache.size < k) {<br> <span class="hljs-comment">// map 结构里有这个值,删除,添加新值到最后</span><br> <span class="hljs-keyword">if</span> (cache.has(item[<span class="hljs-number">1</span>])) {<br> cache.delete(item[<span class="hljs-number">1</span>])<br> cache.set(item[<span class="hljs-number">1</span>], item[<span class="hljs-number">2</span>])<br> } <span class="hljs-keyword">else</span> {<br> cache.set(item[<span class="hljs-number">1</span>], item[<span class="hljs-number">2</span>])<br> }<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">if</span> (cache.has(item[<span class="hljs-number">1</span>])) {<br> cache.delete(item[<span class="hljs-number">1</span>])<br> cache.set(item[<span class="hljs-number">1</span>], item[<span class="hljs-number">2</span>])<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">// 删除第一个数,然后添加到末尾</span><br> <span class="hljs-keyword">const</span> firstKey = cache.entries().next().value[<span class="hljs-number">0</span>]<br> cache.delete(firstKey)<br> cache.set(item[<span class="hljs-number">1</span>], item[<span class="hljs-number">2</span>])<br> }<br> }<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (item[<span class="hljs-number">0</span>] === <span class="hljs-number">2</span>) {<br> <span class="hljs-keyword">if</span> (cache.has(item[<span class="hljs-number">1</span>])) {<br> <span class="hljs-keyword">const</span> value = cache.get(item[<span class="hljs-number">1</span>])<br> result.push(value)<br> <span class="hljs-comment">// 把值放到最后</span><br> cache.delete(item[<span class="hljs-number">1</span>])<br> cache.set(item[<span class="hljs-number">1</span>], value)<br> } <span class="hljs-keyword">else</span> {<br> result.push(-<span class="hljs-number">1</span>)<br> }<br> }<br> }<br> <span class="hljs-keyword">return</span> result<br>}<br><span class="hljs-built_in">module</span>.exports = {<br> <span class="hljs-attr">LRU</span>: LRU<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>算法题</category>
</categories>
</entry>
<entry>
<title>如何用 vue3 开发 IDE 插件</title>
<link href="/2021/07/25/vue3-extension-template/"/>
<url>/2021/07/25/vue3-extension-template/</url>
<content type="html"><![CDATA[<h1 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h1><p>当你想写 IDE 插件的时候,是否觉得原生的写法太过麻烦,为什么不能用框架来写?当 webview 里的页面有十分复杂的交互的时候,写插件里的页面就变成了一件十分头疼的事,任凭外面的框架如何花里胡哨,你也只能使用原生的写法来实现,本文将介绍如何把 Vue3 运用到插件里来开发。</p><h1 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h1><h2 id="创建插件"><a href="#创建插件" class="headerlink" title="创建插件"></a>创建插件</h2><p>全局安装 yo 和 generator-code:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm install -g yo generator-code<br></code></pre></td></tr></table></figure><p>按照步骤,新建插件,选择 Typescript 来开发插件:</p><figure class="highlight shell"><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><code class="hljs shell">yo code<br><br> _-----_ ╭──────────────────────────╮<br>| | │ Welcome to the Visual │<br>|--(o)--| │ Studio Code Extension │<br>`---------´ │ generator! │<br>( _´U`_ ) ╰──────────────────────────╯<br>/___A___\ /<br> | ~ |<br>__'.___.'__<br>´ ` |° ´ Y `<br><br> ? What type of extension do you want to create? New Extension (TypeScript)<br> ? What's the name of your extension? helloWorld<br> ? What's the identifier of your extension? helloworld<br> ? What's the description of your extension?<br> ? Initialize a git repository? No<br> ? Bundle the source code with webpack? Yes<br> ? Which package manager to use?<br> npm<br> ❯ yarn<br></code></pre></td></tr></table></figure><h2 id="新建-vue-项目"><a href="#新建-vue-项目" class="headerlink" title="新建 vue 项目"></a>新建 vue 项目</h2><p>进入插件目录,新建一个名为 frontend 的 vue 项目,需要先安装 vue cli。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">vue create frontend<br></code></pre></td></tr></table></figure><p>此时,你会发现,这里的 vue 项目还是 js 的,我们把它换成 ts 的。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">vue add typescript<br></code></pre></td></tr></table></figure><p>注意: 其中的 Convert all .js files to .ts 选项选 Y。</p><h1 id="新建插件要打开的-panel"><a href="#新建插件要打开的-panel" class="headerlink" title="新建插件要打开的 panel"></a>新建插件要打开的 panel</h1><p>新建 TemplatePanel 类</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-comment">// TemplatePanel.ts</span><br><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TemplatePanel</span> </span>{<br> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> currentPanel: TemplatePanel | <span class="hljs-literal">undefined</span>;<br> <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> _panel: vscode.WebviewPanel;<br> <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> _context: vscode.ExtensionContext;<br> <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> _extensionPath: <span class="hljs-built_in">string</span>;<br> <span class="hljs-keyword">private</span> _disposables: vscode.Disposable[] = [];<br><br> <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span></span><br><span class="hljs-params"><span class="hljs-function"> panel: vscode.WebviewPanel,</span></span><br><span class="hljs-params"><span class="hljs-function"> context: vscode.ExtensionContext</span></span><br><span class="hljs-params"><span class="hljs-function"> </span>)</span> {<br> <span class="hljs-built_in">this</span>._panel = panel;<br> <span class="hljs-built_in">this</span>._context = context;<br> <span class="hljs-built_in">this</span>._extensionPath = context.extensionPath;<br> <span class="hljs-built_in">this</span>.initialize();<br> }<br><br> <span class="hljs-keyword">private</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-title">initialize</span>(<span class="hljs-params"></span>)</span> {<br> <span class="hljs-built_in">this</span>._panel.onDidDispose(<span class="hljs-function">() =></span> <span class="hljs-built_in">this</span>.dispose(), <span class="hljs-literal">null</span>, <span class="hljs-built_in">this</span>._disposables);<br> }<br><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-title">show</span>(<span class="hljs-params">context: vscode.ExtensionContext</span>)</span> {<br> <span class="hljs-comment">// 如果打开了页面,不重复打开</span><br> <span class="hljs-keyword">if</span> (TemplatePanel.currentPanel) {<br> <span class="hljs-keyword">const</span> column = vscode.window.activeTextEditor<br> ? vscode.window.activeTextEditor.viewColumn<br> : <span class="hljs-literal">undefined</span>;<br> TemplatePanel.currentPanel._panel.reveal(column);<br> <span class="hljs-keyword">return</span>;<br> }<br><br> <span class="hljs-keyword">const</span> panel = vscode.window.createWebviewPanel(<br> <span class="hljs-string">"Template"</span>,<br> localize(<span class="hljs-string">"template"</span>),<br> vscode.ViewColumn.Active,<br> {<br> <span class="hljs-attr">enableScripts</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">retainContextWhenHidden</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-comment">// 用于 IDE 自带的文件协议的可读路径</span><br> <span class="hljs-attr">localResourceRoots</span>: [<br> vscode.Uri.file(path.join(context.extensionPath, <span class="hljs-string">"media"</span>)),<br> vscode.Uri.file(path.join(context.extensionPath, <span class="hljs-string">"frontend"</span>, <span class="hljs-string">"dist"</span>)),<br> ],<br> }<br> );<br><br> TemplatePanel.currentPanel = <span class="hljs-keyword">new</span> TemplatePanel(panel, context);<br> }<br><br> <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-title">dispose</span>(<span class="hljs-params"></span>)</span> {<br> TemplatePanel.currentPanel = <span class="hljs-literal">undefined</span>;<br> <span class="hljs-built_in">this</span>._panel.dispose();<br><br> <span class="hljs-keyword">while</span> (<span class="hljs-built_in">this</span>._disposables.length) {<br> <span class="hljs-keyword">const</span> x = <span class="hljs-built_in">this</span>._disposables.pop();<br> <span class="hljs-keyword">if</span> (x) {<br> x.dispose();<br> }<br> }<br> }<br>}<br></code></pre></td></tr></table></figure><h2 id="如何获取-vue-的前端页面"><a href="#如何获取-vue-的前端页面" class="headerlink" title="如何获取 vue 的前端页面"></a>如何获取 vue 的前端页面</h2><p>读取 vue 项目打包后的文件,并把引用的文件路径替换成 IDE 能够识别的文件协议格式。</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getWebviewContent</span>(<span class="hljs-params">extensionPath: <span class="hljs-built_in">string</span></span>) </span>{<br> <span class="hljs-keyword">const</span> distPath = vscode.Uri.file(<br> path.join(extensionPath, <span class="hljs-string">"frontend"</span>, <span class="hljs-string">"dist"</span>)<br> ).with({ <span class="hljs-attr">scheme</span>: <span class="hljs-string">"vscode-resource"</span> });<br> <span class="hljs-comment">// 读取 dits 下的 index.html</span><br> <span class="hljs-keyword">let</span> html = <span class="hljs-keyword">await</span> fse.readFile(<br> path.join(__dirname, <span class="hljs-string">"../frontend/dist/index.html"</span>)<br> );<br> <span class="hljs-keyword">const</span> hrefReg = <span class="hljs-regexp">/href=(["']{1})\/{1}([^\/])/gi</span>;<br> <span class="hljs-keyword">const</span> srcReg = <span class="hljs-regexp">/src=(["']{1})\/{1}([^\/])/gi</span>;<br> <span class="hljs-comment">// 把文件路径替换成 IDE 能够识别的文件协议格式</span><br> <span class="hljs-keyword">let</span> str = html<br> .toString()<br> .replace(hrefReg, <span class="hljs-string">`href=$1<span class="hljs-subst">${distPath}</span>/$2`</span>)<br> .replace(srcReg, <span class="hljs-string">`src=$1<span class="hljs-subst">${distPath}</span>/$2`</span>);<br> <span class="hljs-keyword">return</span> str;<br>}<br></code></pre></td></tr></table></figure><p>在 initialize 方法中赋值 webview 的 html:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-comment">// TemplatePanel.ts 中的 initialize 方法</span><br><span class="hljs-built_in">this</span>._panel.webview.html = <span class="hljs-keyword">await</span> getWebviewContent(<span class="hljs-built_in">this</span>._extensionPath);<br></code></pre></td></tr></table></figure><h2 id="建立插件端和前端页面(Vue)的通信"><a href="#建立插件端和前端页面(Vue)的通信" class="headerlink" title="建立插件端和前端页面(Vue)的通信"></a>建立插件端和前端页面(Vue)的通信</h2><p>vue 编写的页面相当于是前端(浏览器端),而插件端的逻辑相当于是后端(服务器端),两者需要通信,那怎么才能在不启动服务的情况下进行通信呢,这就要用到 postMessage 了。</p><p>在前端页面中,增加 message 的监听:</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-comment">// main.ts</span><br><span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"message"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =></span> {<br> <span class="hljs-keyword">const</span> message = event.data;<br> <span class="hljs-keyword">switch</span> (message.command) {<br> <span class="hljs-keyword">case</span> <span class="hljs-string">"setMessage"</span>: {<br> <span class="hljs-keyword">break</span>;<br> }<br> <span class="hljs-attr">default</span>:<br> <span class="hljs-keyword">break</span>;<br> }<br>});<br></code></pre></td></tr></table></figure><p>在插件端,也要增加 message 的监听,我们写在 initialize 方法里:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-built_in">this</span>._panel.webview.onDidReceiveMessage(<br> <span class="hljs-keyword">async</span> (message) => {<br> <span class="hljs-keyword">switch</span> (message.command) {<br> <span class="hljs-keyword">case</span> <span class="hljs-string">"getMessage"</span>:<br> <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">default</span>:<br> <span class="hljs-keyword">break</span>;<br> }<br> },<br> <span class="hljs-literal">null</span>,<br> <span class="hljs-built_in">this</span>._disposables<br>);<br></code></pre></td></tr></table></figure><p>前端向后端发送消息:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-comment">// main.ts</span><br><span class="hljs-comment">// 引入 acquireVsCodeApi 的方法</span><br><span class="hljs-keyword">const</span> ide = acquireVsCodeApi();<br><span class="hljs-comment">// 发送消息</span><br>ide.postMessage({<br> <span class="hljs-attr">command</span>: <span class="hljs-string">"getMessage"</span>,<br>});<br></code></pre></td></tr></table></figure><p>后端向前端发送消息:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-comment">// templatePanel.ts</span><br><span class="hljs-built_in">this</span>._panel.webview.postMessage({<br> <span class="hljs-attr">command</span>: <span class="hljs-string">"setMessage"</span>,<br> <span class="hljs-attr">data</span>: {<br> <span class="hljs-attr">message</span>: <span class="hljs-string">"hello"</span>,<br> },<br>});<br></code></pre></td></tr></table></figure><h1 id="新增-Vuex"><a href="#新增-Vuex" class="headerlink" title="新增 Vuex"></a>新增 Vuex</h1><p>安装 vuex,由于我们用的是 vue3,所以要安装 vuex@next</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">yarn add vuex@next --save<br></code></pre></td></tr></table></figure><p>在 store.ts 中初始化 vuex</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-comment">// store.ts</span><br><span class="hljs-keyword">import</span> { createStore } <span class="hljs-keyword">from</span> <span class="hljs-string">"vuex"</span>;<br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> store = createStore({<br> <span class="hljs-attr">state</span>: {},<br> <span class="hljs-attr">modules</span>: {},<br>});<br>在 mian.ts 中引入 vuex<br><span class="hljs-comment">// main.ts</span><br><span class="hljs-keyword">import</span> { store } <span class="hljs-keyword">from</span> <span class="hljs-string">"./store"</span>;<br><span class="hljs-keyword">const</span> app = createApp(App);<br>app.use(store);<br>app.mount(<span class="hljs-string">"#app"</span>);<br></code></pre></td></tr></table></figure><h1 id="新增多语言(vue-i18n)"><a href="#新增多语言(vue-i18n)" class="headerlink" title="新增多语言(vue-i18n)"></a>新增多语言(vue-i18n)</h1><p>安装 vue-i18n,由于我们用的是 vue3,所以要安装 vue-i18n@next</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">yarn add vue-i18n@next --save<br></code></pre></td></tr></table></figure><p>在 i18n.ts 中初始化</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-comment">// i18n.ts</span><br><span class="hljs-keyword">import</span> { createI18n } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue-i18n"</span>;<br><br><span class="hljs-keyword">const</span> en = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./locale/en.json"</span>);<br><span class="hljs-keyword">const</span> zhCN = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./locale/zh-CN.json"</span>);<br><br><span class="hljs-comment">// 语言包根据语言环境分类</span><br><span class="hljs-keyword">const</span> messages = {<br> en,<br> <span class="hljs-string">"zh-CN"</span>: zhCN,<br>};<br><br><span class="hljs-keyword">const</span> i18n = createI18n({<br> <span class="hljs-attr">locale</span>: <span class="hljs-string">"zh-CN"</span>, <span class="hljs-comment">// 设置当前语言环境,默认中文简体</span><br> messages, <span class="hljs-comment">// 设置语言环境对应信息</span><br>});<br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> i18n;<br></code></pre></td></tr></table></figure><p>在 mian.ts 中引入 vue-i18n</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-comment">// main.ts</span><br><span class="hljs-keyword">import</span> i18n <span class="hljs-keyword">from</span> <span class="hljs-string">"./i18n/index"</span>;<br><span class="hljs-keyword">const</span> app = createApp(App);<br>app.use(i18n);<br>app.mount(<span class="hljs-string">"#app"</span>);<br>可以在代码中切换语言:<br><span class="hljs-built_in">this</span>.$i18n.locale = <span class="hljs-built_in">this</span>.language;<br></code></pre></td></tr></table></figure><h1 id="如何在-vue-项目中使用静态文件"><a href="#如何在-vue-项目中使用静态文件" class="headerlink" title="如何在 vue 项目中使用静态文件"></a>如何在 vue 项目中使用静态文件</h1><p>由于在 IDE 的 webview 中,使用的是 IDE 的文件协议,而不是正常的 file:// 协议。当你直接使用相对路径或者绝对路径时,是找不到静态资源的,那么,要如何才能在 vue 里用上静态资源呢,方法也很简单,只需要在 vue 项目用上 IDE 的文件协议头即可,我们这里把静态资源放在 media 目录下。</p><p>获取文件协议的 uri</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-comment">// 获取文件协议的 uri</span><br><span class="hljs-built_in">this</span>._panel.webview.asWebviewUri(<br> vscode.Uri.file(path.join(<span class="hljs-built_in">this</span>._extensionPath, <span class="hljs-string">"media"</span>))<br>通过之前的通信方式,把 uri 传到前端页面。<br><span class="hljs-built_in">this</span>._panel.webview.postMessage({<br> <span class="hljs-attr">command</span>: <span class="hljs-string">"setSetting"</span>,<br> <span class="hljs-attr">data</span>: {<br> <span class="hljs-attr">resource</span>: <span class="hljs-built_in">this</span>._panel.webview.asWebviewUri(<br> vscode.Uri.file(path.join(<span class="hljs-built_in">this</span>._extensionPath, <span class="hljs-string">"media"</span>))<br> ),<br> },<br></code></pre></td></tr></table></figure><p>前端接收之后把 uri 拼接成文件协议头:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-keyword">const</span> resource =<br> message.data.resource.scheme +<br> <span class="hljs-string">"://"</span> +<br> message.data.resource.authority +<br> message.data.resource.path;<br></code></pre></td></tr></table></figure><p>在页面中使用:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">img</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"`${resource}/images/logo.png`"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /></span><br></code></pre></td></tr></table></figure><p>这样就可以在前端页面中使用静态资源了。</p><h1 id="如何调试"><a href="#如何调试" class="headerlink" title="如何调试"></a>如何调试</h1><p>watch vue 项目内容<br>在 frontend 目录下的 package.json 中配置命令:</p><figure class="highlight json"><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><code class="hljs json"><span class="hljs-string">"scripts"</span>: {<br> <span class="hljs-attr">"watch"</span>: <span class="hljs-string">"vue-cli-service build --watch"</span><br> }<br></code></pre></td></tr></table></figure><p>配置完成之后,运行 yarn watch,即可实时监听代码变化,无需重新 build。</p><h2 id="watch-插件中内容"><a href="#watch-插件中内容" class="headerlink" title="watch 插件中内容"></a>watch 插件中内容</h2><p>由于在创建插件模板的时候,已经自行创建了 watch 命令,所以只需要在项目的根目录运行 yarn watch 即可。</p><h2 id="运用-vscode-调试"><a href="#运用-vscode-调试" class="headerlink" title="运用 vscode 调试"></a>运用 vscode 调试</h2><p>点击侧边栏的「运行和调试」,运行 Run Extension 任务。</p><p>运行之后,会打开一个新的窗口,使用快捷键 mac:cmd + shift + p win:ctrl + shift + p,输入 show panel,即可打开之前写的页面。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>本文介绍了如何用 vue3 来开发 IDE 插件,融合了 vuex、typescript、vue-i18n 等,能够满足日常的开发,如需查看更多的插件开发内容,可查看 文档,有丰富的 api 能够使用。</p><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h1><p>项目地址: <a href="">https://github.com/Jerome77777/vue3-ide-extension-template</a></p>]]></content>
<categories>
<category>vscode</category>
</categories>
</entry>
<entry>
<title>koa-middleware</title>
<link href="/2021/07/18/koa-middleware/"/>
<url>/2021/07/18/koa-middleware/</url>
<content type="html"><![CDATA[<h1 id="Koa-的核心扩展机制:中间件"><a href="#Koa-的核心扩展机制:中间件" class="headerlink" title="Koa 的核心扩展机制:中间件"></a>Koa 的核心扩展机制:中间件</h1><h2 id="什么是中间件"><a href="#什么是中间件" class="headerlink" title="什么是中间件"></a>什么是中间件</h2><p>中间件是框架的扩展机制,主要用于抽象 HTTP 请求过程。在单一请求响应过程中加入中间件,可以更好地应对复杂的业务逻辑。</p><p>如果把 HTTTP 处理过程比作污水处理,那么中间件就像一层层的过滤网。每个中间件在 HTTP 处理过程中通过改写请求和响应数据、状态,实现特定功能。大家都知道 HTTP 是无状态协议,所以 HTTP 请求的过程可以这样理解:请求被发送过来,经过无数中间件拦截直至被响应为止。</p><p><a href="https://imgtu.com/i/W8n5Y8"><img src="https://z3.ax1x.com/2021/07/18/W8n5Y8.jpg" alt="W8n5Y8.jpg"></a></p><p>请求到达服务器后,依次经过各个中间件,直至被响应,所以整个流程会流经 log 中间件,由请求响应(业务逻辑)中间件给与响应,具体描述如下:</p><ul><li>请求到达 log 中间件,记录此时的时间。</li><li>放过,执行 next,此时会执行下一个中间件。</li><li>执行到请求响应中间件,通过 ctx.body 向浏览器输出响应结果。</li><li>当响应回到 log 中间件时,根据当前时间减去请求到达时间,打印请求耗时。</li><li>最后把响应写到浏览器里。</li></ul><h2 id="Koa-v2"><a href="#Koa-v2" class="headerlink" title="Koa v2"></a>Koa v2</h2><p>在简单了解了中间件之后,本文主要介绍 Koa v2 的内容。Koa v2 是一个成熟的 Web 框架,是由 Koa v1 演进而成的。Koa v2 最重要的特性是支持 async 函数,并且同时支持如下 3 种不同类型函数的中间件。</p>]]></content>
<categories>
<category>Node</category>
</categories>
</entry>
<entry>
<title>vscode 依赖注入</title>
<link href="/2021/07/11/vscode-ioc/"/>
<url>/2021/07/11/vscode-ioc/</url>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在 vscode 的源码中,有许多服务(Service),这些服务提供不同模块的 API 给其他模块使用,在需要依赖该服务的类构造器中用装饰器的形式声明参数,开发者不需要再显式地 new 这个服务对象,在调用者被创建时,这些依赖的服务会被自动创建并传递给调用者,服务之间还能够相互依赖,这样做大幅度地降低了程序的耦合性。本文将带你简单了解 vscode 的依赖注入。</p><h1 id="预备知识"><a href="#预备知识" class="headerlink" title="预备知识"></a>预备知识</h1><h2 id="Typescript-装饰器"><a href="#Typescript-装饰器" class="headerlink" title="Typescript 装饰器"></a>Typescript 装饰器</h2><p>如果您不太了解 typescript 装饰器,请先阅读我之前的文章<a href="https://chenjiangfeng.xyz/2021/07/03/decorators/">《TypeScript 装饰器》</a></p><h1 id="依赖注入详解"><a href="#依赖注入详解" class="headerlink" title="依赖注入详解"></a>依赖注入详解</h1><h2 id="创建服务"><a href="#创建服务" class="headerlink" title="创建服务"></a>创建服务</h2><p>定义一个类并在其构造函数中声明依赖的服务</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span> </span>{<br><span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span></span><br><span class="hljs-params"><span class="hljs-function"><span class="hljs-meta">@IMyService</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> myService: IMyService</span></span><br><span class="hljs-params"><span class="hljs-function"></span>)</span> {<br>}<br>}<br></code></pre></td></tr></table></figure><p>我们在类中使用了一个装饰器 @IMyService,相信你看了预备知识之后,能够清楚地知道这是一个参数装饰器,该装饰器会在运行时被调用,并传入三个参数:</p><ul><li>对于静态成员来说是类的构造函数,对于实例成员是类的原型对象</li><li>成员的名字</li><li>参数在函数参数列表中的索引<br>那么,这个 IMyService 装饰器是如何定义的呢,让我们接下来看:</li></ul><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-keyword">const</span> IMyService = createDecorator<IMyService>(<span class="hljs-string">'myService'</span>);<br><span class="hljs-keyword">interface</span> IMyService {<br><span class="hljs-attr">_serviceBrand</span>: <span class="hljs-literal">undefined</span>;<br>myMethod(): <span class="hljs-built_in">any</span>;<br>}<br></code></pre></td></tr></table></figure><p>当然,这个服务接口需要具体的实现:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyService</span> <span class="hljs-title">implements</span> <span class="hljs-title">IMyService</span> </span>{<br><span class="hljs-attr">_serviceBrand</span>: <span class="hljs-literal">undefined</span>;<br><span class="hljs-function"><span class="hljs-title">myMethod</span>(<span class="hljs-params"></span>)</span> {<br><span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br>}<br>}<br></code></pre></td></tr></table></figure><p>我们发现,在声明这个接口之前,有个 createDecorator 函数定义了一个服务的装饰器,用于在构造函数中声明依赖关系以方便注入依赖。createDecorator 的主要作用是返回一个装饰器,让我们来看看是怎么实现的:</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createDecorator</span><<span class="hljs-title">T</span>>(<span class="hljs-params">serviceId: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">ServiceIdentifier</span><<span class="hljs-title">T</span>> </span>{<br><span class="hljs-comment">// 已经保存过的服务直接返回其装饰器</span><br><span class="hljs-keyword">if</span> (_util.serviceIds.has(serviceId)) {<br><span class="hljs-keyword">return</span> _util.serviceIds.get(serviceId)!;<br>}<br><br><span class="hljs-comment">// 声明装饰器,只能被用于参数装饰器</span><br><span class="hljs-keyword">const</span> id = <<span class="hljs-built_in">any</span>><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target: <span class="hljs-built_in">Function</span>, key: <span class="hljs-built_in">string</span>, index: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">any</span> </span>{<br><span class="hljs-keyword">if</span> (<span class="hljs-built_in">arguments</span>.length !== <span class="hljs-number">3</span>) {<br><span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'@IServiceName-decorator can only be used to decorate a parameter'</span>);<br>}<br><span class="hljs-comment">// 将服务作为依赖保存在目标类的属性中</span><br>storeServiceDependency(id, target, index, <span class="hljs-literal">false</span>);<br>};<br><br>id.toString = <span class="hljs-function">() =></span> serviceId;<br><br><span class="hljs-comment">// 在 serviceIds 保存依赖</span><br>_util.serviceIds.set(serviceId, id);<br><span class="hljs-keyword">return</span> id;<br>}<br>storeServiceDependency 函数:<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">storeServiceDependency</span>(<span class="hljs-params">id: <span class="hljs-built_in">Function</span>, target: <span class="hljs-built_in">Function</span>, index: <span class="hljs-built_in">number</span>, optional: <span class="hljs-built_in">boolean</span></span>): <span class="hljs-title">void</span> </span>{<br><span class="hljs-keyword">if</span> ((target <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>)[_util.DI_TARGET] === target) {<br>(target <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>)[_util.DI_DEPENDENCIES].push({ id, index, optional });<br>} <span class="hljs-keyword">else</span> {<br>(target <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>)[_util.DI_DEPENDENCIES] = [{ id, index, optional }];<br>(target <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>)[_util.DI_TARGET] = target;<br>}<br>}<br></code></pre></td></tr></table></figure><p>storeServiceDependency 函数将传入的服务 ID (唯一的字符串 myService )及索引保存在所装饰类的一个成员 $di$dependencies 数组中, 对于例子中的 MyClass,其构造函数中的一个参数装饰器会在编译的时候被执行,把依赖记入到 $di$dependencies 数组。</p><figure class="highlight ts"><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><code class="hljs ts">MyClass[<span class="hljs-string">'$di$dependencies'</span>] = [<br>{ <span class="hljs-attr">id</span>: <span class="hljs-string">'myService'</span>, <span class="hljs-attr">index</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">optional</span>: <span class="hljs-literal">false</span> }<br>];<br></code></pre></td></tr></table></figure><h2 id="服务集容器"><a href="#服务集容器" class="headerlink" title="服务集容器"></a>服务集容器</h2><p>上节讲到创建了一个服务,那么有多个服务时,就需要一个服务集,用于保存一组服务。</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServiceCollection</span> </span>{<br><span class="hljs-comment">// 服务集的 map</span><br><span class="hljs-keyword">private</span> _entries = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span><ServiceIdentifier<<span class="hljs-built_in">any</span>>, <span class="hljs-built_in">any</span>>();<br><br><span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">...entries: [ServiceIdentifier<<span class="hljs-built_in">any</span>>, <span class="hljs-built_in">any</span>][]</span>)</span> {<br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> [id, service] <span class="hljs-keyword">of</span> entries) {<br><span class="hljs-built_in">this</span>.set(id, service);<br>}<br>}<br><br><span class="hljs-comment">// 添加服务</span><br>set<T>(id: ServiceIdentifier<T>, instanceOrDescriptor: T | SyncDescriptor<T>): T | SyncDescriptor<T> {<br><span class="hljs-keyword">const</span> result = <span class="hljs-built_in">this</span>._entries.get(id);<br><span class="hljs-built_in">this</span>._entries.set(id, instanceOrDescriptor);<br><span class="hljs-keyword">return</span> result;<br>}<br><br><span class="hljs-comment">// 是否含有该服务</span><br>has(id: ServiceIdentifier<<span class="hljs-built_in">any</span>>): <span class="hljs-built_in">boolean</span> {<br><span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._entries.has(id);<br>}<br><br><span class="hljs-comment">// 获取服务</span><br>get<T>(id: ServiceIdentifier<T>): T | SyncDescriptor<T> {<br><span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._entries.get(id);<br>}<br>}<br></code></pre></td></tr></table></figure><p>创建一个服务集容器:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-keyword">const</span> services = <span class="hljs-keyword">new</span> ServiceCollection();<br><span class="hljs-comment">// 第一个参数为服务的构造器,即 id,如使用装饰器中说到的 myService</span><br><span class="hljs-comment">// 第二个参数为服务的实例对象</span><br>services.set(ILoggerService, <span class="hljs-keyword">new</span> LoggerService(logService, fileService));<br>services.set(ILifecycleMainService, <span class="hljs-keyword">new</span> SyncDescriptor(LifecycleMainService));<br></code></pre></td></tr></table></figure><p>在 vscode 中,有些服务是不依赖其他服务,仅被其他服务所依赖,如日志服务(ILoggerService),此类服务创建的时候可直接 new 服务的对象。有些服务还会依赖别的服务,需要 SyncDescriptor 封装之后保存在服务集中。</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SyncDescriptor</span><<span class="hljs-title">T</span>> </span>{<br><br><span class="hljs-keyword">readonly</span> ctor: <span class="hljs-built_in">any</span>;<br><span class="hljs-keyword">readonly</span> staticArguments: <span class="hljs-built_in">any</span>[];<br><span class="hljs-keyword">readonly</span> supportsDelayedInstantiation: <span class="hljs-built_in">boolean</span>;<br><br><span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">ctor: <span class="hljs-keyword">new</span> (...args: <span class="hljs-built_in">any</span>[]) => T, staticArguments: <span class="hljs-built_in">any</span>[] = [], supportsDelayedInstantiation: <span class="hljs-built_in">boolean</span> = <span class="hljs-literal">false</span></span>)</span> {<br><span class="hljs-built_in">this</span>.ctor = ctor;<span class="hljs-comment">//服务的构造器</span><br><span class="hljs-built_in">this</span>.staticArguments = staticArguments;<span class="hljs-comment">// 静态参数</span><br><span class="hljs-built_in">this</span>.supportsDelayedInstantiation = supportsDelayedInstantiation;<span class="hljs-comment">// 是否支持延迟实例化</span><br>}<br>}<br></code></pre></td></tr></table></figure><p>SyncDescriptor 是一个用于包装需要被容器实例化容器的描述符对象,它保存了对象的构造器和静态参数</p><h2 id="实例化容器"><a href="#实例化容器" class="headerlink" title="实例化容器"></a>实例化容器</h2><p>上文讲到,我们创建了一个服务集容器,并把服务注入到了容器之中,那么就需要一个类来操作这个容器, InstantiationService 这个类就是起到这个作用。</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">const</span> IInstantiationService = createDecorator<IInstantiationService>(<span class="hljs-string">'instantiationService'</span>);<br>从源码中,我们也能看到,IInstantiationService 也是一个服务,他最早在 main.ts 中的 startup 函数中被初始化。<br><br><span class="hljs-keyword">const</span> instantiationService = <span class="hljs-keyword">new</span> InstantiationService(services, <span class="hljs-literal">true</span>);<br></code></pre></td></tr></table></figure><p>在创建了 instantiationService 实例之后,可调用 invokeFunction 方法来手动地获取服务实例,容器会自动去分析它所依赖的服务并自动实例化后返回。在寻找容器中的服务时,当在当前容器中找不到这个服务时,会去查找父容器中是否有这个服务。</p><figure class="highlight ts"><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><code class="hljs ts">_getServiceInstanceOrDescriptor<T>(id: ServiceIdentifier<T>): T | SyncDescriptor<T> {<br><span class="hljs-comment">// 在容器中根据 id 获取服务实例或描述符</span><br><span class="hljs-keyword">let</span> instanceOrDesc = <span class="hljs-built_in">this</span>._services.get(id);<br><span class="hljs-keyword">if</span> (!instanceOrDesc && <span class="hljs-built_in">this</span>._parent) {<br><span class="hljs-comment">// 查找父容器的服务</span><br><span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._parent._getServiceInstanceOrDescriptor(id);<br>} <span class="hljs-keyword">else</span> {<br><span class="hljs-keyword">return</span> instanceOrDesc;<br>}<br>}<br></code></pre></td></tr></table></figure><p>如果找到的服务是个 SyncDescriptor,即这个服务还依赖其他服务,则会通过图的关系来处理服务间的依赖关系,这里是整个依赖注入的核心,放到下面详细说明。</p><h2 id="依赖分析"><a href="#依赖分析" class="headerlink" title="依赖分析"></a>依赖分析</h2><p>在上文中讲到,在不依赖其他服务的情况下,是很简单的。当服务之间有依赖关系,随着需求的增加就会变得十分复杂。而依赖注入的核心就是这些关系的处理,以及查看存在的依赖循环,那么 vscode 是如何处理这些依赖关系的呢,让我们看下面这段代码,可能比较复杂,我们慢慢分析。</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts">_createAndCacheServiceInstance<T>(id: ServiceIdentifier<T>, desc: SyncDescriptor<T>, _trace: Trace): T {<br><br><span class="hljs-keyword">type</span> Triple = { <span class="hljs-attr">id</span>: ServiceIdentifier<<span class="hljs-built_in">any</span>>, desc: SyncDescriptor<<span class="hljs-built_in">any</span>>, _trace: Trace; };<br><span class="hljs-keyword">const</span> graph = <span class="hljs-keyword">new</span> Graph<Triple>(<span class="hljs-function"><span class="hljs-params">data</span> =></span> data.id.toString());<br><br><span class="hljs-keyword">let</span> cycleCount = <span class="hljs-number">0</span>;<br> <span class="hljs-comment">// 将当前依赖推入栈</span><br><span class="hljs-keyword">const</span> stack = [{ id, desc, _trace }];<br> <span class="hljs-comment">// 根据依赖关系构造有向图</span><br><span class="hljs-keyword">while</span> (stack.length) {<br><span class="hljs-keyword">const</span> item = stack.pop()!;<br> <span class="hljs-comment">// 查找或者插入节点 graph: myService, (incoming)[], (outgoing)[]</span><br>graph.lookupOrInsertNode(item);<br><br><span class="hljs-comment">// a weak but working heuristic for cycle checks</span><br><span class="hljs-keyword">if</span> (cycleCount++ > <span class="hljs-number">1000</span>) {<br><span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> CyclicDependencyError(graph);<br>}<br><br><span class="hljs-comment">// 检查所有依赖项是否存在以及是否需要首先创建它们, dependency 是我们服务所依赖的其他服务</span><br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> dependency <span class="hljs-keyword">of</span> _util.getServiceDependencies(item.desc.ctor)) {<br><br><span class="hljs-keyword">let</span> instanceOrDesc = <span class="hljs-built_in">this</span>._getServiceInstanceOrDescriptor(dependency.id);<br><span class="hljs-keyword">if</span> (!instanceOrDesc && !dependency.optional) {<br><span class="hljs-built_in">console</span>.warn(<span class="hljs-string">`[createInstance] <span class="hljs-subst">${id}</span> depends on <span class="hljs-subst">${dependency.id}</span> which is NOT registered.`</span>);<br>}<br><br><span class="hljs-keyword">if</span> (instanceOrDesc <span class="hljs-keyword">instanceof</span> SyncDescriptor) {<br><span class="hljs-keyword">const</span> d = { <span class="hljs-attr">id</span>: dependency.id, <span class="hljs-attr">desc</span>: instanceOrDesc, <span class="hljs-attr">_trace</span>: item._trace.branch(dependency.id, <span class="hljs-literal">true</span>) };<br>graph.insertEdge(item, d);<br>stack.push(d);<br>}<br>}<br>}<br><br><span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {<br><span class="hljs-keyword">const</span> roots = graph.roots();<br><br><span class="hljs-comment">// 所有 outgoing 为空但是还有节点时,认为是有依赖循环,报错</span><br><span class="hljs-keyword">if</span> (roots.length === <span class="hljs-number">0</span>) {<br><span class="hljs-keyword">if</span> (!graph.isEmpty()) {<br><span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> CyclicDependencyError(graph);<br>}<br><span class="hljs-keyword">break</span>;<br>}<br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> { data } <span class="hljs-keyword">of</span> roots) {<br><span class="hljs-comment">// Repeat the check for this still being a service sync descriptor. That's because</span><br><span class="hljs-comment">// instantiating a dependency might have side-effect and recursively trigger instantiation</span><br><span class="hljs-comment">// so that some dependencies are now fullfilled already.</span><br><span class="hljs-keyword">const</span> instanceOrDesc = <span class="hljs-built_in">this</span>._getServiceInstanceOrDescriptor(data.id);<br><span class="hljs-keyword">if</span> (instanceOrDesc <span class="hljs-keyword">instanceof</span> SyncDescriptor) {<br><span class="hljs-comment">// 创建实例</span><br><span class="hljs-keyword">const</span> instance = <span class="hljs-built_in">this</span>._createServiceInstanceWithOwner(data.id, data.desc.ctor, data.desc.staticArguments, data.desc.supportsDelayedInstantiation, data._trace);<br><span class="hljs-built_in">this</span>._setServiceInstance(data.id, instance);<br>}<br>graph.removeNode(data);<br>}<br>}<br><span class="hljs-keyword">return</span> <T><span class="hljs-built_in">this</span>._getServiceInstanceOrDescriptor(id);<br>}<br></code></pre></td></tr></table></figure><p>vscode 是通过图来保存依赖间的关系,我们的依赖关系可以看做是一个有向图,不同的依赖可以看做是图中的一个节点,而节点间实例化的先后顺序可以看做图的边,在 vscode 中,是采用邻接表这种数据结构来表示图,即Graph 中用一个 _nodes 来保存每个顶点,且每个顶点的所有相邻(出度及入度)顶点保存在顶点对应的一张链表中。</p><figure class="highlight ts"><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><code class="hljs ts">insertEdge(<span class="hljs-keyword">from</span>: T, <span class="hljs-attr">to</span>: T): <span class="hljs-built_in">void</span> {<br><span class="hljs-keyword">const</span> fromNode = <span class="hljs-built_in">this</span>.lookupOrInsertNode(<span class="hljs-keyword">from</span>);<br><span class="hljs-keyword">const</span> toNode = <span class="hljs-built_in">this</span>.lookupOrInsertNode(to);<br><br>fromNode.outgoing.set(<span class="hljs-built_in">this</span>._hashFn(to), toNode);<br>toNode.incoming.set(<span class="hljs-built_in">this</span>._hashFn(<span class="hljs-keyword">from</span>), fromNode);<br>}<br></code></pre></td></tr></table></figure><p>有向图构造完之后,从图中拿出所有出度构成的依赖数组,因为依赖关系是逐层往上的,即将 A 服务所依赖的其他服务依次实例化,最后再实例化 A ,一直到全部实例化完成为止。</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {<br> <span class="hljs-comment">// 出度,即本服务依赖的服务数组</span><br><span class="hljs-keyword">const</span> roots = graph.roots();<br><br><span class="hljs-comment">// 根节点为空但是图中不为空时,报错</span><br><span class="hljs-keyword">if</span> (roots.length === <span class="hljs-number">0</span>) {<br> <span class="hljs-comment">// 如果所有依赖都已经实例化完成而图中还有节点则认为包含循环依赖</span><br><span class="hljs-keyword">if</span> (!graph.isEmpty()) {<br><span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> CyclicDependencyError(graph);<br>}<br><span class="hljs-keyword">break</span>;<br>}<br> <span class="hljs-comment">// 遍历数组并以此实例化</span><br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> { data } <span class="hljs-keyword">of</span> roots) {<br><span class="hljs-comment">// Repeat the check for this still being a service sync descriptor. That's because</span><br><span class="hljs-comment">// instantiating a dependency might have side-effect and recursively trigger instantiation</span><br><span class="hljs-comment">// so that some dependencies are now fullfilled already.</span><br><span class="hljs-keyword">const</span> instanceOrDesc = <span class="hljs-built_in">this</span>._getServiceInstanceOrDescriptor(data.id);<br><span class="hljs-keyword">if</span> (instanceOrDesc <span class="hljs-keyword">instanceof</span> SyncDescriptor) {<br><span class="hljs-comment">// 创建实例</span><br><span class="hljs-keyword">const</span> instance = <span class="hljs-built_in">this</span>._createServiceInstanceWithOwner(data.id, data.desc.ctor, data.desc.staticArguments, data.desc.supportsDelayedInstantiation, data._trace);<br><span class="hljs-built_in">this</span>._setServiceInstance(data.id, instance);<br>}<br>graph.removeNode(data);<br>}<br>}<br><span class="hljs-keyword">return</span> <T><span class="hljs-built_in">this</span>._getServiceInstanceOrDescriptor(id);<br></code></pre></td></tr></table></figure><p>当所有实例化全部完成,调用栈回到 _createInstance 方法,serviceArags 拿到了所有的依赖后调用 create 方法传入构造器以及其参数创建实例。</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">private</span> _createInstance<T>(ctor: <span class="hljs-built_in">any</span>, <span class="hljs-attr">args</span>: <span class="hljs-built_in">any</span>[] = [], <span class="hljs-attr">_trace</span>: Trace): T {<br><br><span class="hljs-comment">// 由服务装饰器定义的参数,根据 index 排序</span><br><span class="hljs-keyword">let</span> serviceDependencies = _util.getServiceDependencies(ctor).sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =></span> a.index - b.index);<br><span class="hljs-keyword">let</span> serviceArgs: <span class="hljs-built_in">any</span>[] = [];<br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> dependency <span class="hljs-keyword">of</span> serviceDependencies) {<br><span class="hljs-comment">// 获取或者创建实例</span><br><span class="hljs-keyword">let</span> service = <span class="hljs-built_in">this</span>._getOrCreateServiceInstance(dependency.id, _trace);<br><span class="hljs-keyword">if</span> (!service && <span class="hljs-built_in">this</span>._strict && !dependency.optional) {<br><span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`[createInstance] <span class="hljs-subst">${ctor.name}</span> depends on UNKNOWN service <span class="hljs-subst">${dependency.id}</span>.`</span>);<br>}<br>serviceArgs.push(service);<br>}<br><br><span class="hljs-keyword">let</span> firstServiceArgPos = serviceDependencies.length > <span class="hljs-number">0</span> ? serviceDependencies[<span class="hljs-number">0</span>].index : args.length;<br><br><span class="hljs-comment">// check for argument mismatches, adjust static args if needed</span><br><span class="hljs-keyword">if</span> (args.length !== firstServiceArgPos) {<br><span class="hljs-built_in">console</span>.warn(<span class="hljs-string">`[createInstance] First service dependency of <span class="hljs-subst">${ctor.name}</span> at position <span class="hljs-subst">${firstServiceArgPos + <span class="hljs-number">1</span>}</span> conflicts with <span class="hljs-subst">${args.length}</span> static arguments`</span>);<br><br><span class="hljs-keyword">let</span> delta = firstServiceArgPos - args.length;<br><span class="hljs-keyword">if</span> (delta > <span class="hljs-number">0</span>) {<br>args = args.concat(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(delta));<br>} <span class="hljs-keyword">else</span> {<br>args = args.slice(<span class="hljs-number">0</span>, firstServiceArgPos);<br>}<br>}<br><br><span class="hljs-comment">// 创建服务实例</span><br><span class="hljs-keyword">return</span> <T><span class="hljs-keyword">new</span> ctor(...[...args, ...serviceArgs]);<br>}<br></code></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>本文从 vscode 源码的角度分析了其依赖注入的原理,简而言之,依赖分析的过程是递归向下获取所有的依赖项,再递归向上优先实例化最底层的依赖,在实例化依赖的时候,会逐级去查找依赖并实例化。用服务集容器来管理依赖,可以让每个服务集容器具有不同的能力,例如在 vscode 中,主进程和渲染进程并不共享一套服务,因为主进程和渲染进程的能力和职责不同,分开管理比较合理。</p>]]></content>
<categories>
<category>vscode</category>
</categories>
</entry>
<entry>
<title>链表介绍</title>
<link href="/2021/07/05/link-introduction/"/>
<url>/2021/07/05/link-introduction/</url>
<content type="html"><![CDATA[<h2 id="链表"><a href="#链表" class="headerlink" title="链表"></a>链表</h2><h3 id="链表结构"><a href="#链表结构" class="headerlink" title="链表结构"></a>链表结构</h3><p>底层的存储结构:</p><p>从图中我们看到,数组需要一块连续的内存空间来存储,对内存的要求比较高。如果我们申请一个 100MB 大小的数组,当内存中没有连续的、足够大的存储空间时,即便内存的剩余总可用空间大于 100MB,仍然会申请失败。</p><p>而链表恰恰相反,它并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用,所以如果我们申请的是 100MB 大小的链表,根本不会有问题。</p><img src="https://static001.geekbang.org/resource/image/d5/cd/d5d5bee4be28326ba3c28373808a62cd.jpg"><h3 id="单链表"><a href="#单链表" class="headerlink" title="单链表"></a>单链表</h3><p>链表通过指针将一组零散的内存块串联在一起。其中,我们把内存块称为链表的“结点”。为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点的地址。如图所示,我们把这个记录下个结点地址的指针叫作后继指针 next。</p><img src="https://static001.geekbang.org/resource/image/b9/eb/b93e7ade9bb927baad1348d9a806ddeb.jpg"><p>从单链表图中,你应该可以发现,其中有两个结点是比较特殊的,它们分别是第一个结点和最后一个结点。我们习惯性地把第一个结点叫作头结点,把最后一个结点叫作尾结点。其中,头结点用来记录链表的基地址。有了它,我们就可以遍历得到整条链表。而尾结点特殊的地方是:指针不是指向下一个结点,而是指向一个空地址 NULL,表示这是链表上最后一个结点。</p><p>与数组一样,链表也支持数据的查找、插入和删除操作。</p><p>我们知道,在进行数组的插入、删除操作时,为了保持内存数据的连续性,需要做大量的数据搬移,所以时间复杂度是 O(n)。而在链表中插入或者删除一个数据,我们并不需要为了保持内存的连续性而搬移结点,因为链表的存储空间本身就不是连续的。所以,在链表中插入和删除一个数据是非常快速的。</p><img src="https://static001.geekbang.org/resource/image/45/17/452e943788bdeea462d364389bd08a17.jpg"><p>从图中我们可以看出,针对链表的插入和删除操作,我们只需要考虑相邻结点的指针改变,所以对应的时间复杂度是 O(1)。</p><p>但是,有利就有弊。链表要想随机访问第 k 个元素,就没有数组那么高效了。因为链表中的数据并非连续存储的,所以无法像数组那样,根据首地址和下标,通过寻址公式就能直接计算出对应的内存地址,而是需要根据指针一个结点一个结点地依次遍历,直到找到相应的结点。</p><h3 id="循环链表"><a href="#循环链表" class="headerlink" title="循环链表"></a>循环链表</h3><p>循环链表是一种特殊的单链表。实际上,循环链表也很简单。它跟单链表唯一的区别就在尾结点。我们知道,单链表的尾结点指针指向空地址,表示这就是最后的结点了。而循环链表的尾结点指针是指向链表的头结点。从我画的循环链表图中,你应该可以看出来,它像一个环一样首尾相连,所以叫作“循环”链表。</p><img src="https://static001.geekbang.org/resource/image/86/55/86cb7dc331ea958b0a108b911f38d155.jpg"><p>和单链表相比,循环链表的优点是从链尾到链头比较方便。当要处理的数据具有环型结构特点时,就特别适合采用循环链表。比如著名的约瑟夫问题。尽管用单链表也可以实现,但是用循环链表实现的话,代码就会简洁很多。</p><h3 id="双向链表"><a href="#双向链表" class="headerlink" title="双向链表"></a>双向链表</h3><p>单向链表只有一个方向,结点只有一个后继指针 next 指向后面的结点。而双向链表,顾名思义,它支持两个方向,每个结点不止有一个后继指针 next 指向后面的结点,还有一个前驱指针 prev 指向前面的结点。</p><img src="https://static001.geekbang.org/resource/image/cb/0b/cbc8ab20276e2f9312030c313a9ef70b.jpg"><p>从图中可以看出来,双向链表需要额外的两个空间来存储后继结点和前驱结点的地址。所以,如果存储同样多的数据,双向链表要比单链表占用更多的内存空间。虽然两个指针比较浪费存储空间,但可以支持双向遍历,这样也带来了双向链表操作的灵活性。那相比单链表,双向链表适合解决哪种问题呢?</p><p>从结构上来看,双向链表可以支持 O(1) 时间复杂度的情况下找到前驱结点,正是这样的特点,也使双向链表在某些情况下的插入、删除等操作都要比单链表简单、高效。</p><ul><li><p>删除操作</p><p> 在实际的软件开发中,从链表中删除一个数据无外乎这两种情况:</p><ul><li>删除结点中“值等于某个给定值”的结点;</li><li>删除给定指针指向的结点。</li></ul><p> 对于第一种情况,不管是单链表还是双向链表,为了查找到值等于给定值的结点,都需要从头结点开始一个一个依次遍历对比,直到找到值等于给定值的结点,然后再通过我前面讲的指针操作将其删除。</p><p> 尽管单纯的删除操作时间复杂度是 O(1),但遍历查找的时间是主要的耗时点,对应的时间复杂度为 O(n)。根据时间复杂度分析中的加法法则,删除值等于给定值的结点对应的链表操作的总时间复杂度为 O(n)。</p><p> 对于第二种情况,我们已经找到了要删除的结点,但是删除某个结点 q 需要知道其前驱结点,而单链表并不支持直接获取前驱结点,所以,为了找到前驱结点,我们还是要从头结点开始遍历链表,直到 p->next=q,说明 p 是 q 的前驱结点。</p><p> 但是对于双向链表来说,这种情况就比较有优势了。因为双向链表中的结点已经保存了前驱结点的指针,不需要像单链表那样遍历。所以,针对第二种情况,单链表删除操作需要 O(n) 的时间复杂度,而双向链表只需要在 O(1) 的时间复杂度内就搞定了!</p><p> 同理,如果我们希望在链表的某个指定结点前面插入一个结点,双向链表比单链表有很大的优势。双向链表可以在 O(1) 时间复杂度搞定,而单向链表需要 O(n) 的时间复杂度。你可以参照我刚刚讲过的删除操作自己分析一下。</p><p> 除了插入、删除操作有优势之外,对于一个有序链表,双向链表的按值查询的效率也要比单链表高一些。因为,我们可以记录上次查找的位置 p,每次查询时,根据要查找的值与 p 的大小关系,决定是往前还是往后查找,所以平均只需要查找一半的数据。</p><p> 现在,你有没有觉得双向链表要比单链表更加高效呢?这就是为什么在实际的软件开发中,双向链表尽管比较费内存,但还是比单链表的应用更加广泛的原因。如果你熟悉 Java 语言,你肯定用过 LinkedHashMap 这个容器。如果你深入研究 LinkedHashMap 的实现原理,就会发现其中就用到了双向链表这种数据结构。</p><p> 实际上,这里有一个更加重要的知识点需要你掌握,那就是<code>用空间换时间</code>的设计思想。当内存空间充足的时候,如果我们更加追求代码的执行速度,我们就可以选择空间复杂度相对较高、但时间复杂度相对很低的算法或者数据结构。相反,如果内存比较紧缺,比如代码跑在手机或者单片机上,这个时候,就要反过来用时间换空间的设计思路。</p><p> 对于执行较慢的程序,可以通过消耗更多的内存(空间换时间)来进行优化;而消耗过多内存的程序,可以通过消耗更多的时间(时间换空间)来降低内存的消耗。</p></li></ul><h3 id="双向循环链表"><a href="#双向循环链表" class="headerlink" title="双向循环链表"></a>双向循环链表</h3><img src="https://static001.geekbang.org/resource/image/d1/91/d1665043b283ecdf79b157cfc9e5ed91.jpg"><h3 id="链表-VS-数组性能大比拼"><a href="#链表-VS-数组性能大比拼" class="headerlink" title="链表 VS 数组性能大比拼"></a>链表 VS 数组性能大比拼</h3><img src="https://static001.geekbang.org/resource/image/4f/68/4f63e92598ec2551069a0eef69db7168.jpg"><p>数组简单易用,在实现上使用的是连续的内存空间,可以借助 CPU 的缓存机制,预读数组中的数据,所以访问效率更高。而链表在内存中并不是连续存储,所以对 CPU 缓存不友好,没办法有效预读。</p><p>数组的缺点是大小固定,一经声明就要占用整块连续内存空间。如果声明的数组过大,系统可能没有足够的连续内存空间分配给它,导致“内存不足(out of memory)”。如果声明的数组过小,则可能出现不够用的情况。这时只能再申请一个更大的内存空间,把原数组拷贝进去,非常费时。链表本身没有大小的限制,天然地支持动态扩容,我觉得这也是它与数组最大的区别。</p><p>如果你的代码对内存的使用非常苛刻,那数组就更适合你。因为链表中的每个结点都需要消耗额外的存储空间去存储一份指向下一个结点的指针,所以内存消耗会翻倍。而且,对链表进行频繁的插入、删除操作,还会导致频繁的内存申请和释放,容易造成内存碎片,如果是 Java 语言,就有可能会导致频繁的 GC(Garbage Collection,垃圾回收)。</p><h3 id="如何基于链表实现-LRU-缓存淘汰算法"><a href="#如何基于链表实现-LRU-缓存淘汰算法" class="headerlink" title="如何基于链表实现 LRU 缓存淘汰算法"></a>如何基于链表实现 LRU 缓存淘汰算法</h3><p>我们维护一个有序单链表,越靠近链表尾部的结点是越早之前访问的。当有一个新的数据被访问时,我们从链表头开始顺序遍历链表。</p><ol><li><p>如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并将其从原来的位置删除,然后再插入到链表的头部。</p></li><li><p>如果此数据没有在缓存链表中,又可以分为两种情况:</p><ul><li>如果此时缓存未满,则将此结点直接插入到链表的头部;</li><li>如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部。</li></ul></li></ol><p>现在我们来看下缓存访问的时间复杂度是多少。因为不管缓存有没有满,我们都需要遍历一遍链表,所以这种基于链表的实现思路,缓存访问的时间复杂度为 O(n)。</p><p>实际上,我们可以继续优化这个实现思路,比如引入散列表(Hash table)来记录每个数据的位置,将缓存访问的时间复杂度降到 O(1)。</p><h3 id="写链表代码技巧"><a href="#写链表代码技巧" class="headerlink" title="写链表代码技巧"></a>写链表代码技巧</h3><h4 id="理解指针或引用的含义"><a href="#理解指针或引用的含义" class="headerlink" title="理解指针或引用的含义"></a>理解指针或引用的含义</h4><p>事实上,看懂链表的结构并不是很难,但是一旦把它和指针混在一起,就很容易让人摸不着头脑。所以,要想写对链表代码,首先就要理解好指针。</p><p>我们知道,有些语言有“指针”的概念,比如 C 语言;有些语言没有指针,取而代之的是“引用”,比如 Java、Python。不管是“指针”还是“引用”,实际上,它们的意思都是一样的,都是存储所指对象的内存地址,以下为 C 语言的指针,其他语言自行转换为引用即可。</p><p>实际上,对于指针的理解,你只需要记住下面这句话就可以了:</p><p><strong>将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。</strong></p><p>在编写链表代码的时候,我们经常会有这样的代码:p->next=q。这行代码是说,p 结点中的 next 指针存储了 q 结点的内存地址。</p><p>还有一个更复杂的,也是我们写链表代码经常会用到的:p->next=p->next->next。这行代码表示,p 结点的 next 指针存储了 p 结点的下下一个结点的内存地址。</p><h4 id="警惕指针丢失和内存泄漏"><a href="#警惕指针丢失和内存泄漏" class="headerlink" title="警惕指针丢失和内存泄漏"></a>警惕指针丢失和内存泄漏</h4><img src="https://static001.geekbang.org/resource/image/05/6e/05a4a3b57502968930d517c934347c6e.jpg"><p>如图所示,我们希望在结点 a 和相邻的结点 b 之间插入结点 x,假设当前指针 p 指向结点 a。如果我们将代码实现变成下面这个样子,就会发生指针丢失和内存泄露。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c">p->next = x; <span class="hljs-comment">// 将p的next指针指向x结点;</span><br>x->next = p->next; <span class="hljs-comment">// 将x的结点的next指针指向b结点;</span><br></code></pre></td></tr></table></figure><p>p->next 指针在完成第一步操作之后,已经不再指向结点 b 了,而是指向结点 x。第 2 行代码相当于将 x 赋值给 x->next,自己指向自己。因此,整个链表也就断成了两半,从结点 b 往后的所有结点都无法访问到了。</p><p>对于有些语言来说,比如 C 语言,内存管理是由程序员负责的,如果没有手动释放结点对应的内存空间,就会产生内存泄露。所以,我们插入结点时,一定要注意操作的顺序,要先将结点 x 的 next 指针指向结点 b,再把结点 a 的 next 指针指向结点 x,这样才不会丢失指针,导致内存泄漏。所以,对于刚刚的插入代码,我们只需要把第 1 行和第 2 行代码的顺序颠倒一下就可以了。</p><p>同理,删除链表结点时,也一定要记得手动释放内存空间,否则,也会出现内存泄漏的问题。当然,对于像 Java 这种虚拟机自动管理内存的编程语言来说,就不需要考虑这么多了。</p><h4 id="利用哨兵简化实现难度"><a href="#利用哨兵简化实现难度" class="headerlink" title="利用哨兵简化实现难度"></a>利用哨兵简化实现难度</h4><p>首先,我们先来回顾一下单链表的插入和删除操作。如果我们在结点 p 后面插入一个新的结点,只需要下面两行代码就可以搞定。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c">new_node->next = p->next;<br>p->next = new_node;<br></code></pre></td></tr></table></figure><p>但是,当我们要向一个空链表中插入第一个结点,刚刚的逻辑就不能用了。我们需要进行下面这样的特殊处理,其中 head 表示链表的头结点。所以,从这段代码,我们可以发现,对于单链表的插入操作,第一个结点和其他结点的插入逻辑是不一样的。</p><figure class="highlight c"><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><code class="hljs c"><span class="hljs-keyword">if</span> (head == null) {<br> head = new_node;<br>}<br></code></pre></td></tr></table></figure><p>我们再来看单链表结点删除操作。如果要删除结点 p 的后继结点,我们只需要一行代码就可以搞定。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c">p->next = p->next->next;<br></code></pre></td></tr></table></figure><p>但是,如果我们要删除链表中的最后一个结点,前面的删除代码就不 work 了。跟插入类似,我们也需要对于这种情况特殊处理。写成代码是这样子的:</p><figure class="highlight c"><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><code class="hljs c"><span class="hljs-keyword">if</span> (head->next == null) {<br> head = null;<br>}<br></code></pre></td></tr></table></figure><p>从前面的一步一步分析,我们可以看出,针对链表的插入、删除操作,需要对插入第一个结点和删除最后一个结点的情况进行特殊处理。这样代码实现起来就会很繁琐,不简洁,而且也容易因为考虑不全而出错。如何来解决这个问题呢?</p><p>技巧三中提到的哨兵就要登场了。哨兵,解决的是国家之间的边界问题。同理,这里说的哨兵也是解决“边界问题”的,不直接参与业务逻辑。</p><p>还记得如何表示一个空链表吗?head=null 表示链表中没有结点了。其中 head 表示头结点指针,指向链表中的第一个结点。</p><p>如果我们引入哨兵结点,在任何时候,不管链表是不是空,head 指针都会一直指向这个哨兵结点。我们也把这种有哨兵结点的链表叫带头链表。相反,没有哨兵结点的链表就叫作不带头链表。</p><p>如图,你可以发现,哨兵结点是不存储数据的。因为哨兵结点一直存在,所以插入第一个结点和插入其他结点,删除最后一个结点和删除其他结点,都可以统一为相同的代码实现逻辑了。</p><img src="https://static001.geekbang.org/resource/image/7d/c7/7d22d9428bdbba96bfe388fe1e3368c7.jpg"><p>实际上,这种利用哨兵简化编程难度的技巧,在很多代码实现中都有用到,比如插入排序、归并排序、动态规划等。现在为了让你感受更深,我再举一个非常简单的例子。代码我是用 C 语言实现的,不涉及语言方面的高级语法,很容易看懂,你可以类比到你熟悉的语言。</p><p>代码一:</p><figure class="highlight c"><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><code class="hljs c"><span class="hljs-comment">// 在数组a中,查找key,返回key所在的位置</span><br><span class="hljs-comment">// 其中,n表示数组a的长度</span><br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">find</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* a, <span class="hljs-keyword">int</span> n, <span class="hljs-keyword">char</span> key)</span> </span>{<br> <span class="hljs-comment">// 边界条件处理,如果a为空,或者n<=0,说明数组中没有数据,就不用while循环比较了</span><br> <span class="hljs-keyword">if</span>(a == null || n <= <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<br> }<br> <br> <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;<br> <span class="hljs-comment">// 这里有两个比较操作:i<n和a[i]==key.</span><br> <span class="hljs-keyword">while</span> (i < n) {<br> <span class="hljs-keyword">if</span> (a[i] == key) {<br> <span class="hljs-keyword">return</span> i;<br> }<br> ++i;<br> }<br> <br> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<br>}<br></code></pre></td></tr></table></figure><p>代码二:</p><figure class="highlight c"><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></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">// 在数组a中,查找key,返回key所在的位置</span><br><span class="hljs-comment">// 其中,n表示数组a的长度</span><br><span class="hljs-comment">// 我举2个例子,你可以拿例子走一下代码</span><br><span class="hljs-comment">// a = {4, 2, 3, 5, 9, 6} n=6 key = 7</span><br><span class="hljs-comment">// a = {4, 2, 3, 5, 9, 6} n=6 key = 6</span><br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">find</span><span class="hljs-params">(<span class="hljs-keyword">char</span>* a, <span class="hljs-keyword">int</span> n, <span class="hljs-keyword">char</span> key)</span> </span>{<br> <span class="hljs-keyword">if</span>(a == null || n <= <span class="hljs-number">0</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<br> }<br> <br> <span class="hljs-comment">// 这里因为要将a[n-1]的值替换成key,所以要特殊处理这个值</span><br> <span class="hljs-keyword">if</span> (a[n<span class="hljs-number">-1</span>] == key) {<br> <span class="hljs-keyword">return</span> n<span class="hljs-number">-1</span>;<br> }<br> <br> <span class="hljs-comment">// 把a[n-1]的值临时保存在变量tmp中,以便之后恢复。tmp=6。</span><br> <span class="hljs-comment">// 之所以这样做的目的是:希望find()代码不要改变a数组中的内容</span><br> <span class="hljs-keyword">char</span> tmp = a[n<span class="hljs-number">-1</span>];<br> <span class="hljs-comment">// 把key的值放到a[n-1]中,此时a = {4, 2, 3, 5, 9, 7}</span><br> a[n<span class="hljs-number">-1</span>] = key;<br> <br> <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;<br> <span class="hljs-comment">// while 循环比起代码一,少了i<n这个比较操作</span><br> <span class="hljs-keyword">while</span> (a[i] != key) {<br> ++i;<br> }<br> <br> <span class="hljs-comment">// 恢复a[n-1]原来的值,此时a= {4, 2, 3, 5, 9, 6}</span><br> a[n<span class="hljs-number">-1</span>] = tmp;<br> <br> <span class="hljs-keyword">if</span> (i == n<span class="hljs-number">-1</span>) {<br> <span class="hljs-comment">// 如果i == n-1说明,在0...n-2之间都没有key,所以返回-1</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">// 否则,返回i,就是等于key值的元素的下标</span><br> <span class="hljs-keyword">return</span> i;<br> }<br>}<br></code></pre></td></tr></table></figure><p>对比两段代码,在字符串 a 很长的时候,比如几万、几十万,你觉得哪段代码运行得更快点呢?答案是代码二,因为两段代码中执行次数最多就是 while 循环那一部分。第二段代码中,我们通过一个哨兵 a[n-1] = key,成功省掉了一个比较语句 i</p><p>当然,这只是为了举例说明哨兵的作用,你写代码的时候千万不要写第二段那样的代码,因为可读性太差了。大部分情况下,我们并不需要如此追求极致的性能。</p><h4 id="重点留意边界条件处理"><a href="#重点留意边界条件处理" class="headerlink" title="重点留意边界条件处理"></a>重点留意边界条件处理</h4><p>软件开发中,代码在一些边界或者异常情况下,最容易产生 Bug。链表代码也不例外。要实现没有 Bug 的链表代码,一定要在编写的过程中以及编写完成之后,检查边界条件是否考虑全面,以及代码在边界条件下是否能正确运行。</p><p>可参考以下几个方面:</p><ul><li>如果链表为空时,代码是否能正常工作?</li><li>如果链表只包含一个结点时,代码是否能正常工作?</li><li>如果链表只包含两个结点时,代码是否能正常工作?</li><li>代码逻辑在处理头结点和尾结点的时候,是否能正常工作?</li></ul><h4 id="举例画图,辅助思考"><a href="#举例画图,辅助思考" class="headerlink" title="举例画图,辅助思考"></a>举例画图,辅助思考</h4><p>对于稍微复杂的链表操作,比如前面我们提到的单链表反转,指针一会儿指这,一会儿指那,一会儿就被绕晕了。总感觉脑容量不够,想不清楚。所以这个时候就要使用大招了,举例法和画图法。</p><p>你可以找一个具体的例子,把它画在纸上,释放一些脑容量,留更多的给逻辑思考,这样就会感觉到思路清晰很多。比如往单链表中插入一个数据这样一个操作,我一般都是把各种情况都举一个例子,画出插入前和插入后的链表变化,如图所示:</p><img src="https://static001.geekbang.org/resource/image/4a/f8/4a701dd79b59427be654261805b349f8.jpg"><p>转自 《数据结构与算法之美》</p>]]></content>
<categories>
<category>算法</category>
</categories>
</entry>
<entry>
<title>数组介绍</title>
<link href="/2021/07/05/array-introduction/"/>
<url>/2021/07/05/array-introduction/</url>
<content type="html"><![CDATA[<h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><p>数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。</p><ul><li><p>线性表(Linear List)。顾名思义,线性表就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。其实除了数组,链表、队列、栈等也是线性表结构。</p> <img src="https://static001.geekbang.org/resource/image/b6/77/b6b71ec46935130dff5c4b62cf273477.jpg"/><p> 与它相对立的概念是非线性表,比如二叉树、堆、图等。之所以叫非线性,是因为,在非线性表中,数据之间并不是简单的前后关系。</p> <img src="https://static001.geekbang.org/resource/image/6e/69/6ebf42641b5f98f912d36f6bf86f6569.jpg"/></li><li><p>连续的内存空间和相同类型的数据。正是因为这两个限制,它才有了一个堪称“杀手锏”的特性:“随机访问”。但有利就有弊,这两个限制也让数组的很多操作变得非常低效,比如要想在数组中删除、插入一个数据,为了保证连续性,就需要做大量的数据搬移工作。</p></li></ul><h3 id="数组是如何实现根据下标随机访问数组元素的"><a href="#数组是如何实现根据下标随机访问数组元素的" class="headerlink" title="数组是如何实现根据下标随机访问数组元素的"></a>数组是如何实现根据下标随机访问数组元素的</h3><p>拿一个长度为 10 的 int 类型的数组 int[] a = new int[10]来举例。在我画的这个图中,计算机给数组 a[10],分配了一块连续内存空间 1000~1039,其中,内存块的首地址为 base_address = 1000。</p><img src="https://static001.geekbang.org/resource/image/98/c4/98df8e702b14096e7ee4a5141260cdc4.jpg"><p>我们知道,计算机会给每个内存单元分配一个地址,计算机通过地址来访问内存中的数据。当计算机需要随机访问数组中的某个元素时,它会首先通过下面的寻址公式,计算出该元素存储的内存地址:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c">a[i]_address = base_address + i * data_type_size<br></code></pre></td></tr></table></figure><p>其中 data_type_size 表示数组中每个元素的大小。我们举的这个例子里,数组中存储的是 int 类型数据,所以 data_type_size 就为 4 个字节。</p><p>数组支持随机访问,根据下标随机访问的时间复杂度为 O(1)。</p><h3 id="低效的“插入”和“删除”"><a href="#低效的“插入”和“删除”" class="headerlink" title="低效的“插入”和“删除”"></a>低效的“插入”和“删除”</h3><ul><li>插入操作</li></ul><p>假设数组的长度为 n,现在,如果我们需要将一个数据插入到数组中的第 k 个位置。为了把第 k 个位置腾出来,给新来的数据,我们需要将第 k~n 这部分的元素都顺序地往后挪一位。那插入操作的时间复杂度是多少呢?</p><p>如果在数组的末尾插入元素,那就不需要移动数据了,这时的时间复杂度为 O(1)。但如果在数组的开头插入元素,那所有的数据都需要依次往后移动一位,所以最坏时间复杂度是 O(n)。 因为我们在每个位置插入元素的概率是一样的,所以平均情况时间复杂度为 (1+2+…n)/n=O(n)。</p><p>如果数组中的数据是有序的,我们在某个位置插入一个新的元素时,就必须按照刚才的方法搬移 k 之后的数据。但是,如果数组中存储的数据并没有任何规律,数组只是被当作一个存储数据的集合。在这种情况下,如果要将某个数据插入到第 k 个位置,为了避免大规模的数据搬移,我们还有一个简单的办法就是,直接将第 k 位的数据搬移到数组元素的最后,把新的元素直接放入第 k 个位置。</p><p>举一个例子。假设数组 a[10]中存储了如下 5 个元素:a,b,c,d,e。</p><p>我们现在需要将元素 x 插入到第 3 个位置。我们只需要将 c 放入到 a[5],将 a[2]赋值为 x 即可。最后,数组中的元素如下: a,b,x,d,e,c。</p><img src="https://static001.geekbang.org/resource/image/3f/dc/3f70b4ad9069ec568a2caaddc231b7dc.jpg"><p>利用这种处理技巧,在特定场景下,在第 k 个位置插入一个元素的时间复杂度就会降为 O(1)。</p><ul><li>删除操作</li></ul><p>跟插入数据类似,如果我们要删除第 k 个位置的数据,为了内存的连续性,也需要搬移数据,不然中间就会出现空洞,内存就不连续了。</p><p>和插入类似,如果删除数组末尾的数据,则最好情况时间复杂度为 O(1);如果删除开头的数据,则最坏情况时间复杂度为 O(n);平均情况时间复杂度也为 O(n)。</p><p>举个例子,数组 a[10]中存储了 8 个元素:a,b,c,d,e,f,g,h。现在,我们要依次删除 a,b,c 三个元素。</p><img src="https://static001.geekbang.org/resource/image/b6/e5/b69b8c5dbf6248649ddab7d3e7cfd7e5.jpg"><p>为了避免 d,e,f,g,h 这几个数据会被搬移三次,我们可以先记录下已经删除的数据。每次的删除操作并不是真正地搬移数据,只是记录数据已经被删除。当数组没有更多空间存储数据时,我们再触发执行一次真正的删除操作,这样就大大减少了删除操作导致的数据搬移。</p><h3 id="警惕数组的访问越界问题"><a href="#警惕数组的访问越界问题" class="headerlink" title="警惕数组的访问越界问题"></a>警惕数组的访问越界问题</h3><figure class="highlight c"><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></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">int</span> argc, <span class="hljs-keyword">char</span>* argv[])</span></span>{<br> <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">int</span> arr[<span class="hljs-number">3</span>] = {<span class="hljs-number">0</span>};<br> <span class="hljs-keyword">for</span>(; i<=<span class="hljs-number">3</span>; i++){<br> arr[i] = <span class="hljs-number">0</span>;<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"hello world\n"</span>);<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><p>这段代码的运行结果并非是打印三行“hello word”,而是会无限打印“hello world”,这是为什么呢?</p><p>因为,数组大小为 3,a[0],a[1],a[2],而我们的代码因为书写错误,导致 for 循环的结束条件错写为了 i<=3 而非 i<3,所以当 i=3 时,数组 a[3]访问越界。</p><p>在 C 语言中,只要不是访问受限的内存,所有的内存空间都是可以自由访问的。根据我们前面讲的数组寻址公式,a[3]也会被定位到某块不属于数组的内存地址上,而这个地址正好是存储变量 i 的内存地址,那么 a[3]=0 就相当于 i=0,所以就会导致代码无限循环。</p><h3 id="容器能否完全替代数组?"><a href="#容器能否完全替代数组?" class="headerlink" title="容器能否完全替代数组?"></a>容器能否完全替代数组?</h3><p>数组本身在定义的时候需要预先指定大小,因为需要分配连续的内存空间。如果我们申请了大小为 10 的数组,当第 11 个数据需要存储到数组中时,我们就需要重新分配一块更大的空间,将原来的数据复制过去,然后再将新的数据插入。</p><p>如果使用 ArrayList,我们就完全不需要关心底层的扩容逻辑,ArrayList 已经帮我们实现好了。每次存储空间不够的时候,它都会将空间自动扩容为 1.5 倍大小。</p><p>不过,这里需要注意一点,因为扩容操作涉及内存申请和数据搬移,是比较耗时的。所以,如果事先能确定需要存储的数据大小,最好在创建 ArrayList 的时候事先指定数据大小。</p><h3 id="数组的使用"><a href="#数组的使用" class="headerlink" title="数组的使用"></a>数组的使用</h3><ul><li><p>Java ArrayList 无法存储基本类型,比如 int、long,需要封装为 Integer、Long 类,而 Autoboxing、Unboxing 则有一定的性能消耗,所以如果特别关注性能,或者希望使用基本类型,就可以选用数组。</p></li><li><p>如果数据大小事先已知,并且对数据的操作非常简单,用不到 ArrayList 提供的大部分方法,也可以直接使用数组。</p></li><li><p>还有一个是我个人的喜好,当要表示多维数组时,用数组往往会更加直观。比如 Object[][] array;而用容器的话则需要这样定义:ArrayList > array。</p></li></ul><h3 id="为什么数组要从-0-开始编号而不是-1-?"><a href="#为什么数组要从-0-开始编号而不是-1-?" class="headerlink" title="为什么数组要从 0 开始编号而不是 1 ?"></a>为什么数组要从 0 开始编号而不是 1 ?</h3><p>从数组存储的内存模型上来看,“下标”最确切的定义应该是“偏移(offset)”。前面也讲到,如果用 a 来表示数组的首地址,a[0]就是偏移为 0 的位置,也就是首地址,a[k]就表示偏移 k 个 type_size 的位置,所以计算 a[k]的内存地址只需要用这个公式:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c">a[k]_address = base_address + k * type_size<br></code></pre></td></tr></table></figure><p>但是,如果数组从 1 开始计数,那我们计算数组元素 a[k]的内存地址就会变为:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c">a[k]_address = base_address + (k<span class="hljs-number">-1</span>)*type_size<br></code></pre></td></tr></table></figure><p>对比两个公式,我们不难发现,从 1 开始编号,每次随机访问数组元素都多了一次减法运算,对于 CPU 来说,就是多了一次减法指令。</p><p>数组作为非常基础的数据结构,通过下标随机访问数组元素又是其非常基础的编程操作,效率的优化就要尽可能做到极致。所以为了减少一次减法操作,数组选择了从 0 开始编号,而不是从 1 开始。</p><p>上面解释得再多其实都算不上压倒性的证明,说数组起始编号非 0 开始不可。所以我觉得最主要的原因可能是历史原因。</p><p>C 语言设计者用 0 开始计数数组下标,之后的 Java、JavaScript 等高级语言都效仿了 C 语言,或者说,为了在一定程度上减少 C 语言程序员学习 Java 的学习成本,因此继续沿用了从 0 开始计数的习惯。实际上,很多语言中数组也并不是从 0 开始计数的,比如 Matlab。甚至还有一些语言支持负数下标,比如 Python。</p><p>转自《数据结构与算法之美》</p>]]></content>
<categories>
<category>算法</category>
</categories>
</entry>
<entry>
<title>均摊时间复杂度</title>
<link href="/2021/07/05/amortized-time-complexity/"/>
<url>/2021/07/05/amortized-time-complexity/</url>
<content type="html"><![CDATA[<h2 id="均摊时间复杂度"><a href="#均摊时间复杂度" class="headerlink" title="均摊时间复杂度"></a>均摊时间复杂度</h2><figure class="highlight c"><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><code class="hljs c"><span class="hljs-comment">// array表示一个长度为n的数组</span><br><span class="hljs-comment">// 代码中的array.length就等于n</span><br><span class="hljs-keyword">int</span>[] <span class="hljs-built_in">array</span> = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[n];<br><span class="hljs-keyword">int</span> count = <span class="hljs-number">0</span>;<br><br><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">insert</span><span class="hljs-params">(<span class="hljs-keyword">int</span> val)</span> </span>{<br> <span class="hljs-keyword">if</span> (count == <span class="hljs-built_in">array</span>.length) {<br> <span class="hljs-keyword">int</span> sum = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-built_in">array</span>.length; ++i) {<br> sum = sum + <span class="hljs-built_in">array</span>[i];<br> }<br> <span class="hljs-built_in">array</span>[<span class="hljs-number">0</span>] = sum;<br> count = <span class="hljs-number">1</span>;<br> }<br><br> <span class="hljs-built_in">array</span>[count] = val;<br> ++count;<br>}<br></code></pre></td></tr></table></figure><p>这段代码实现了一个往数组中插入数据的功能。当数组满了之后,也就是代码中的 count == array.length 时,我们用 for 循环遍历数组求和,并清空数组,将求和之后的 sum 值放到数组的第一个位置,然后再将新的数据插入。但如果数组一开始就有空闲空间,则直接将数据插入数组。</p><p>最理想的情况下,数组中有空闲空间,我们只需要将数据插入到数组下标为 count 的位置就可以了,所以最好情况时间复杂度为 O(1)。最坏的情况下,数组中没有空闲空间了,我们需要先做一次数组的遍历求和,然后再将数据插入,所以最坏情况时间复杂度为 O(n)。</p><p>那平均时间复杂度是多少呢?答案是 O(1)。我们还是可以通过前面讲的概率论的方法来分析。</p><p>假设数组的长度是 n,根据数据插入的位置的不同,我们可以分为 n 种情况,每种情况的时间复杂度是 O(1)。除此之外,还有一种“额外”的情况,就是在数组没有空闲空间时插入一个数据,这个时候的时间复杂度是 O(n)。而且,这 n+1 种情况发生的概率一样,都是 1/(n+1)。所以,根据加权平均的计算方法,我们求得的平均时间复杂度就是:</p><img src="https://static001.geekbang.org/resource/image/6d/ed/6df62366a60336d9de3bc34f488d8bed.jpg"/><h3 id="摊还分析法"><a href="#摊还分析法" class="headerlink" title="摊还分析法"></a>摊还分析法</h3><p>find() 函数在极端情况下,复杂度才为 O(1)。但 insert() 在大部分情况下,时间复杂度都为 O(1)。只有个别情况下,复杂度才比较高,为 O(n)。这是 insert()第一个区别于 find() 的地方。</p><p>我们再来看第二个不同的地方。对于 insert() 函数来说,O(1) 时间复杂度的插入和 O(n) 时间复杂度的插入,出现的频率是非常有规律的,而且有一定的前后时序关系,一般都是一个 O(n) 插入之后,紧跟着 n-1 个 O(1) 的插入操作,循环往复。</p><p>所以,针对这样一种特殊场景的复杂度分析,我们并不需要像之前讲平均复杂度分析方法那样,找出所有的输入情况及相应的发生概率,然后再计算加权平均值。</p><p>针对这种特殊的场景,我们引入了一种更加简单的分析方法:摊还分析法,通过摊还分析得到的时间复杂度我们起了一个名字,叫均摊时间复杂度。</p><p>那究竟如何使用摊还分析法来分析算法的均摊时间复杂度呢?</p><p>我们还是继续看在数组中插入数据的这个例子。每一次 O(n) 的插入操作,都会跟着 n-1 次 O(1) 的插入操作,所以把耗时多的那次操作均摊到接下来的 n-1 次耗时少的操作上,均摊下来,这一组连续的操作的均摊时间复杂度就是 O(1)。这就是均摊分析的大致思路。</p><p>均摊时间复杂度和摊还分析应用场景比较特殊,所以我们并不会经常用到。为了方便你理解、记忆,我这里简单总结一下它们的应用场景。如果你遇到了,知道是怎么回事儿就行了。</p><p>对一个数据结构进行一组连续操作中,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度比较高,而且这些操作之间存在前后连贯的时序关系,这个时候,我们就可以将这一组操作放在一块儿分析,看是否能将较高时间复杂度那次操作的耗时,平摊到其他那些时间复杂度比较低的操作上。而且,在能够应用均摊时间复杂度分析的场合,一般均摊时间复杂度就等于最好情况时间复杂度。</p><p>尽管很多数据结构和算法书籍都花了很大力气来区分平均时间复杂度和均摊时间复杂度,但其实我个人认为,均摊时间复杂度就是一种特殊的平均时间复杂度,我们没必要花太多精力去区分它们。你最应该掌握的是它的分析方法,摊还分析。至于分析出来的结果是叫平均还是叫均摊,这只是个说法,并不重要。</p><p>转自《数据结构与算法之美》</p>]]></content>
<categories>
<category>算法</category>
</categories>
</entry>
<entry>
<title>最好、最坏、平均情况时间复杂度</title>
<link href="/2021/07/05/some-time-complexity/"/>
<url>/2021/07/05/some-time-complexity/</url>
<content type="html"><![CDATA[<h2 id="最好、最坏情况时间复杂度"><a href="#最好、最坏情况时间复杂度" class="headerlink" title="最好、最坏情况时间复杂度"></a>最好、最坏情况时间复杂度</h2><figure class="highlight c"><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></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">// n表示数组array的长度</span><br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">find</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] <span class="hljs-built_in">array</span>, <span class="hljs-keyword">int</span> n, <span class="hljs-keyword">int</span> x)</span> </span>{<br> <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">int</span> pos = <span class="hljs-number">-1</span>;<br> <span class="hljs-keyword">for</span> (; i < n; ++i) {<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">array</span>[i] == x) pos = i;<br> }<br> <span class="hljs-keyword">return</span> pos;<br>}<br></code></pre></td></tr></table></figure><p>这段代码要实现的功能是,在一个无序的数组(array)中,查找变量 x 出现的位置。如果没有找到,就返回 -1。按照上节课讲的分析方法,这段代码的复杂度是 $O(n)$,其中,n 代表数组的长度。</p><p>我们在数组中查找一个数据,并不需要每次都把整个数组都遍历一遍,因为有可能中途找到就可以提前结束循环了。但是,这段代码写得不够高效。我们可以这样优化一下这段查找代码。</p><figure class="highlight c"><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><code class="hljs c"><span class="hljs-comment">// n表示数组array的长度</span><br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">find</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] <span class="hljs-built_in">array</span>, <span class="hljs-keyword">int</span> n, <span class="hljs-keyword">int</span> x)</span> </span>{<br> <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">int</span> pos = <span class="hljs-number">-1</span>;<br> <span class="hljs-keyword">for</span> (; i < n; ++i) {<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">array</span>[i] == x) {<br> pos = i;<br> <span class="hljs-keyword">break</span>;<br> }<br> }<br> <span class="hljs-keyword">return</span> pos;<br>}<br></code></pre></td></tr></table></figure><p>这个时候,问题就来了。我们优化完之后,这段代码的时间复杂度还是 O(n) 吗?</p><p>要查找的变量 x 可能出现在数组的任意位置。如果数组中第一个元素正好是要查找的变量 x,那就不需要继续遍历剩下的 n-1 个数据了,那时间复杂度就是 O(1)。但如果数组中不存在变量 x,那我们就需要把整个数组都遍历一遍,时间复杂度就成了 O(n)。所以,不同的情况下,这段代码的时间复杂度是不一样的。</p><p>为了表示代码在不同情况下的不同时间复杂度,我们需要引入三个概念:最好情况时间复杂度、最坏情况时间复杂度和平均情况时间复杂度。</p><h3 id="最好情况时间复杂度"><a href="#最好情况时间复杂度" class="headerlink" title="最好情况时间复杂度"></a>最好情况时间复杂度</h3><p>在最理想的情况下,执行这段代码的时间复杂度。就像我们刚刚讲到的,在最理想的情况下,要查找的变量 x 正好是数组的第一个元素,这个时候对应的时间复杂度就是最好情况时间复杂度。</p><h3 id="最坏情况时间复杂度"><a href="#最坏情况时间复杂度" class="headerlink" title="最坏情况时间复杂度"></a>最坏情况时间复杂度</h3><p>在最糟糕的情况下,执行这段代码的时间复杂度。就像刚举的那个例子,如果数组中没有要查找的变量 x,我们需要把整个数组都遍历一遍才行,所以这种最糟糕情况下对应的时间复杂度就是最坏情况时间复杂度。</p><h3 id="平均情况时间复杂度"><a href="#平均情况时间复杂度" class="headerlink" title="平均情况时间复杂度"></a>平均情况时间复杂度</h3><p>好情况时间复杂度和最坏情况时间复杂度对应的都是极端情况下的代码复杂度,发生的概率其实并不大。为了更好地表示平均情况下的复杂度,我们需要引入另一个概念:平均情况时间复杂度,后面简称为平均时间复杂度。</p><p>要查找的变量 x 在数组中的位置,有 n+1 种情况:在数组的 0~n-1 位置中和不在数组中。我们把每种情况下,查找需要遍历的元素个数累加起来,然后再除以 n+1,就可以得到需要遍历的元素个数的平均值,即:</p><img src="https://static001.geekbang.org/resource/image/d8/2f/d889a358b8eccc5bbb90fc16e327a22f.jpg"/><p>我们知道,时间复杂度的大 O 标记法中,可以省略掉系数、低阶、常量,所以,咱们把刚刚这个公式简化之后,得到的平均时间复杂度就是 O(n)。</p><p>这个结论虽然是正确的,但是计算过程稍微有点儿问题。究竟是什么问题呢?我们刚讲的这 n+1 种情况,出现的概率并不是一样的。</p><p>我们知道,要查找的变量 x,要么在数组里,要么就不在数组里。这两种情况对应的概率统计起来很麻烦,为了方便你理解,我们假设在数组中与不在数组中的概率都为 1/2。另外,要查找的数据出现在 0~n-1 这 n 个位置的概率也是一样的,为 1/n。所以,根据概率乘法法则,要查找的数据出现在 0~n-1 中任意位置的概率就是 1/(2n)。</p><p>因此,前面的推导过程中存在的最大问题就是,没有将各种情况发生的概率考虑进去。如果我们把每种情况发生的概率也考虑进去,那平均时间复杂度的计算过程就变成了这样:</p><img src="https://static001.geekbang.org/resource/image/36/7f/36c0aabdac69032f8a43368f5e90c67f.jpg"/><p>这个值就是概率论中的加权平均值,也叫作期望值,所以平均时间复杂度的全称应该叫加权平均时间复杂度或者期望时间复杂度。</p><p>引入概率之后,前面那段代码的加权平均值为 (3n+1)/4。用大 O 表示法来表示,去掉系数和常量,这段代码的加权平均时间复杂度仍然是 O(n)。</p><p>转自《数据结构与算法之美》</p>]]></content>
<categories>
<category>算法</category>
</categories>
</entry>
<entry>
<title>空间复杂度介绍</title>
<link href="/2021/07/05/space-complexity/"/>
<url>/2021/07/05/space-complexity/</url>
<content type="html"><![CDATA[<h2 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h2><p>空间复杂度表示算法的存储空间与数据规模之间的增长关系。</p><figure class="highlight c"><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></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-keyword">int</span> n)</span> </span>{<br> <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">int</span>[] a = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[n];<br> <span class="hljs-keyword">for</span> (i; i <n; ++i) {<br> a[i] = i * i;<br> }<br><br> <span class="hljs-keyword">for</span> (i = n<span class="hljs-number">-1</span>; i >= <span class="hljs-number">0</span>; --i) {<br> print out a[i]<br> }<br>}<br></code></pre></td></tr></table></figure><p>跟时间复杂度分析一样,我们可以看到,第 2 行代码中,我们申请了一个空间存储变量 i,但是它是常量阶的,跟数据规模 n 没有关系,所以我们可以忽略。第 3 行申请了一个大小为 n 的 int 类型数组,除此之外,剩下的代码都没有占用更多的空间,所以整段代码的空间复杂度就是 $O(n)$。</p><p>我们常见的空间复杂度就是 O(1)、O(n)、O(n2 ),像 O(logn)、O(nlogn) 这样的对数阶复杂度平时都用不到。而且,空间复杂度分析比时间复杂度分析要简单很多。所以,对于空间复杂度,掌握刚我说的这些内容已经足够了。</p>]]></content>
<categories>
<category>算法</category>
</categories>
</entry>
<entry>
<title>时间复杂度介绍</title>
<link href="/2021/07/05/time-complexity/"/>
<url>/2021/07/05/time-complexity/</url>
<content type="html"><![CDATA[<h2 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h2><h3 id="O-1"><a href="#O-1" class="headerlink" title="$O(1)$"></a>$O(1)$</h3><p>首先你必须明确一个概念,$O(1)$ 只是常量级时间复杂度的一种表示方法,并不是指只执行了一行代码。比如这段代码,即便有 3 行,它的时间复杂度也是 $O(1)$,而不是 $O(3)$。</p><figure class="highlight c"><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><code class="hljs c"><span class="hljs-keyword">int</span> i = <span class="hljs-number">8</span>;<br><span class="hljs-keyword">int</span> j = <span class="hljs-number">6</span>; <br><span class="hljs-keyword">int</span> sum = i + j;<br></code></pre></td></tr></table></figure><p>只要代码的执行时间不随 n 的增大而增长,这样代码的时间复杂度我们都记作 O(1)。或者说,一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)。</p><h3 id="O-logn-、-O-nlogn"><a href="#O-logn-、-O-nlogn" class="headerlink" title="$O(logn)$、$O(nlogn)$"></a>$O(logn)$、$O(nlogn)$</h3><p>对数阶时间复杂度非常常见,同时也是最难分析的一种时间复杂度。我通过一个例子来说明一下。</p><figure class="highlight c"><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><code class="hljs c">i=<span class="hljs-number">1</span>;<br><br><span class="hljs-keyword">while</span> (i <= n)<br> { <br> i = i * <span class="hljs-number">2</span>; <br> }<br></code></pre></td></tr></table></figure><p>根据我们前面讲的复杂度分析方法,第三行代码是循环执行次数最多的。所以,我们只要能计算出这行代码被执行了多少次,就能知道整段代码的时间复杂度。</p><p>从代码中可以看出,变量 i 的值从 1 开始取,每循环一次就乘以 2。当大于 n 时,循环结束。还记得我们高中学过的等比数列吗?实际上,变量 i 的取值就是一个等比数列。如果我把它一个一个列出来,就应该是这个样子的:</p><img src="https://static001.geekbang.org/resource/image/9b/9a/9b1c88264e7a1a20b5954be9bc4bec9a.jpg"/><p>所以,我们只要知道 $x$ 值是多少,就知道这行代码执行的次数了。通过 $2x=n$ 求解 $x$ 这个问题我们想高中应该就学过了,我就不多说了。$x=log_2n$,所以,这段代码的时间复杂度就是 $O(log_2n)$。</p><p>现在,我把代码稍微改下,你再看看,这段代码的时间复杂度是多少?</p><figure class="highlight c"><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><code class="hljs c">i=<span class="hljs-number">1</span>; <br><span class="hljs-keyword">while</span> (i <= n) <br> { <br> i = i * <span class="hljs-number">3</span>; <br> }<br></code></pre></td></tr></table></figure><p>根据我刚刚讲的思路,很简单就能看出来,这段代码的时间复杂度为 $O(log_3n)$。</p><p>实际上,不管是以 2 为底、以 3 为底,还是以 10 为底,我们可以把所有对数阶的时间复杂度都记为 $O(logn)$。为什么呢?</p><p>我们知道,对数之间是可以互相转换的,$log_3n$ 就等于 $log_32 * log_2n$,所以 $O(log_3n) = O(C * log_2n)$,其中 $C=log_32$ 是一个常量。基于我们前面的一个理论:在采用大 O 标记复杂度的时候,可以忽略系数,即 $O(Cf(n)) = O(f(n))$。所以,$O(log_2n)$ 就等于 $O(log_3n)$。因此,在对数阶时间复杂度的表示方法里,我们忽略对数的“底”,统一表示为 O(logn)。</p><p>如果你理解了我前面讲的 $O(logn)$,那 $O(nlogn)$ 就很容易理解了。还记得我们刚讲的乘法法则吗?如果一段代码的时间复杂度是 $O(logn)$,我们循环执行 n 遍,时间复杂度就是 $O(nlogn)$ 了。而且,$O(nlogn)$ 也是一种非常常见的算法时间复杂度。比如,归并排序、快速排序的时间复杂度都是 $O(nlogn)$。</p><h3 id="O-m-n-、O-m-n"><a href="#O-m-n-、O-m-n" class="headerlink" title="$O(m+n)、O(m*n)$"></a>$O(m+n)、O(m*n)$</h3><p>我们再来讲一种跟前面都不一样的时间复杂度,代码的复杂度由两个数据的规模来决定。</p><figure class="highlight c"><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><code class="hljs c"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">cal</span><span class="hljs-params">(<span class="hljs-keyword">int</span> m, <span class="hljs-keyword">int</span> n)</span> </span>{<br> <span class="hljs-keyword">int</span> sum_1 = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>;<br> <span class="hljs-keyword">for</span> (; i < m; ++i) {<br> sum_1 = sum_1 + i;<br> }<br><br> <span class="hljs-keyword">int</span> sum_2 = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">int</span> j = <span class="hljs-number">1</span>;<br> <span class="hljs-keyword">for</span> (; j < n; ++j) {<br> sum_2 = sum_2 + j;<br> }<br><br> <span class="hljs-keyword">return</span> sum_1 + sum_2;<br>}<br></code></pre></td></tr></table></figure><p>从代码中可以看出,m 和 n 是表示两个数据规模。我们无法事先评估 m 和 n 谁的量级大,所以我们在表示复杂度的时候,就不能简单地利用加法法则,省略掉其中一个。所以,上面代码的时间复杂度就是 $O(m+n)$。</p><p>针对这种情况,原来的加法法则就不正确了,我们需要将加法规则改为:$T1(m) + T2(n) = O(f(m) + g(n))$。但是乘法法则继续有效:$T1(m)*T2(n) = O(f(m) * f(n))$。</p><p>转自《数据结构与算法之美》</p>]]></content>
<categories>
<category>算法</category>
</categories>
</entry>
<entry>
<title>TypeScript 装饰器</title>
<link href="/2021/07/03/decorators/"/>
<url>/2021/07/03/decorators/</url>
<content type="html"><![CDATA[<p>装饰器 是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。</p><h2 id="预备知识"><a href="#预备知识" class="headerlink" title="预备知识"></a>预备知识</h2><h3 id="装饰器工厂"><a href="#装饰器工厂" class="headerlink" title="装饰器工厂"></a>装饰器工厂</h3><p>如果我们要定制一个修饰器应用到一个声明上,我们得写一个装饰器工厂函数。 装饰器工厂就是一个简单的函数,它返回一个表达式,以供装饰器在运行时调用。</p><p>例如:</p><figure class="highlight typescript"><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><code class="hljs typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">color</span>(<span class="hljs-params">value: <span class="hljs-built_in">string</span></span>) </span>{ <span class="hljs-comment">// 这是一个装饰器工厂</span><br> <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target</span>) </span>{ <span class="hljs-comment">// 这是装饰器</span><br> <span class="hljs-comment">// do something with "target" and "value"...</span><br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="属性描述符"><a href="#属性描述符" class="headerlink" title="属性描述符"></a>属性描述符</h3><p>Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。</p><figure class="highlight typescript"><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><code class="hljs typescript"><span class="hljs-comment">/**</span><br><span class="hljs-comment">* obj: 要定义属性的对象。</span><br><span class="hljs-comment">* prop: 要定义或修改的属性的名称或 Symbol 。</span><br><span class="hljs-comment">* descriptor: 要定义或修改的属性描述符。</span><br><span class="hljs-comment">*/</span><br><span class="hljs-built_in">Object</span>.defineProperty(obj, prop, descriptor)<br></code></pre></td></tr></table></figure><p>该方法允许精确地添加或修改对象的属性。默认的情况下,使用 Object.defineProperty() 添加的属性值是不可修改(immutable)的。</p><h3 id="数据描述符"><a href="#数据描述符" class="headerlink" title="数据描述符"></a>数据描述符</h3><p>数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。</p><h3 id="存取描述符"><a href="#存取描述符" class="headerlink" title="存取描述符"></a>存取描述符</h3><p>存取描述符是由 getter 函数和setter 函数所描述的属性。</p><h3 id="Reflect"><a href="#Reflect" class="headerlink" title="Reflect"></a>Reflect</h3><h5 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h5><p>Reflect是 ES6 为了操作对象而提供的新 API。Reflect对象的设计目的有这样几个。</p><p>将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty),放到 Reflect 对象上。现阶段,某些方法同时在 Object和 Reflect 对象上部署,未来的新方法将只部署在 Reflect 对象上。也就是说,从 Reflect 对象上可以拿到语言内部的方法。</p><p>修改某些 Object 方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而 Reflect.defineProperty(obj, name, desc) 则会返回 false。</p><p>让 Object 操作都变成函数行为。某些 Object 操作是命令式,比如 name in obj 和 delete obj[name],而 Reflect.has(obj, name) 和Reflect.deleteProperty(obj, name) 让它们变成了函数行为。</p><p>Reflect 对象的方法与 Proxy 对象的方法一一对应,只要是 Proxy 对象的方法,就能在 Reflect 对象上找到对应的方法。这就让 Proxy 对象可以方便地调用对应的 Reflect 方法,完成默认行为,作为修改行为的基础。也就是说,不管 Proxy 怎么修改默认行为,你总可以在Reflect 上获取默认行为。</p><h2 id="类装饰器"><a href="#类装饰器" class="headerlink" title="类装饰器"></a>类装饰器</h2><p>类装饰器应用于类构造函数,可以用来监视,修改或替换类定义</p><p>接口定义:</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">type</span> ClassDecorator = <span class="xml"><span class="hljs-tag"><<span class="hljs-name">TFunction</span> <span class="hljs-attr">extends</span> <span class="hljs-attr">Function</span>></span>(target: TFunction) => TFunction | void;</span><br><span class="xml">类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。</span><br></code></pre></td></tr></table></figure><p>首先,写一个最简单的装饰器:</p><p>decorator.ts :</p><figure class="highlight typescript"><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><code class="hljs typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">helloWorld</span>(<span class="hljs-params">target: <span class="hljs-built_in">any</span></span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello World!'</span>)<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'target :'</span>, target.toString())<br>}<br><br><span class="hljs-meta">@helloWorld</span><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloWorldClass</span> </span>{<br> <span class="hljs-attr">name</span>: <span class="hljs-built_in">string</span> = <span class="hljs-string">'jerome'</span><br> <br> <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> {<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'I am constructor.'</span>)<br> }<br><br> <span class="hljs-function"><span class="hljs-title">test</span>(<span class="hljs-params"></span>)</span> {<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'I am test method.'</span>)<br> }<br>}<br></code></pre></td></tr></table></figure><p>运行 tsc -p . 编译 ts 文件,生成 js 文件,并用 node 执行这个 js 文件:</p><figure class="highlight shell"><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><code class="hljs shell"><span class="hljs-meta">$</span><span class="bash"> node decorator/decorator.js</span> <br>hello World!<br>target : function HelloWorldClass() {<br> this.name = 'jerome';<br> console.log('I am constructor.');<br> }<br></code></pre></td></tr></table></figure><p>由此可见,装饰器在运行时就被执行,target 传递的就是 HelloWorldClass 类的构造函数,也印证了装饰器的定义中,它在运行时被调用,被装饰的声明信息作为参数传入。</p><p>接下来,我们解析一下这个 js 文件:</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">var</span> __decorate = (<span class="hljs-built_in">this</span> && <span class="hljs-built_in">this</span>.__decorate) || <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">decorators, target, key, desc</span>) </span>{<br> <span class="hljs-keyword">var</span> c = <span class="hljs-built_in">arguments</span>.length,<br> r = c < <span class="hljs-number">3</span> ? target : desc === <span class="hljs-literal">null</span> ? desc = <span class="hljs-built_in">Object</span>.getOwnPropertyDescriptor(target, key) : desc,<br> d;<br> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">Reflect</span> === <span class="hljs-string">"object"</span> && <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">Reflect</span>.decorate === <span class="hljs-string">"function"</span>) r = <span class="hljs-built_in">Reflect</span>.decorate(decorators, target, key, desc);<br> <span class="hljs-keyword">else</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = decorators.length - <span class="hljs-number">1</span>; i >= <span class="hljs-number">0</span>; i--)<br> <span class="hljs-keyword">if</span> (d = decorators[i]) r = (c < <span class="hljs-number">3</span> ? d(r) : c > <span class="hljs-number">3</span> ? d(target, key, r) : d(target, key)) || r;<br> <span class="hljs-keyword">return</span> c > <span class="hljs-number">3</span> && r && <span class="hljs-built_in">Object</span>.defineProperty(target, key, r), r;<br>};<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">helloWorld</span>(<span class="hljs-params">target</span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello World!'</span>);<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'target :'</span>, target.toString());<br>}<br><span class="hljs-keyword">var</span> HelloWorldClass = <span class="hljs-comment">/** <span class="hljs-doctag">@class </span>*/</span> (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HelloWorldClass</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">this</span>.name = <span class="hljs-string">'jerome'</span>;<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'I am constructor.'</span>);<br> }<br> HelloWorldClass.prototype.test = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'I am test method.'</span>);<br> };<br> HelloWorldClass = __decorate([<br> helloWorld<br> ], HelloWorldClass);<br> <span class="hljs-keyword">return</span> HelloWorldClass;<br>}());<br></code></pre></td></tr></table></figure><p>代码太多,让我们分几步来解析:</p><p>@helloWorld 类装饰器解析</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">var</span> __decorate = (<span class="hljs-built_in">this</span> && <span class="hljs-built_in">this</span>.__decorate) || <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">decorators, target, key, desc</span>) </span>{<br> <span class="hljs-keyword">var</span> c = <span class="hljs-built_in">arguments</span>.length,<br> r = c < <span class="hljs-number">3</span> ? target : desc === <span class="hljs-literal">null</span> ? desc = <span class="hljs-built_in">Object</span>.getOwnPropertyDescriptor(target, key) : desc,<br> d;<br> <span class="hljs-comment">// 如果原生反射可用,使用原生反射触发装饰器</span><br> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">Reflect</span> === <span class="hljs-string">"object"</span> && <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">Reflect</span>.decorate === <span class="hljs-string">"function"</span>) r = <span class="hljs-built_in">Reflect</span>.decorate(decorators, target, key, desc);<br> <span class="hljs-keyword">else</span><br> <span class="hljs-comment">// 自右向左迭代装饰器</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = decorators.length - <span class="hljs-number">1</span>; i >= <span class="hljs-number">0</span>; i--)<br> <span class="hljs-comment">// 如果装饰器合法,将其赋值给 d</span><br> <span class="hljs-keyword">if</span> (d = decorators[i]) r = (c < <span class="hljs-number">3</span> ? d(r) : c > <span class="hljs-number">3</span> ? d(target, key, r) : d(target, key)) || r;<br> <span class="hljs-keyword">return</span> c > <span class="hljs-number">3</span> && r && <span class="hljs-built_in">Object</span>.defineProperty(target, key, r), r;<br>};<br></code></pre></td></tr></table></figure><p>第一行定义了 __decorate 函数,就是通过 @helloWorld 解析出来的,用来处理装饰器的功能。</p><p>这个函数有四个参数,让我们来看看都是些什么</p><figure class="highlight js"><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><code class="hljs js"> <span class="hljs-comment">/**</span><br><span class="hljs-comment"> * decorators: 数组,包含多个装饰器</span><br><span class="hljs-comment"> * target: 被装饰的类,即 HelloWorldClass 的构造函数</span><br><span class="hljs-comment"> * key: 变量名称</span><br><span class="hljs-comment"> * desc: 属性描述符</span><br><span class="hljs-comment">*/</span><br> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">decorators, target, key, desc</span>) </span>{...}<br></code></pre></td></tr></table></figure><p>c < 3 ? 为什么是 3,c 代表的是传入参数的个数,如果未传入属性描述符,r 都为 target,若传入属性描述符且不为空,则 r 为属性描述符。</p><p>通过对这段 js 的分析之后,可以简化为如下:</p> <figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> c = <span class="hljs-number">2</span>, r = target, d;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = decorators.length - <span class="hljs-number">1</span>; i >= <span class="hljs-number">0</span>; i--)<br> <span class="hljs-keyword">if</span> (d = decorators[i]) r = d(r) || r;<br> <span class="hljs-keyword">return</span> r;<br></code></pre></td></tr></table></figure><p>当装饰器合法时,将其赋值给 d,r = d(r) || r 相当于把 target 作为参数调用装饰器函数的结果赋值给 r, 如果 d(r) 没有返回值,返回的是原来的类 target,当有返回值的时候,返回的是 d(r) 的 return 内容。</p><p>HelloWorldClass 类</p><p>从打包出的结果来看,类 HelloWorld 被解析成了一个自执行函数:</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">var</span> HelloWorldClass = <span class="hljs-comment">/** <span class="hljs-doctag">@class </span>*/</span> (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HelloWorldClass</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">this</span>.name = <span class="hljs-string">'jerome'</span>;<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'I am constructor.'</span>);<br> }<br> HelloWorldClass.prototype.test = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'I am test method.'</span>);<br> };<br> HelloWorldClass = __decorate([<br> helloWorld<br> ], HelloWorldClass);<br> <span class="hljs-keyword">return</span> HelloWorldClass;<br>}());<br></code></pre></td></tr></table></figure><p>在自执行函数中,HelloWorldClass 接收 __decorate() 函数的执行结果,相当于改变了构造函数,所以可以利用装饰器修改类的功能。</p><h2 id="带返回值的类装饰器"><a href="#带返回值的类装饰器" class="headerlink" title="带返回值的类装饰器"></a>带返回值的类装饰器</h2><p>上面的例子是没有返回值的装饰器函数,它返回的是原来的类,那么带返回值的装饰器函数是怎么样的呢?是否是被装饰器修改之后的类呢?让我们来一起探究一下:</p><p>按照之前的步骤,这次我们的装饰器要带有返回值,下面是一个 override 构造函数的例子:</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">classDecorator</span><<span class="hljs-title">T</span> <span class="hljs-title">extends</span> </span>{<span class="hljs-keyword">new</span>(...args:any[]):{}}>(<span class="hljs-title">constructor</span>:<span class="hljs-title">T</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">constructor</span> </span>{<br> newProperty = <span class="hljs-string">"new property"</span>;<br> hello = <span class="hljs-string">"override"</span>;<br> }<br>}<br><br>@classDecorator<br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Greeter</span> </span>{<br> property = <span class="hljs-string">"property"</span>;<br> hello: string;<br> <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">m: string</span>)</span> {<br> <span class="hljs-built_in">this</span>.hello = m;<br> }<br>}<br><br><span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">new</span> Greeter(<span class="hljs-string">"world"</span>));<br></code></pre></td></tr></table></figure><p>运行的结果:</p><figure class="highlight shell"><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><code class="hljs shell"><span class="hljs-meta">$</span><span class="bash"> node decorator/decoratorReturn.js</span> <br>class_1 {<br>property: 'property',<br>hello: 'override',<br>newProperty: 'new property'<br>}<br></code></pre></td></tr></table></figure><p>由代码可知,Greeter 的构造函数是对 hello 的赋值为 world,然而在使用了 @classDecorator 这个构造函数之后,hello 的值变为了 override, 说明了类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。</p><h2 id="属性装饰器"><a href="#属性装饰器" class="headerlink" title="属性装饰器"></a>属性装饰器</h2><p>属性装饰器声明在一个属性声明之前,属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:</p><p>对于静态成员来说是类的构造函数,对于实例成员是类的原型对象<br>成员的名字。</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">type</span> PropertyDecorator =<br> <span class="hljs-function">(<span class="hljs-params">target: <span class="hljs-built_in">Object</span>, propertyKey: <span class="hljs-built_in">string</span> | symbol</span>) =></span> <span class="hljs-built_in">void</span>;<br></code></pre></td></tr></table></figure><p>那么,如何理解呢,让我们来看段代码:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logParameter</span>(<span class="hljs-params">target: <span class="hljs-built_in">Object</span>, propertyName: <span class="hljs-built_in">string</span></span>) </span>{<br> <span class="hljs-comment">// 属性值</span><br> <span class="hljs-keyword">let</span> _val = <span class="hljs-built_in">this</span>[propertyName];<br><br> <span class="hljs-comment">// 属性读取访问器</span><br> <span class="hljs-keyword">const</span> getter = <span class="hljs-function">() =></span> {<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Get: <span class="hljs-subst">${propertyName}</span> => <span class="hljs-subst">${_val}</span>`</span>);<br> <span class="hljs-keyword">return</span> _val;<br> };<br><br> <span class="hljs-comment">// 属性写入访问器</span><br> <span class="hljs-keyword">const</span> setter = <span class="hljs-function"><span class="hljs-params">newVal</span> =></span> {<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Set: <span class="hljs-subst">${propertyName}</span> => <span class="hljs-subst">${newVal}</span>`</span>);<br> _val = newVal;<br> };<br><br> <span class="hljs-comment">// 删除属性</span><br> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">delete</span> <span class="hljs-built_in">this</span>[propertyName]) {<br> <span class="hljs-comment">// 创建新属性及其读取访问器、写入访问器</span><br> <span class="hljs-built_in">Object</span>.defineProperty(target, propertyName, {<br> <span class="hljs-attr">get</span>: getter,<br> <span class="hljs-attr">set</span>: setter,<br> <span class="hljs-attr">enumerable</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">configurable</span>: <span class="hljs-literal">true</span><br> });<br> }<br>}<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Greeter</span> </span>{<br> <span class="hljs-meta">@logParameter</span><br> <span class="hljs-attr">greeting</span>: <span class="hljs-built_in">string</span>;<br>}<br><br><span class="hljs-keyword">const</span> greeter = <span class="hljs-keyword">new</span> Greeter();<br>greeter.greeting = <span class="hljs-string">'Jerome'</span>;<br>greeter.greeting<br></code></pre></td></tr></table></figure><p>运行这段代码:</p><figure class="highlight shell"><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><code class="hljs shell"><span class="hljs-meta">$</span><span class="bash"> node decorator/prototype.js</span> <br>Set: greeting => Jerome<br>Get: greeting => Jerome<br></code></pre></td></tr></table></figure><p>从结果可知,在实例中使用了 getter 和 setter 方法之后,都会打印出相应的 log,即装饰器的表达式在运行的时候被调用了。</p><p>让我们来看看编译成 js 之后的 Greeter 类</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> Greeter = <span class="hljs-comment">/** <span class="hljs-doctag">@class </span>*/</span> (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Greeter</span>(<span class="hljs-params"></span>) </span>{<br> }<br> __decorate([<br> logParameter,<br> __metadata(<span class="hljs-string">"design:type"</span>, <span class="hljs-built_in">String</span>)<br> ], Greeter.prototype, <span class="hljs-string">"greeting"</span>, <span class="hljs-keyword">void</span> <span class="hljs-number">0</span>);<br> <span class="hljs-keyword">return</span> Greeter;<br>}());<br></code></pre></td></tr></table></figure><p>由此可见,此次 __decorate 函数传入了 4 个参数,由在类装饰器分析的 _decorate 函数可知:</p><p> 从右往左运行装饰器,先运行__metadata(“design:type”, String) 表示被装饰的参数 greeting 是 String 类型,再运行 logParameter 装饰器,改写 greeting 参数的 getter 和 setter 方法。</p><h2 id="方法装饰器"><a href="#方法装饰器" class="headerlink" title="方法装饰器"></a>方法装饰器</h2><p>方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。 它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。</p><p>方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:</p><p>target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。</p><p>propertyKey:成员的名字。</p><p>descriptor:成员的属性描述符。</p><p>同样地,让我们来看段代码:</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logMethod</span>(<span class="hljs-params"></span></span><br><span class="hljs-params"><span class="hljs-function"> target: <span class="hljs-built_in">Object</span>,</span></span><br><span class="hljs-params"><span class="hljs-function"> propertyName: <span class="hljs-built_in">string</span>,</span></span><br><span class="hljs-params"><span class="hljs-function"> propertyDescriptor: PropertyDescriptor</span>): <span class="hljs-title">PropertyDescriptor</span> </span>{<br> <span class="hljs-keyword">const</span> method = propertyDescriptor.value;<br><br> propertyDescriptor.value = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">...args: <span class="hljs-built_in">any</span>[]</span>) </span>{<br> <span class="hljs-comment">// 将 greet 的参数列表转换为字符串</span><br> <span class="hljs-keyword">const</span> params = args.map(<span class="hljs-function"><span class="hljs-params">a</span> =></span> <span class="hljs-built_in">JSON</span>.stringify(a)).join();<br> <span class="hljs-comment">// 调用 greet() 并获取其返回值</span><br> <span class="hljs-keyword">const</span> result = method.apply(<span class="hljs-built_in">this</span>, args);<br> <span class="hljs-comment">// 转换结尾为字符串</span><br> <span class="hljs-keyword">const</span> r = <span class="hljs-built_in">JSON</span>.stringify(result);<br> <span class="hljs-comment">// 在终端显示函数调用细节</span><br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Call: <span class="hljs-subst">${propertyName}</span>(<span class="hljs-subst">${params}</span>) => <span class="hljs-subst">${r}</span>`</span>);<br> <span class="hljs-comment">// 返回调用函数的结果</span><br> <span class="hljs-keyword">return</span> result;<br> }<br> <span class="hljs-keyword">return</span> propertyDescriptor;<br>};<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Greeter</span> </span>{<br> <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> name: <span class="hljs-built_in">string</span></span>)</span> { }<br><br> <span class="hljs-meta">@logMethod</span><br> greet(message: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span> {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> says: <span class="hljs-subst">${message}</span>`</span>;<br> }<br>}<br><br><span class="hljs-keyword">const</span> greeter = <span class="hljs-keyword">new</span> Greeter(<span class="hljs-string">'Jerome'</span>);<br>greeter.greet(<span class="hljs-string">'Hello'</span>);<br></code></pre></td></tr></table></figure><p>运行这段代码:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta">$</span><span class="bash"> node decorator/method.js</span> <br>Call: greet("Hello") => "Jerome says: Hello"<br></code></pre></td></tr></table></figure><p>由打印结果可知,logMethod 这个方法装饰器在运行时当作了函数被调用。该函数有利于内审方法的调用,符合面向切面编程的思想。</p><p>让我们来看看编译成 js 之后的 Greeter 类:</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">var</span> Greeter = <span class="hljs-comment">/** <span class="hljs-doctag">@class </span>*/</span> (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Greeter</span>(<span class="hljs-params">name</span>) </span>{<br> <span class="hljs-built_in">this</span>.name = name;<br> }<br> Greeter.prototype.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">message</span>) </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.name + <span class="hljs-string">" says: "</span> + message;<br> };<br> __decorate([<br> logMethod,<br> __metadata(<span class="hljs-string">"design:type"</span>, <span class="hljs-built_in">Function</span>),<br> __metadata(<span class="hljs-string">"design:paramtypes"</span>, [<span class="hljs-built_in">String</span>]),<br> __metadata(<span class="hljs-string">"design:returntype"</span>, <span class="hljs-built_in">String</span>)<br> ], Greeter.prototype, <span class="hljs-string">"greet"</span>, <span class="hljs-literal">null</span>);<br> <span class="hljs-keyword">return</span> Greeter;<br>}());<br></code></pre></td></tr></table></figure><p>由此可见,此次 __decorate 函数传入了 4 个参数,由在类装饰器分析的 _decorate 函数可知:</p><p> 从右往左运行装饰器,先运行__metadata(“design:returntype”, String) 表示被装饰的方法 greet 的返回值的属性是 String 类型, __metadata(“design:paramtypes”, [String]) 表示方法参数的类型是 String,__metadata(“design:type”, Function)表示被装饰的是函数类型,再运行 logMethod 装饰器,打印出了函数调用的细节。</p><h2 id="参数装饰器"><a href="#参数装饰器" class="headerlink" title="参数装饰器"></a>参数装饰器</h2><p>参数装饰器声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。</p><p>参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:</p><p>target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。</p><p>propertyKey:成员的名字。</p><p>index:参数在函数参数列表中的索引。</p><p>同样地,让我们来看一段代码:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logParameter</span>(<span class="hljs-params">target: <span class="hljs-built_in">Object</span>, propertyName: <span class="hljs-built_in">string</span>, index: <span class="hljs-built_in">number</span></span>) </span>{<br> <span class="hljs-comment">// 为相应方法生成元数据键,以储存被装饰的参数的位置</span><br> <span class="hljs-keyword">const</span> metadataKey = <span class="hljs-string">`log_<span class="hljs-subst">${propertyName}</span>_parameters`</span>;<br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(target[metadataKey])) {<br> target[metadataKey].push(index);<br> }<br> <span class="hljs-keyword">else</span> {<br> target[metadataKey] = [index];<br> }<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'target => '</span>, target)<br>}<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Greeter</span> </span>{<br> greet(<span class="hljs-meta">@logParameter</span> message: <span class="hljs-built_in">string</span>, <span class="hljs-attr">middle</span>:<span class="hljs-built_in">string</span>, <span class="hljs-meta">@logParameter</span> name: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span> {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${name}</span> : <span class="hljs-subst">${message}</span>`</span>;<br> }<br>}<br><span class="hljs-keyword">const</span> greeter = <span class="hljs-keyword">new</span> Greeter();<br>greeter.greet(<span class="hljs-string">'hello'</span>,<span class="hljs-string">'I am middle'</span>, <span class="hljs-string">'jerome'</span>);<br></code></pre></td></tr></table></figure><p>运行打包之后的 js:</p><figure class="highlight shell"><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><code class="hljs shell"><span class="hljs-meta">$</span><span class="bash"> node decorator/parameter.js</span> <br>target => Greeter { greet: [Function], log_greet_parameters: [ 2 ] }<br>target => Greeter { greet: [Function], log_greet_parameters: [ 2, 0 ] }<br></code></pre></td></tr></table></figure><p>可以看到,打印了两个 log,message 和 name 的位置分别是 0 和 2。</p><p>让我们来看看编译成 js 之后的 Greeter 类:</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> Greeter = <span class="hljs-comment">/** <span class="hljs-doctag">@class </span>*/</span> (<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Greeter</span>(<span class="hljs-params"></span>) </span>{<br> }<br> Greeter.prototype.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">message, middle, name</span>) </span>{<br> <span class="hljs-keyword">return</span> name + <span class="hljs-string">" : "</span> + message;<br> };<br> __decorate([<br> __param(<span class="hljs-number">0</span>, logParameter), __param(<span class="hljs-number">2</span>, logParameter),<br> __metadata(<span class="hljs-string">"design:type"</span>, <span class="hljs-built_in">Function</span>),<br> __metadata(<span class="hljs-string">"design:paramtypes"</span>, [<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>]),<br> __metadata(<span class="hljs-string">"design:returntype"</span>, <span class="hljs-built_in">String</span>)<br> ], Greeter.prototype, <span class="hljs-string">"greet"</span>, <span class="hljs-literal">null</span>);<br> <span class="hljs-keyword">return</span> Greeter;<br>}());<br></code></pre></td></tr></table></figure><p> 由此可见,此次 _decorate 函数也传入 4 个参数,注意第 4 个参数为 null,这在 _decorate 函数中会使 r 的值有所不同。由前面可知,装饰器从右往左运行,依次确定被装饰对象的返回值类型,参数类型以及自身的类型为 Function,这里有个不一样的 __param() 装饰器,让我们也来了解一下:</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">var</span> __param = (<span class="hljs-built_in">this</span> && <span class="hljs-built_in">this</span>.__param) || <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">paramIndex, decorator</span>) </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">target, key</span>) </span>{<br> decorator(target, key, paramIndex);<br> }<br>};<br></code></pre></td></tr></table></figure><p>可见,他调用了 logParameter 函数,并传入了一个 paramIndex 表示参数的位置。由此,参数装饰器也一目了然了。</p><p>访问器装饰器<br>访问器装饰器应用于访问器的属性描述符,可用于观测、修改、替换访问器的定义。</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">enumerable</span>(<span class="hljs-params">value: <span class="hljs-built_in">boolean</span></span>) </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span></span><br><span class="hljs-params"><span class="hljs-function"> target: <span class="hljs-built_in">any</span>, propertyKey: <span class="hljs-built_in">string</span>, descriptor: PropertyDescriptor</span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'decorator - sets the enumeration part of the accessor'</span>);<br> descriptor.enumerable = value;<br> };<br>}<br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{<br> <span class="hljs-keyword">private</span> _age: <span class="hljs-built_in">number</span> = <span class="hljs-number">18</span>;<br> <span class="hljs-keyword">private</span> _name: <span class="hljs-built_in">string</span> = <span class="hljs-string">'jerome'</span>;<br><br> <span class="hljs-meta">@enumerable</span>(<span class="hljs-literal">false</span>)<br> <span class="hljs-keyword">get</span> <span class="hljs-title">age</span>() { <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._age; }<br><br> <span class="hljs-keyword">set</span> <span class="hljs-title">age</span>(<span class="hljs-params">age: <span class="hljs-built_in">any</span></span>) { <span class="hljs-built_in">this</span>._age = age; }<br><br> <span class="hljs-meta">@enumerable</span>(<span class="hljs-literal">true</span>)<br> <span class="hljs-keyword">get</span> <span class="hljs-title">name</span>() {<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._name;<br> }<br><br> <span class="hljs-keyword">set</span> <span class="hljs-title">name</span>(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) {<br> <span class="hljs-built_in">this</span>._name = name;<br> }<br><br>}<br><br><span class="hljs-keyword">const</span> person = <span class="hljs-keyword">new</span> Person();<br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> prop <span class="hljs-keyword">in</span> person) {<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`enumerable property = <span class="hljs-subst">${prop}</span>`</span>);<br>}<br></code></pre></td></tr></table></figure><p>运行之后:</p><figure class="highlight shell"><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><code class="hljs shell"><span class="hljs-meta">$</span><span class="bash"> node decorator/defineObject.js</span> <br>decorator - sets the enumeration part of the accessor<br>decorator - sets the enumeration part of the accessor<br>enumerable property = _age<br>enumerable property = _name<br>enumerable property = name<br></code></pre></td></tr></table></figure><p>上面的例子中,我们定义了两个访问器 name 和 age ,并通过装饰器设置是否将其列入可枚举属性,我们把 age 设置为false, 所以在清单中不会出现 age。</p><h2 id="元数据"><a href="#元数据" class="headerlink" title="元数据"></a>元数据</h2><p>Reflect Metadata是 ES7 的一个提案,它主要用来在声明的时候添加和读取元数据。</p><p>可以通过 npm 安装这个库:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">npm i reflect-metadata --save<br></code></pre></td></tr></table></figure><p>TypeScript 支持为带有装饰器的声明生成元数据。 你需要在命令行或 tsconfig.json 里启用 emitDecoratorMetadata 编译器选项。</p><p>命令行:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata<br></code></pre></td></tr></table></figure><p>tsconfig.json:</p><figure class="highlight json"><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><code class="hljs json">{<br> <span class="hljs-attr">"compilerOptions"</span>: {<br> <span class="hljs-attr">"target"</span>: <span class="hljs-string">"ES5"</span>,<br> <span class="hljs-attr">"experimentalDecorators"</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">"emitDecoratorMetadata"</span>: <span class="hljs-literal">true</span><br> }<br>}<br></code></pre></td></tr></table></figure><p>当启用后,只要 reflect-metadata 库被引入了,设计阶段添加的类型信息可以在运行时使用。元信息反射 API 能够用来以标准方式组织元信息。「反射」的意思是代码可以侦测同一系统中的其他代码(或其自身)。反射在组合/依赖注入、运行时类型断言、测试等使用场景下很有用。</p><p>在这里,我们能够使用之前学过的各类装饰器来修饰你的代码。</p><p>例如:</p><figure class="highlight ts"><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><code class="hljs ts"><span class="hljs-keyword">import</span> <span class="hljs-string">"reflect-metadata"</span>;<br><br><span class="hljs-comment">// 【参数装饰器】用来存储被装饰参数的索引</span><br><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logParameter</span>(<span class="hljs-params">target: <span class="hljs-built_in">Object</span>, propertyName: <span class="hljs-built_in">string</span>, index: <span class="hljs-built_in">number</span></span>) </span>{<br> <span class="hljs-keyword">const</span> indices = <span class="hljs-built_in">Reflect</span>.getMetadata(<span class="hljs-string">`log_<span class="hljs-subst">${propertyName}</span>_parameters`</span>, target, propertyName) || [];<br> indices.push(index);<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'indices => '</span>, indices);<br> <span class="hljs-built_in">Reflect</span>.defineMetadata(<span class="hljs-string">`log_<span class="hljs-subst">${propertyName}</span>_parameters`</span>, indices, target, propertyName);<br>}<br><br><span class="hljs-comment">// 【属性装饰器】用来获取属性的运行时类型</span><br><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logProperty</span>(<span class="hljs-params">target: <span class="hljs-built_in">Object</span>, propertyName: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">void</span> </span>{<br> <span class="hljs-comment">// 获取对象属性的设计类型</span><br> <span class="hljs-keyword">var</span> t = <span class="hljs-built_in">Reflect</span>.getMetadata(<span class="hljs-string">"design:type"</span>, target, propertyName);<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${propertyName}</span> type: <span class="hljs-subst">${t.name}</span>`</span>);<br>}<br><br><br><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Greeter</span> </span>{<br> <span class="hljs-meta">@logProperty</span><br> <span class="hljs-keyword">private</span> name: <span class="hljs-built_in">string</span>;<br> <br> <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>)</span> {<br> <span class="hljs-built_in">this</span>.name = name;<br> }<br><br> greet(<span class="hljs-meta">@logParameter</span> message: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span> {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> says: <span class="hljs-subst">${message}</span>`</span>;<br> }<br>}<br><br><span class="hljs-keyword">const</span> greeter = <span class="hljs-keyword">new</span> Greeter(<span class="hljs-string">'jerome'</span>);<br>greeter.greet(<span class="hljs-string">'hello'</span>);<br></code></pre></td></tr></table></figure><p>design:type 表示被装饰的对象是什么类型<br>design:paramtypes 表示被装饰对象的参数类型<br>design:returntype 表示被装饰对象的返回值属性</p><p>运行这段代码:</p><figure class="highlight shell"><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><code class="hljs shell"><span class="hljs-meta">$</span><span class="bash"> node decorator/reflect-metadata.js</span> <br>name type: String<br>indices => [ 0 ]<br></code></pre></td></tr></table></figure><p>打印出了我们想知道的 name 的类型以及 message 的参数索引。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>typescript 的装饰器本质上提供了被装饰对象 Property Descriptor 的操作,都是在运行的时候被当作函数调用。看了这篇文章,是否觉得 typescript 这个装饰器的特性有点像 java spring 中注解的写法,我们可以利用我们写的装饰器来实现反射、依赖注入,类型断言等,实现在运行中程序对自身进行检查,vscode 就是典型的利用 typescript 的装饰器实现了依赖注入,有兴趣的请关注后续的文章。</p><h2 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h2><p>装饰器是扩展 JavaScript 类的建议,TC39 五年来一直在研究装饰方案,有兴趣的可以关注下 TC39 的这个<a href="https://github.com/tc39/proposal-decorators">提案</a>,babel 也实现了该提案,<a href="https://babeljs.io/docs/en/babel-plugin-proposal-decorators">具体可查</a>。</p>]]></content>
<categories>
<category>TypeScript</category>
</categories>
</entry>
<entry>
<title>原型模式</title>
<link href="/2021/06/27/prototype/"/>
<url>/2021/06/27/prototype/</url>
<content type="html"><![CDATA[<h3 id="原型对象"><a href="#原型对象" class="headerlink" title="原型对象"></a>原型对象</h3><p>在我们创建的一个函数时,都有一个 prototype(原型)属性,这个属性是一个<strong>指针</strong>,指向<strong>原型对象</strong>,并且所有的原型对象都会自动获得一个 constructor ,下面我们先定义一个函数,并把所有的属性和方法都挂载在函数的 prototype 属性下,并新建两个对象实例:</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Person</span>(<span class="hljs-params"></span>) </span>{}<br><br>Person.prototype.name = <span class="hljs-string">'jerome'</span><br>Person.prototype.age = <span class="hljs-number">18</span><br>Person.prototype.job = <span class="hljs-string">'Front End Engineer'</span><br>Person.prototype.sayName = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> alter(<span class="hljs-built_in">this</span>.name)<br>}<br><br><span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> Person()<br><span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> Person()<br></code></pre></td></tr></table></figure><p>那么,代码中实际上 Person 构造函数、Person 的原型属性以及 Person 现有的两个实例间的关系是怎么样的呢,让我们看下图:</p><p><img src="https://img-blog.csdnimg.cn/20210503234607875.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2plcm9tZV83Nzc=,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p><p>从图中我们可以看到,Person 的 prototype 属性指向了 Person 的原型对象,而原型对象中的 constructor 又指回了 Peron。并且在 Person 的原型下,还有我们定义的属性和方法。再看创建的两个实例,每个实例都有一个内部属性 [[prototype]](__proto__) 指向了原型对象。</p><h3 id="原型对象的问题"><a href="#原型对象的问题" class="headerlink" title="原型对象的问题"></a>原型对象的问题</h3><p>由于原型模式省略了为构造函数初始化参数这一环节,默认情况下所有的实例都会取得相同的属性值,在一定程度上造成了不便。但是,还有一个更大的问题,是由其共享的本性所导致的,在属性有引用类型的时候,这个问题就比较突出了,让我们看下下面的代码:</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Person</span>(<span class="hljs-params"></span>) </span>{}<br><br>Person.prototype = {<br> <span class="hljs-attr">constrcutor</span>: Person,<br> <span class="hljs-attr">name</span>: <span class="hljs-string">'jerome'</span>,<br> <span class="hljs-attr">age</span>: <span class="hljs-number">18</span>,<br> <span class="hljs-attr">job</span>: <span class="hljs-string">'Front End Engineer'</span>,<br> <span class="hljs-attr">friends</span>: [<span class="hljs-string">'shy'</span>, <span class="hljs-string">'faker'</span>],<br> <span class="hljs-attr">sayName</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> alter(<span class="hljs-built_in">this</span>.name)<br> }<br>}<br><br><span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> Person()<br><span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> Person()<br><br>person1.friends.push(<span class="hljs-string">'rookie'</span>)<br><br><span class="hljs-built_in">console</span>.log(person1.friends) <span class="hljs-comment">// "shy,faker,rookie"</span><br><span class="hljs-built_in">console</span>.log(person2.friends) <span class="hljs-comment">// "shy,faker,rookie"</span><br><span class="hljs-built_in">console</span>.log(person1.friends === person2.friends) <span class="hljs-comment">// true</span><br></code></pre></td></tr></table></figure><p>当原型对象中有引用类型的值时,修改引用类型的值,由于他是一个引用(指针),会修改所有实例的这个属性的值,就如上代码,在 person1.friends 增加一个值之后,person1 和 person2 的 friends 都被修改了。</p><h3 id="组合使用构造函数模式和原型模式"><a href="#组合使用构造函数模式和原型模式" class="headerlink" title="组合使用构造函数模式和原型模式"></a>组合使用构造函数模式和原型模式</h3><p>由于在使用原型模式时有引用类型会造成的问题,那么可以结合构造函数和原型模式来使用。这个方法我总结了一句话:属性使用构造函数模式(不共享),方法使用原型模式(共享)。让我们来看下下面的例子:</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Person</span>(<span class="hljs-params">name, age, job</span>) </span>{<br> <span class="hljs-built_in">this</span>.name = name<br> <span class="hljs-built_in">this</span>.age = age<br> <span class="hljs-built_in">this</span>.job = job<br> <span class="hljs-built_in">this</span>.friends = [<span class="hljs-string">'shy'</span>, <span class="hljs-string">'faker'</span>]<br>}<br><br>Person.prototype = {<br> <span class="hljs-attr">constrcutor</span>: Person,<br> <span class="hljs-attr">sayName</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> alter(<span class="hljs-built_in">this</span>.name)<br> }<br>}<br><br><span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'jerome'</span>, <span class="hljs-number">18</span>, <span class="hljs-string">'Front End Engineer'</span>)<br><span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'the shy'</span>, <span class="hljs-number">18</span>, <span class="hljs-string">'gamer'</span>)<br><br>person1.friends.push(<span class="hljs-string">'rookie'</span>)<br><br><span class="hljs-built_in">console</span>.log(person1.friends) <span class="hljs-comment">// "shy,faker,rookie"</span><br><span class="hljs-built_in">console</span>.log(person2.friends) <span class="hljs-comment">// "shy,faker"</span><br><span class="hljs-built_in">console</span>.log(person1.friends === person2.friends) <span class="hljs-comment">// false</span><br></code></pre></td></tr></table></figure><p>可以看到,两个实例的 friends 已经不共享了。</p><h2 id="原型链"><a href="#原型链" class="headerlink" title="原型链"></a>原型链</h2><p>原型链的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SuperType</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">this</span>.property = <span class="hljs-literal">true</span><br>}<br><br>SuperType.prototype.getSuperValue = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.property<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SubType</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">this</span>.subproperty = <span class="hljs-literal">false</span><br>}<br><br>SubType.prototype = <span class="hljs-keyword">new</span> SuperType()<br><br>SubType.property.getSubValue = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.subproperty<br>}<br><br><span class="hljs-keyword">const</span> instance = <span class="hljs-keyword">new</span> SubType()<br><span class="hljs-built_in">console</span>.log(instance.getSuperValue()) <span class="hljs-comment">// true</span><br></code></pre></td></tr></table></figure><p>我们可以看到,instance 是 SubType 对象,却可以使用 SuperType 的方法,这就是继承了 SuperType ,而继承的实现就是通过创建父函数的实例,并将该实例赋值给子函数的 prototype 实现的。实现的本质是重写原型对象,代之以一个新类型的实例。让我们来看下他们之间的关系:</p><p><img src="https://img-blog.csdnimg.cn/20210503234623313.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2plcm9tZV83Nzc=,size_16,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述"></p><p>在上面代码中,我们没有使用 SubType 默认的原型对象,而是使用了 SuperType 的实例当作他的原型。这个原型含有 SuperType 所有的属性和方法。从之前原型对象的知识点可知,实例的内部还有一个指针([[prototype]]),指向原型,这里相当于是 SubType 的原型对象指向了 SuperType 的原型,这样就实现了继承。</p><h3 id="原型链的问题"><a href="#原型链的问题" class="headerlink" title="原型链的问题"></a>原型链的问题</h3><p>同样的,原型链也含有引用类型的问题,那么,接下来我将介绍一下如何解决这个问题。</p><h4 id="借用构造函数"><a href="#借用构造函数" class="headerlink" title="借用构造函数"></a>借用构造函数</h4><p>这个方法的基本思想就是在子类型构造函数的内部通过 call 或者 apply 调用超类型构造函数。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SuperType</span>(<span class="hljs-params">name</span>) </span>{<br> <span class="hljs-built_in">this</span>.name = name<br> <span class="hljs-built_in">this</span>.friends = [<span class="hljs-string">'the shy'</span>, <span class="hljs-string">'faker'</span>]<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SubType</span>(<span class="hljs-params"></span>) </span>{<br> SuperType.call(<span class="hljs-built_in">this</span>, <span class="hljs-string">'jerome'</span>)<br> <span class="hljs-built_in">this</span>.age = <span class="hljs-number">18</span><br>}<br><br><span class="hljs-keyword">const</span> instance1 = <span class="hljs-keyword">new</span> SubType()<br>instance1.friends.push(<span class="hljs-string">'rookie'</span>)<br><span class="hljs-built_in">console</span>.log(instance1.friends) <span class="hljs-comment">// [ 'the shy', 'faker', 'rookie' ]</span><br><span class="hljs-built_in">console</span>.log(instance1.name) <span class="hljs-comment">// jerome</span><br><br><span class="hljs-keyword">const</span> instance2 = <span class="hljs-keyword">new</span> SubType()<br><span class="hljs-built_in">console</span>.log(instance2.friends) <span class="hljs-comment">// [ 'the shy', 'faker' ]</span><br></code></pre></td></tr></table></figure><p>但这个方法存在一个问题,方法都在构造函数中定义,函数复用也无从说起,这个方法很少单独使用。</p><h4 id="组合继承"><a href="#组合继承" class="headerlink" title="组合继承"></a>组合继承</h4><p>组合继承,就是将原型链和借用构造函数的技术组合到一起。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SuperType</span>(<span class="hljs-params">name</span>) </span>{<br> <span class="hljs-built_in">this</span>.name = name<br> <span class="hljs-built_in">this</span>.friends = [<span class="hljs-string">'the shy'</span>, <span class="hljs-string">'faker'</span>]<br>}<br><br>SuperType.prototype.sayName = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SubType</span>(<span class="hljs-params">name, age</span>) </span>{<br> SuperType.call(<span class="hljs-built_in">this</span>, name)<br> <span class="hljs-built_in">this</span>.age = age<br>}<br><br><span class="hljs-comment">// 继承方法</span><br>SubType.prototype = <span class="hljs-keyword">new</span> SuperType()<br>SubType.prototype.constructor = SubType<br>SubType.prototype.sayAge = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.age)<br>}<br><br><span class="hljs-keyword">const</span> instance1 = <span class="hljs-keyword">new</span> SubType(<span class="hljs-string">'jerome'</span>, <span class="hljs-number">18</span>)<br>instance1.friends.push(<span class="hljs-string">'rookie'</span>)<br><span class="hljs-built_in">console</span>.log(instance1.friends) <span class="hljs-comment">// [ 'the shy', 'faker', 'rookie' ]</span><br>instance1.sayName() <span class="hljs-comment">// jerome</span><br>instance1.sayAge() <span class="hljs-comment">// 18</span><br><br><span class="hljs-keyword">const</span> instance2 = <span class="hljs-keyword">new</span> SubType(<span class="hljs-string">'the shy'</span>, <span class="hljs-number">19</span>)<br><span class="hljs-built_in">console</span>.log(instance2.friends) <span class="hljs-comment">// [ 'the shy', 'faker' ]</span><br>instance2.sayName() <span class="hljs-comment">// the shy</span><br>instance2.sayAge() <span class="hljs-comment">// 19</span><br></code></pre></td></tr></table></figure><p>在这个例子中,可以看到 SubType 继承了 SuperType 的属性和方法,又有自己的属性和方法,并且 friends 属性是相互独立的,避免了原型链(引用类型问题)和借用构造函数(方法无法复用)的缺陷,但组合继承也有缺点,我们后续会说到。</p><h4 id="原型式继承"><a href="#原型式继承" class="headerlink" title="原型式继承"></a>原型式继承</h4><p>原型式继承,就是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。可以利用 Object.create() 来实现,这个方法接收两个参数:一个用作新对象原型的对象和一个为新对象定义额外属性的对象(可选)</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-keyword">const</span> person = {<br> <span class="hljs-attr">name</span>: <span class="hljs-string">'jerome'</span>,<br> <span class="hljs-attr">friends</span>: [<span class="hljs-string">'the shy'</span>, <span class="hljs-string">'faker'</span>]<br>}<br><br><span class="hljs-keyword">const</span> anotherPerson = <span class="hljs-built_in">Object</span>.create(person, {<br> <span class="hljs-attr">name</span>: {<br> <span class="hljs-attr">value</span>: <span class="hljs-string">'rookie'</span><br> }<br>})<br><br>anotherPerson.friends.push(<span class="hljs-string">'zoom'</span>) <br><span class="hljs-built_in">console</span>.log(anotherPerson.name) <span class="hljs-comment">// rookie</span><br><span class="hljs-built_in">console</span>.log(person.friends) <span class="hljs-comment">// [ 'the shy', 'faker', 'zoom' ]</span><br><span class="hljs-built_in">console</span>.log(anotherPerson.friends) <span class="hljs-comment">// [ 'the shy', 'faker', 'zoom' ]</span><br></code></pre></td></tr></table></figure><p>可以看到,原型式继承还有引用类型的问题</p><h4 id="寄生式继承"><a href="#寄生式继承" class="headerlink" title="寄生式继承"></a>寄生式继承</h4><p>寄生式继承,就是创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。</p><figure class="highlight js"><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><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createAnother</span>(<span class="hljs-params">original</span>) </span>{<br> <span class="hljs-keyword">const</span> clone = <span class="hljs-built_in">Object</span>.create(original)<br> clone.sayHi = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hi'</span>)<br> }<br> <span class="hljs-keyword">return</span> clone<br>}<br></code></pre></td></tr></table></figure><p>在例子中,该函数为源对象增加了一个 sayHi 的方法,和原型式继承类似。</p><h4 id="寄生组合式继承"><a href="#寄生组合式继承" class="headerlink" title="寄生组合式继承"></a>寄生组合式继承</h4><p>从前面看,组合式继承似乎就是最好最常用的继承方式,不过,它也有自己的不足,组合式继承无论在什么情况下,都会调用两次超类型的构造函数,第一次是在 new SuperType() 的时候,第二次是在调用 SuperType.call 的时候。</p><p>寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 相当于 subType 的原型对象不直接 new 出来,而是从 Object 继承下来</span><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">inheritPrototype</span>(<span class="hljs-params">subType, superType</span>) </span>{<br> <span class="hljs-keyword">const</span> prototype = <span class="hljs-built_in">Object</span>.create(superType.prototype)<br> prototype.constructor = subType<span class="hljs-comment">// constructor 指回构造函数</span><br> subType.prototype = prototype<span class="hljs-comment">// prototype 指向原型对象</span><br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SuperType</span>(<span class="hljs-params">name</span>) </span>{<br> <span class="hljs-built_in">this</span>.name = name<br> <span class="hljs-built_in">this</span>.friends = [<span class="hljs-string">'the shy'</span>, <span class="hljs-string">'faker'</span>]<br>}<br><br>SuperType.prototype.sayName = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SubType</span>(<span class="hljs-params">name, age</span>) </span>{<br> SuperType.call(<span class="hljs-built_in">this</span>, name)<br> <span class="hljs-built_in">this</span>.age = age<br>}<br><br>inheritPrototype(SubType, SuperType)<br><br>SubType.prototype.sayAge = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<br> <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.age)<br>}<br><br><span class="hljs-keyword">const</span> instance1 = <span class="hljs-keyword">new</span> SubType(<span class="hljs-string">'jerome'</span>, <span class="hljs-number">18</span>)<br>instance1.friends.push(<span class="hljs-string">'zoom'</span>)<br><span class="hljs-built_in">console</span>.log(instance1.friends) <span class="hljs-comment">// [ 'the shy', 'faker', 'chen' ]</span><br>instance1.sayName() <span class="hljs-comment">// jerome</span><br>instance1.sayAge() <span class="hljs-comment">// 18</span><br><br><br><span class="hljs-keyword">const</span> instance2 = <span class="hljs-keyword">new</span> SubType(<span class="hljs-string">'rookie'</span>, <span class="hljs-number">19</span>)<br><span class="hljs-built_in">console</span>.log(instance2.friends) <span class="hljs-comment">// [ 'the shy', 'faker' ]</span><br>instance2.sayName() <span class="hljs-comment">// rookie</span><br>instance2.sayAge() <span class="hljs-comment">//19</span><br></code></pre></td></tr></table></figure><p>这个例子的高效率提现在它只调用了一次超类型的构造函数,避免在 SubType.prototype 上创建不必要的、多余的属性。与此同时,原型链还能保持不变,寄生组合继承是引用类型最理想的继承范式。</p>]]></content>
<categories>
<category>JavaScript</category>
</categories>
</entry>
</search>