-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.xml
6491 lines (6342 loc) · 806 KB
/
index.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
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Road to Final</title>
<link>https://hearecho.github.io/</link>
<description>Recent content on Road to Final</description>
<generator>Hugo -- gohugo.io</generator>
<language>zh-cn</language>
<lastBuildDate>Wed, 13 Apr 2022 12:09:28 +0800</lastBuildDate><atom:link href="https://hearecho.github.io/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>刷题笔记 双指针</title>
<link>https://hearecho.github.io/post/%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0-%E5%8F%8C%E6%8C%87%E9%92%88/</link>
<pubDate>Wed, 13 Apr 2022 12:09:28 +0800</pubDate>
<guid>https://hearecho.github.io/post/%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0-%E5%8F%8C%E6%8C%87%E9%92%88/</guid>
<description>
<p> 双指针经常在数组和链表中使用。二分查找、滑动窗口、快慢指针都是双指针的变形用法。</p>
<h3 id="二分查找">二分查找</h3>
<p>二分查找,主要是在有序数组中进行查找符合目标值,一般中等难度的问题都不会简单的让查找某个确定的值,而是进行变相的询问,例如询问左边界问题,左边界问题也是用的最多的一种方式。</p>
<h4 id="34-在排序数组中查找元素的第一个和最后一个位置httpsleetcode-cncomproblemsfind-first-and-last-position-of-element-in-sorted-array"><a href="https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/">34. 在排序数组中查找元素的第一个和最后一个位置</a></h4>
<p>这道题可以使用调用两次最左位置,或者是一次最左,一次最右。两次调用最左位置,就是查找$target$和$target+1$的最左位置,这样就可以获得目标值的最左位置和最有位置。当然最右位置等于$target+1$最左位置-1。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">searchRange</span><span class="p">(</span><span class="nx">nums</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">target</span> <span class="kt">int</span><span class="p">)</span> <span class="p">[]</span><span class="kt">int</span> <span class="p">{</span>
<span class="c1">// 时间复杂度的要求所以肯定是使用二分查找方法
</span><span class="c1"></span> <span class="c1">// 我们需要查找的是上边界以及下边界
</span><span class="c1"></span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">nums</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">}</span>
<span class="p">}</span>
<span class="nx">l</span> <span class="o">:=</span> <span class="nf">binarySearch</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="nx">target</span><span class="p">)</span>
<span class="nx">h</span> <span class="o">:=</span> <span class="nf">binarySearch</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="nx">target</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">l</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">nums</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">nums</span><span class="p">[</span><span class="nx">l</span><span class="p">]</span> <span class="o">==</span> <span class="nx">target</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="nx">l</span><span class="p">,</span> <span class="nx">h</span><span class="o">-</span><span class="mi">1</span><span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">}</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">binarySearch</span><span class="p">(</span><span class="nx">nums</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">target</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
<span class="nx">l</span><span class="p">,</span><span class="nx">h</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="nx">nums</span><span class="p">)</span>
<span class="k">for</span> <span class="nx">l</span><span class="p">&lt;</span><span class="nx">h</span> <span class="p">{</span>
<span class="c1">// 由于是查找边界,所以不能是
</span><span class="c1"></span> <span class="nx">mid</span> <span class="o">:=</span> <span class="nx">l</span> <span class="o">+</span> <span class="p">(</span><span class="nx">h</span><span class="o">-</span><span class="nx">l</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span>
<span class="k">if</span> <span class="nx">nums</span><span class="p">[</span><span class="nx">mid</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="nx">target</span> <span class="p">{</span>
<span class="nx">h</span> <span class="p">=</span> <span class="nx">mid</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">l</span> <span class="p">=</span> <span class="nx">mid</span> <span class="o">+</span> <span class="mi">1</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">l</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="354-俄罗斯套娃信封问题httpsleetcode-cncomproblemsrussian-doll-envelopes"><a href="https://leetcode-cn.com/problems/russian-doll-envelopes/">354. 俄罗斯套娃信封问题</a></h4>
<p>这道题可以转换为最长子序列问题,最长子学列问题通常使用动态规划数组,在这里我们使用二分查找的方式来解决最长子序列问题。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">maxEnvelopes</span><span class="p">(</span><span class="nx">envelopes</span> <span class="p">[][]</span><span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
<span class="c1">// 排序之后转换为寻找最长子序列问题
</span><span class="c1"></span> <span class="nx">sort</span><span class="p">.</span><span class="nf">Slice</span><span class="p">(</span><span class="nx">envelopes</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">j</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
<span class="k">if</span> <span class="nx">envelopes</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="nx">envelopes</span><span class="p">[</span><span class="nx">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">envelopes</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="p">&gt;</span> <span class="nx">envelopes</span><span class="p">[</span><span class="nx">j</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">envelopes</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="p">&lt;</span> <span class="nx">envelopes</span><span class="p">[</span><span class="nx">j</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
<span class="p">})</span>
<span class="nx">n</span> <span class="o">:=</span> <span class="nb">len</span><span class="p">(</span><span class="nx">envelopes</span><span class="p">)</span>
<span class="nx">heights</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span>
<span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p">&lt;</span> <span class="nx">n</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
<span class="nx">heights</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="p">=</span> <span class="nx">envelopes</span><span class="p">[</span><span class="nx">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
<span class="p">}</span>
<span class="c1">//求heights里面的最长上升子学列
</span><span class="c1"></span> <span class="kd">var</span> <span class="nx">lengthOfLTS</span> <span class="kd">func</span><span class="p">()</span> <span class="kt">int</span>
<span class="c1">//
</span><span class="c1"></span> <span class="nx">lengthOfLTS</span> <span class="p">=</span> <span class="kd">func</span><span class="p">()</span> <span class="kt">int</span> <span class="p">{</span>
<span class="c1">// 洗牌算法
</span><span class="c1"></span> <span class="nx">piles</span> <span class="o">:=</span> <span class="mi">0</span>
<span class="nx">top</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span>
<span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p">&lt;</span> <span class="nx">n</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
<span class="c1">// 当前要处理的扑克牌
</span><span class="c1"></span> <span class="nx">poker</span> <span class="o">:=</span> <span class="nx">heights</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span>
<span class="c1">// piles表示此时的牌堆
</span><span class="c1"></span> <span class="c1">// 而left就是当前要处理的牌要插入的位置,如果位置大于piles
</span><span class="c1"></span> <span class="c1">// 说明是放在牌堆大小扩充了
</span><span class="c1"></span> <span class="nx">left</span><span class="p">,</span> <span class="nx">right</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">piles</span>
<span class="k">for</span> <span class="nx">left</span> <span class="p">&lt;</span> <span class="nx">right</span> <span class="p">{</span>
<span class="nx">mid</span> <span class="o">:=</span> <span class="nx">left</span> <span class="o">+</span> <span class="p">(</span><span class="nx">right</span><span class="o">-</span><span class="nx">left</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span>
<span class="k">if</span> <span class="nx">top</span><span class="p">[</span><span class="nx">mid</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="nx">poker</span> <span class="p">{</span>
<span class="nx">right</span> <span class="p">=</span> <span class="nx">mid</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">left</span> <span class="p">=</span> <span class="nx">mid</span> <span class="o">+</span> <span class="mi">1</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="nx">left</span> <span class="o">==</span> <span class="nx">piles</span> <span class="p">{</span>
<span class="nx">piles</span><span class="o">++</span>
<span class="p">}</span>
<span class="nx">top</span><span class="p">[</span><span class="nx">left</span><span class="p">]</span> <span class="p">=</span> <span class="nx">poker</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">piles</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nf">lengthOfLTS</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="875-爱吃香蕉的珂珂httpsleetcode-cncomproblemskoko-eating-bananas"><a href="https://leetcode-cn.com/problems/koko-eating-bananas/">875. 爱吃香蕉的珂珂</a></h4>
<p>这道题是二分搜索的应用,将问题抽象为二分搜索。即我们要寻找一个$x$,使得$f(x)$满足目标$target$。</p>
<p>例如该题中:$x$为吃香蕉的速度,$f(x)$为判断以$x$速度吃香蕉是否可以在警卫回来之前吃完($target$)。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">minEatingSpeed</span><span class="p">(</span><span class="nx">piles</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">h</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
<span class="c1">// 首先确定速度k的范围
</span><span class="c1"></span> <span class="c1">// k最小值为1, 最大值当没办法进行确定的时候,就可以选择值的最大可能性
</span><span class="c1"></span> <span class="c1">// 二分法寻找左边界问题
</span><span class="c1"></span> <span class="nx">l</span><span class="p">,</span> <span class="nx">r</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">100000001</span>
<span class="nx">sort2</span><span class="p">.</span><span class="nf">Ints</span><span class="p">(</span><span class="nx">piles</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">f</span> <span class="kd">func</span><span class="p">(</span><span class="nx">x</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span>
<span class="c1">// f(x)
</span><span class="c1"></span> <span class="nx">f</span> <span class="p">=</span> <span class="kd">func</span><span class="p">(</span><span class="nx">x</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
<span class="nx">use</span> <span class="o">:=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">piles</span><span class="p">);</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
<span class="nx">use</span> <span class="o">+=</span> <span class="nx">piles</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">/</span> <span class="nx">x</span>
<span class="k">if</span> <span class="nx">piles</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="o">%</span><span class="nx">x</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">{</span>
<span class="nx">use</span><span class="o">++</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">use</span> <span class="o">&lt;=</span> <span class="nx">h</span>
<span class="p">}</span>
<span class="k">for</span> <span class="nx">l</span> <span class="p">&lt;</span> <span class="nx">r</span> <span class="p">{</span>
<span class="nx">mid</span> <span class="o">:=</span> <span class="nx">l</span> <span class="o">+</span> <span class="p">(</span><span class="nx">r</span><span class="o">-</span><span class="nx">l</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span>
<span class="k">if</span> <span class="nf">f</span><span class="p">(</span><span class="nx">mid</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// 可以吃完
</span><span class="c1"></span> <span class="nx">r</span> <span class="p">=</span> <span class="nx">mid</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="c1">// 不可以吃完
</span><span class="c1"></span> <span class="nx">l</span> <span class="p">=</span> <span class="nx">mid</span> <span class="o">+</span> <span class="mi">1</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">l</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="滑动窗口">滑动窗口</h3>
<p>滑动窗口算法是双指针的一种变种,或者说是应用方法。我们一般考虑的就是窗口的两个端点,可以看作两个指针。一般应用的题型的数据结构是字符串或者是数组。而且滑动窗口算法一般都可以使用暴力法来进行解决。</p>
<p>滑动窗口一般处理都是连续问题,连续子数组或者是子串问题。因为非连续问题不可能存在于一个窗口中,那个时候可能使用动态规划可能会好一点。从类型上来说,滑动窗口一般分为两种类型:</p>
<ul>
<li>固定窗口大小,然后找到符合条件的结果</li>
<li>非固定窗口大小,找到满足符合条件的结果。</li>
</ul>
<h4 id="固定窗口大小">固定窗口大小</h4>
<p>对于固定窗口大小,我们第一步就需要初始化窗口,即构建一个最开始窗口。</p>
<ul>
<li>初始化<code>l</code>为0,初始化<code>r</code>使得<code>r-l+1</code>为窗口大小。</li>
<li>同时移动<code>l、r</code>,来保证窗口的移动。</li>
<li>判断窗口内部是否满足题目的条件,如果满足则更新或者直接结束,不满足则继续进行循环。</li>
</ul>
<h5 id="例题">例题</h5>
<p><a href="https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/">438. 找到字符串中所有字母异位词 - 力扣(LeetCode) (leetcode-cn.com)</a></p>
<p>该题就是固定窗口大小,而窗口大小并不是直接给出,而是根据匹配字符串的长度来确定窗口长度大小。使用哈希表的目的是为了判断是否满足题目中的条件,而答题流程则是固定滑动窗口答题流程。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">findAnagrams</span><span class="p">(</span><span class="nx">s</span><span class="p">,</span> <span class="nx">p</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="nx">ans</span> <span class="p">[]</span><span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">sLen</span><span class="p">,</span> <span class="nx">pLen</span> <span class="o">:=</span> <span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span>
<span class="k">if</span> <span class="nx">sLen</span> <span class="p">&lt;</span> <span class="nx">pLen</span> <span class="p">{</span>
<span class="k">return</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">sCount</span><span class="p">,</span> <span class="nx">pCount</span> <span class="p">[</span><span class="mi">26</span><span class="p">]</span><span class="kt">int</span>
<span class="c1">// 这部分就是初始化滑动窗口
</span><span class="c1"></span> <span class="k">for</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">ch</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">p</span> <span class="p">{</span>
<span class="nx">sCount</span><span class="p">[</span><span class="nx">s</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="o">-</span><span class="sc">&#39;a&#39;</span><span class="p">]</span><span class="o">++</span>
<span class="nx">pCount</span><span class="p">[</span><span class="nx">ch</span><span class="o">-</span><span class="sc">&#39;a&#39;</span><span class="p">]</span><span class="o">++</span>
<span class="p">}</span>
<span class="c1">// 初始化之后就需要进行一次判断
</span><span class="c1"></span> <span class="k">if</span> <span class="nx">sCount</span> <span class="o">==</span> <span class="nx">pCount</span> <span class="p">{</span>
<span class="nx">ans</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">ans</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">for</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">ch</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">s</span><span class="p">[:</span><span class="nx">sLen</span><span class="o">-</span><span class="nx">pLen</span><span class="p">]</span> <span class="p">{</span>
<span class="c1">// 进入滑动窗口 即r的移动
</span><span class="c1"></span> <span class="nx">sCount</span><span class="p">[</span><span class="nx">ch</span><span class="o">-</span><span class="sc">&#39;a&#39;</span><span class="p">]</span><span class="o">--</span>
<span class="c1">// 从滑动窗口中取出 即l的移动
</span><span class="c1"></span> <span class="nx">sCount</span><span class="p">[</span><span class="nx">s</span><span class="p">[</span><span class="nx">i</span><span class="o">+</span><span class="nx">pLen</span><span class="p">]</span><span class="o">-</span><span class="sc">&#39;a&#39;</span><span class="p">]</span><span class="o">++</span>
<span class="c1">// 进行是否满足条件的判断
</span><span class="c1"></span> <span class="k">if</span> <span class="nx">sCount</span> <span class="o">==</span> <span class="nx">pCount</span> <span class="p">{</span>
<span class="nx">ans</span> <span class="p">=</span> <span class="nb">append</span><span class="p">(</span><span class="nx">ans</span><span class="p">,</span> <span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="可变滑动窗口">可变滑动窗口</h4>
<p>对于可变滑动窗口,由于窗口大小是未知的,所以初始化的时候窗口大小为1</p>
<ul>
<li>初始化<code>l、r</code>为0</li>
<li>移动<code>r</code>,来保证窗口的扩张。</li>
<li>判断窗口内部是否满足题目的条件,如果满足则更新或者直接结束,不满足则可以通过和条件对比来增加<code>l</code>或者是<code>r</code>。</li>
</ul>
<h5 id="例题-1">例题</h5>
<p><a href="https://leetcode-cn.com/problems/subarray-product-less-than-k/">713. 乘积小于K的子数组 - 力扣(LeetCode) (leetcode-cn.com)</a></p>
<p>该题就很明显可以使用滑动窗口,并且窗口大小是可变的。而需要满足的条件就是乘积小于<code>K</code>。之后每次满足条件之后更新参数即可,并根据乘积值来更新窗口的大小。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">numSubarrayProductLessThanK</span><span class="p">(</span><span class="nx">nums</span> <span class="p">[]</span><span class="kt">int</span><span class="p">,</span> <span class="nx">k</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span>
<span class="c1">// 乘积小于k
</span><span class="c1"></span> <span class="c1">// 连续的子数组
</span><span class="c1"></span> <span class="c1">// 严格小于 等于不行
</span><span class="c1"></span> <span class="c1">// 正整数数组,即 k&lt;=1的话就直接返回空数组
</span><span class="c1"></span> <span class="nx">res</span> <span class="o">:=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="nx">k</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">{</span>
<span class="k">return</span> <span class="nx">res</span>
<span class="p">}</span>
<span class="nx">mul</span> <span class="o">:=</span> <span class="mi">1</span>
<span class="nx">l</span><span class="p">,</span><span class="nx">r</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">,</span><span class="mi">0</span>
<span class="c1">// 滑动窗口 窗口长度的变化
</span><span class="c1"></span> <span class="c1">// 如果一个窗口的乘积小于k 因为都是正整数 所以整个区间内部的小窗口都会小于k
</span><span class="c1"></span> <span class="k">for</span> <span class="nx">r</span> <span class="p">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="nx">nums</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">mul</span> <span class="o">*=</span> <span class="nx">nums</span><span class="p">[</span><span class="nx">r</span><span class="p">]</span>
<span class="nx">r</span><span class="o">++</span>
<span class="k">for</span> <span class="nx">mul</span> <span class="o">&gt;=</span> <span class="nx">k</span> <span class="p">{</span>
<span class="nx">mul</span> <span class="o">/=</span> <span class="nx">nums</span><span class="p">[</span><span class="nx">l</span><span class="p">]</span>
<span class="nx">l</span><span class="o">++</span>
<span class="p">}</span>
<span class="nx">res</span> <span class="o">+=</span> <span class="p">(</span><span class="nx">r</span><span class="o">-</span><span class="nx">l</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">res</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="快慢指针">快慢指针</h3>
<p>快慢指针一般用于在链表中寻找中点,或者是链表环问题。一般是利用快指针会比慢指针走的距离多一倍。</p>
<h4 id="142-环形链表-iihttpsleetcode-cncomproblemslinked-list-cycle-ii"><a href="https://leetcode-cn.com/problems/linked-list-cycle-ii/">142. 环形链表 II</a></h4>
<p>相比<a href="https://leetcode-cn.com/problems/linked-list-cycle/">环形链表</a>该题需要找到环的入口,判断环形链表则是使用快指针慢指针走的位置是存在倍数关系的。而判断环的入口则是使用了两者之间走过的距离差是环的长度整数倍的数学关系。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">detectCycle</span><span class="p">(</span><span class="nx">head</span> <span class="o">*</span><span class="nx">ListNode</span><span class="p">)</span> <span class="o">*</span><span class="nx">ListNode</span> <span class="p">{</span>
<span class="c1">// 找到环入口节点
</span><span class="c1"></span> <span class="nx">slow</span><span class="p">,</span> <span class="nx">fast</span> <span class="o">:=</span> <span class="nx">head</span><span class="p">,</span> <span class="nx">head</span>
<span class="k">for</span> <span class="nx">fast</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="o">&amp;&amp;</span> <span class="nx">fast</span><span class="p">.</span><span class="nx">Next</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
<span class="nx">slow</span> <span class="p">=</span> <span class="nx">slow</span><span class="p">.</span><span class="nx">Next</span>
<span class="nx">fast</span> <span class="p">=</span> <span class="nx">fast</span><span class="p">.</span><span class="nx">Next</span><span class="p">.</span><span class="nx">Next</span>
<span class="k">if</span> <span class="nx">fast</span> <span class="o">==</span> <span class="nx">slow</span> <span class="p">{</span>
<span class="k">break</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="nx">fast</span> <span class="o">==</span> <span class="kc">nil</span> <span class="o">||</span> <span class="nx">fast</span><span class="p">.</span><span class="nx">Next</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">nil</span>
<span class="p">}</span>
<span class="c1">// 相等证明有环
</span><span class="c1"></span> <span class="nx">fast</span> <span class="p">=</span> <span class="nx">head</span>
<span class="k">for</span> <span class="nx">slow</span> <span class="o">!=</span> <span class="nx">fast</span> <span class="p">{</span>
<span class="nx">slow</span> <span class="p">=</span> <span class="nx">slow</span><span class="p">.</span><span class="nx">Next</span>
<span class="nx">fast</span> <span class="p">=</span> <span class="nx">fast</span><span class="p">.</span><span class="nx">Next</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">fast</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="876-链表的中间结点httpsleetcode-cncomproblemsmiddle-of-the-linked-list"><a href="https://leetcode-cn.com/problems/middle-of-the-linked-list/">876. 链表的中间结点</a></h4>
<p>该题是快慢指针最简单的运用,即快指针比慢指针走的距离的二倍。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">findMid</span><span class="p">(</span><span class="nx">head</span> <span class="o">*</span><span class="nx">ListNode</span><span class="p">)</span> <span class="o">*</span><span class="nx">ListNode</span><span class="p">{</span>
<span class="nx">slow</span><span class="p">,</span><span class="nx">fast</span> <span class="o">:=</span> <span class="nx">head</span><span class="p">,</span><span class="nx">head</span>
<span class="k">for</span> <span class="nx">fast</span><span class="o">!=</span><span class="kc">nil</span> <span class="o">||</span> <span class="nx">fast</span><span class="p">.</span><span class="nx">Next</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
<span class="nx">slow</span> <span class="p">=</span> <span class="nx">slow</span><span class="p">.</span><span class="nx">Next</span>
<span class="nx">fast</span> <span class="p">=</span> <span class="nx">fast</span><span class="p">.</span><span class="nx">Next</span><span class="p">.</span><span class="nx">Next</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">slow</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div>
</description>
</item>
<item>
<title>计算机网络</title>
<link>https://hearecho.github.io/post/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</link>
<pubDate>Fri, 08 Apr 2022 20:47:06 +0800</pubDate>
<guid>https://hearecho.github.io/post/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</guid>
<description>
<h2 id="网络层相关">网络层相关</h2>
<h2 id="传输层相关">传输层相关</h2>
<h3 id="1-既然ip层会分片-为什么tcp还要分段">1. 既然IP层会分片, 为什么TCP还要分段?</h3>
<p>IP分片的原因:</p>
<p>受到传输链路MTU的影响,而且因为数据链路层的MTU在传输过程中会发生改变,所以说在传输的过程中经过某个路由器之后也会进行分片。MTU默认值为1500byte</p>
<p>TCP分片的原因:</p>
<p>TCP分片的主要原因是因为受到网络层数据段的影响。即MSS大小的限制。MSS大小限制为1460,即1500 - 20(IP头) -20(TCP头)。</p>
<p>TCP还要分段的原因:</p>
<p>如果是TCP不分段,</p>
<h2 id="其他">其他</h2>
</description>
</item>
<item>
<title>Go垃圾收集</title>
<link>https://hearecho.github.io/post/go%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86/</link>
<pubDate>Fri, 04 Mar 2022 17:04:41 +0800</pubDate>
<guid>https://hearecho.github.io/post/go%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86/</guid>
<description>
<h2 id="go-垃圾收集">Go 垃圾收集</h2>
<p>Go垃圾收集使用的标记清除的方式,并且是并行GC,即和用户程序是一起运行的。标记方式使用的则是三色收集法。</p>
<h3 id="垃圾收集步骤">垃圾收集步骤</h3>
<p>Go垃圾收集总共是分为四部分:</p>
<ol>
<li>Sweep Termination: 对未清扫的span进行清扫, 只有上一轮的GC的清扫工作完成才可以开始新一轮的GC</li>
<li>Mark: 扫描所有根对象, 和根对象可以到达的所有对象, 标记它们不被回收</li>
<li>Mark Termination: 完成标记工作, 重新扫描部分根对象</li>
<li>Sweep: 按标记结果清扫span</li>
</ol>
<p>在GC过程中会有两种后台任务(G), 一种是标记用的后台任务, 一种是清扫用的后台任务。清扫任务会在程序启动时就启动,但是在进入清扫阶段之后才被唤醒。其中在标记阶段开始的时候和标记阶段结束的时候需要停止用户程序即STW(Stop The World)。两次STW的作用如下:</p>
<ol>
<li>第一次STW会准备根对象的扫描, 启动写屏障(Write Barrier)和辅助GC(mutator assist).</li>
<li>第二次STW会重新扫描部分根对象, 禁用写屏障(Write Barrier)和辅助GC(mutator assist).</li>
</ol>
<h3 id="gc的触发条件">Gc的触发条件</h3>
<p>源码给出的触发条件主要有三种,如果不是这三种则是一直进行GC:</p>
<ol>
<li>gcTriggerHeap: 当前分配的内存达到一定值就触发GC</li>
<li>gcTriggerTime: 当一定时间没有执行过GC就触发GC</li>
<li>gcTriggerCycle: 要求启动新一轮的GC, 已启动则跳过, 手动触发GC的<code>runtime.GC()</code>会使用这个条件</li>
</ol>
<p>go源代码如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="p">(</span><span class="nx">t</span> <span class="nx">gcTrigger</span><span class="p">)</span> <span class="nf">test</span><span class="p">()</span> <span class="kt">bool</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">!</span><span class="nx">memstats</span><span class="p">.</span><span class="nx">enablegc</span> <span class="o">||</span> <span class="nx">panicking</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">||</span> <span class="nx">gcphase</span> <span class="o">!=</span> <span class="nx">_GCoff</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">false</span>
<span class="p">}</span>
<span class="k">switch</span> <span class="nx">t</span><span class="p">.</span><span class="nx">kind</span> <span class="p">{</span>
<span class="k">case</span> <span class="nx">gcTriggerHeap</span><span class="p">:</span>
<span class="c1">// Non-atomic access to heap_live for performance. If
</span><span class="c1"></span> <span class="c1">// we are going to trigger on this, this thread just
</span><span class="c1"></span> <span class="c1">// atomically wrote heap_live anyway and we&#39;ll see our
</span><span class="c1"></span> <span class="c1">// own write.
</span><span class="c1"></span> <span class="k">return</span> <span class="nx">memstats</span><span class="p">.</span><span class="nx">heap_live</span> <span class="o">&gt;=</span> <span class="nx">memstats</span><span class="p">.</span><span class="nx">gc_trigger</span>
<span class="k">case</span> <span class="nx">gcTriggerTime</span><span class="p">:</span>
<span class="k">if</span> <span class="nx">gcpercent</span> <span class="p">&lt;</span> <span class="mi">0</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">false</span>
<span class="p">}</span>
<span class="nx">lastgc</span> <span class="o">:=</span> <span class="nb">int64</span><span class="p">(</span><span class="nx">atomic</span><span class="p">.</span><span class="nf">Load64</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">memstats</span><span class="p">.</span><span class="nx">last_gc_nanotime</span><span class="p">))</span>
<span class="k">return</span> <span class="nx">lastgc</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="nx">t</span><span class="p">.</span><span class="nx">now</span><span class="o">-</span><span class="nx">lastgc</span> <span class="p">&gt;</span> <span class="nx">forcegcperiod</span>
<span class="k">case</span> <span class="nx">gcTriggerCycle</span><span class="p">:</span>
<span class="c1">// t.n &gt; work.cycles, but accounting for wraparound.
</span><span class="c1"></span> <span class="k">return</span> <span class="nb">int32</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">n</span><span class="o">-</span><span class="nx">work</span><span class="p">.</span><span class="nx">cycles</span><span class="p">)</span> <span class="p">&gt;</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">true</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="三色标记法">三色标记法</h3>
<p>三色标记法就是通过堆内存中不同状态的下的对象进行标价来为后续的清除做准备。三色的含义如下:</p>
<ol>
<li>黑色: 对象在这次GC中已标记, 且这个对象包含的子对象也已标记</li>
<li>灰色: 对象在这次GC中已标记, 但这个对象包含的子对象未标记</li>
<li>白色: 对象在这次GC中未标记</li>
</ol>
<p>三色标记的过程:</p>
<ol>
<li>先将Gc root标记为灰色,加入到灰色队列中</li>
<li>从灰色队列中取出对象,将其标记为黑色,并将其直接引用对象标记为灰色放入到灰色队列中</li>
<li>重复步骤2,直到没有灰色对象的存在,此时剩余的白色对象就是需要进行回收的对象。</li>
</ol>
<p>Gc root对象</p>
<ul>
<li>Fixed Roots: 特殊的扫描工作
<ul>
<li>fixedRootFinalizers: 扫描析构器队列</li>
<li>fixedRootFreeGStacks: 释放已中止的G的栈</li>
</ul>
</li>
<li>Flush Cache Roots: 释放mcache中的所有span, 要求STW</li>
<li>Data Roots: 扫描可读写的全局变量</li>
<li>BSS Roots: 扫描只读的全局变量</li>
<li>Span Roots: 扫描各个span中特殊对象(析构器列表)</li>
<li>Stack Roots: 扫描各个G的栈</li>
</ul>
<h3 id="写屏障">写屏障</h3>
<p>写屏障的存在是因为go的垃圾收集过程是和用户程序并行的。并行的过程就会产生一些对象依赖上的变化,造成错误回收。例如开始扫描的时候发现根对象A和B,B拥有C的指针,GC先扫描A, 然后B把C的指针交给A, GC再扫描B, 这时C就不会被扫描到。写屏障就是为了避免这种类型的问题而存在的。</p>
<p><strong>启用了写屏障(Write Barrier)后, 当B把C的指针交给A时, GC会认为在这一轮的扫描中C的指针是存活的,
即使A可能会在稍后丢掉C, 那么C就在下一轮回收.</strong></p>
<p>也就是说,写屏障启动之后,用户程序的改动对于GC将不会造成任何影响,相互独立。写屏障只针对指针启用, 而且只在GC的标记阶段启用, 平时会直接把值写入到目标地址.</p>
<p>混合写屏障会同时标记指针写入目标的&quot;原指针&quot;和“新指针&quot;。标记原指针的原因是,,其他运行中的线程有可能会同时把这个指针的值复制到寄存器或者栈上的本地变量,因为<strong>复制指针到寄存器或者栈上的本地变量不会经过写屏障</strong>, 所以有可能会导致指针不被标记,记新指针的原因是, 其他运行中的线程有可能会转移指针的位置。混合写屏障可以让GC在并行标记结束后不需要重新扫描各个G的堆栈, 可以减少Mark Termination中的STW时间。如果只是单独的写屏障,需要排除那些不经过写屏障的读写操作。</p>
<h3 id="辅助gc">辅助GC</h3>
<p>为了防止heap增速太快, 在GC执行的过程中如果同时运行的G分配了内存, 那么这个G会被要求辅助GC做一部分的工作.
在GC的过程中同时运行的G称为&quot;mutator&quot;, &ldquo;mutator assist&quot;机制就是G辅助GC做一部分工作的机制.</p>
<p>辅助GC做的工作有两种类型, 一种是标记(Mark), 另一种是清扫(Sweep).</p>
</description>
</item>
<item>
<title>Go Question</title>
<link>https://hearecho.github.io/post/go-question/</link>
<pubDate>Fri, 25 Feb 2022 14:12:22 +0800</pubDate>
<guid>https://hearecho.github.io/post/go-question/</guid>
<description>
<h3 id="go-questions">Go Questions</h3>
<h4 id="1nil切片和空切片零切片">1.nil切片和空切片、零切片</h4>
<p>nil切片指向的地址为0,而所有创建的空切片的内存地址是存在的,并且是一个固定值。</p>
<p>零切片就是底层数组内部数据全是<code>零变量</code>。说白了就是使用<code>make</code>初始化之后的切片。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">compareSlice</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">s1</span> <span class="p">[]</span><span class="kt">int</span>
<span class="nx">s2</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span>
<span class="nx">s4</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;s1 pointer:%+v, s2 pointer:%+v, s4 pointer:%+v, \n&#34;</span><span class="p">,</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">SliceHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s1</span><span class="p">)),</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">SliceHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s2</span><span class="p">)),</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">SliceHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s4</span><span class="p">)))</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%v\n&#34;</span><span class="p">,</span> <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">SliceHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s1</span><span class="p">))).</span><span class="nx">Data</span><span class="o">==</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">SliceHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s2</span><span class="p">))).</span><span class="nx">Data</span><span class="p">)</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%v\n&#34;</span><span class="p">,</span> <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">SliceHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s2</span><span class="p">))).</span><span class="nx">Data</span><span class="o">==</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">SliceHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s4</span><span class="p">))).</span><span class="nx">Data</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// 结果
</span><span class="c1"></span><span class="cm">/**
</span><span class="cm">s1 pointer:{Data:0 Len:0 Cap:0}, s2 pointer:{Data:824633999016 Len:0 Cap:0}, s4 pointer:{Data:824633999016 Len:0 Cap:0},
</span><span class="cm">false
</span><span class="cm">true
</span><span class="cm">*/</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="2字符串转换为byte数组会发生内存拷贝吗">2.字符串转换为byte数组,会发生内存拷贝吗?</h4>
<p>严格来说,只要进行了类型的强制转换都会发生内存拷贝。所以说字符串转换为byte数组会发生内存拷贝。go的字符串也为不可变对象,在内存中的实现方式是一个只读的字节数组。字符串要想修改只能先转换为可写的数组,然后在转换为字符串。其数据结构如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">StringHeader</span> <span class="kd">struct</span> <span class="p">{</span>
<span class="nx">Data</span> <span class="kt">uintptr</span>
<span class="nx">Len</span> <span class="kt">int</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>用代码展示,可以从结果上看出,不论是从字符串转换为byte数组还是从byte数组转换为字符串,均发生内存拷贝了。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">StringAndByte</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">s</span> <span class="o">:=</span> <span class="s">&#34;hello&#34;</span>
<span class="nx">tempByte</span> <span class="o">:=</span> <span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span>
<span class="nx">s2</span> <span class="o">:=</span> <span class="nb">string</span><span class="p">(</span><span class="nx">tempByte</span><span class="p">)</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;s Pointer:%+v\n&#34;</span><span class="p">,</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">StringHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s</span><span class="p">)))</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;tempByte Pointer:%+v\n&#34;</span><span class="p">,</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">SliceHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">tempByte</span><span class="p">)))</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;s2 Pointer:%+v\n&#34;</span><span class="p">,</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">StringHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">s2</span><span class="p">)))</span>
<span class="p">}</span>
<span class="c1">// 结果
</span><span class="c1"></span><span class="cm">/**
</span><span class="cm">s Pointer:{Data:12543120 Len:5}
</span><span class="cm">tempByte Pointer:{Data:824633999064 Len:5 Cap:32}
</span><span class="cm">s2 Pointer:{Data:824633999032 Len:5}
</span><span class="cm">*/</span>
</code></pre></td></tr></table>
</div>
</div><p><strong>不过也有方法可以不用进行内存拷贝实现转换</strong>,实际上,字符串和byte数组的底层结构之间只是少了Cap字段,所以我们可以将<code>StringHeader</code> 的地址强转成 <code>SliceHeader</code> 就可以了。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">a</span> <span class="o">:=</span><span class="s">&#34;aaa&#34;</span>
<span class="nx">ssh</span> <span class="o">:=</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="nx">reflect</span><span class="p">.</span><span class="nx">StringHeader</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">a</span><span class="p">))</span>
<span class="nx">b</span> <span class="o">:=</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="p">[]</span><span class="kt">byte</span><span class="p">)(</span><span class="nx">unsafe</span><span class="p">.</span><span class="nf">Pointer</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">ssh</span><span class="p">))</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="3翻转含有中文数字英文字母的字符串">3.翻转含有中文、数字、英文字母的字符串</h4>
<p>因为中文、英文、数字所占用的字节数是不相同的,所以我们不可以使用转换为byte数组来进行反转在转换,我们这个情况需要将字符串转换为<code>[]rune</code>,因为其表示的范围更大,<code>rune==int32</code>而<code>byte==uint8</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">ReverseComplexString</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">reverse</span> <span class="o">:=</span> <span class="kd">func</span> <span class="p">(</span><span class="nx">s</span> <span class="p">[]</span><span class="kt">rune</span><span class="p">)</span> <span class="p">[]</span><span class="kt">rune</span> <span class="p">{</span>
<span class="k">for</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">j</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="p">&lt;</span> <span class="nx">j</span><span class="p">;</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">j</span> <span class="p">=</span> <span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="nx">j</span><span class="o">-</span><span class="mi">1</span> <span class="p">{</span>
<span class="nx">s</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="nx">s</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span> <span class="p">=</span> <span class="nx">s</span><span class="p">[</span><span class="nx">j</span><span class="p">],</span> <span class="nx">s</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">s</span>
<span class="p">}</span>
<span class="nx">src</span> <span class="o">:=</span> <span class="s">&#34;你好abc啊哈哈&#34;</span>
<span class="nx">dst</span> <span class="o">:=</span> <span class="nf">reverse</span><span class="p">([]</span><span class="nb">rune</span><span class="p">(</span><span class="nx">src</span><span class="p">))</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;%v\n&#34;</span><span class="p">,</span> <span class="nb">string</span><span class="p">(</span><span class="nx">dst</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="4-拷贝大切片一定比小切片的代价大吗">4. 拷贝大切片一定比小切片的代价大吗?</h4>
<p>并不是,所有切片的大小相同;<strong>三个字段</strong>(一个 uintptr,两个int)。切片中的第一个字是指向切片底层数组的指针,这是切片的存储空间,第二个字段是切片的长度,第三个字段是容量。将一个 slice 变量分配给另一个变量只会复制三个机器字。所以 <strong>拷贝大切片跟小切片的代价应该是一样的</strong>。</p>
<p><em>拷贝就相当于是变换指针的指向,而不是将内存数据从一个地址拷贝到另一处地址,所以这个只更换指针的指向也造成了更改其中一个切片的数据,另一个切片显示的数据也会改变即为<strong>浅拷贝</strong></em></p>
<h4 id="5-map不初始化使用会怎么样slice呢">5. map不初始化使用会怎么样,slice呢?</h4>
<p>map不初始化为nil,向里面添加值会直接报错。<code>panic: assignment to entry in nil map</code>。但是可以进行取值,不过返回的是对应类型的零值。并且初始化和不初始化的map。长度均为0。但是<code>slice</code>是可以声明之后就可以使用(<strong>不是真正意义上的使用</strong>)的,可以使用<code>append</code>向里面添加元素(这种方式其实是返回了一个新的切片),但是不能使用直接用索引赋值的方法添加元素,不过<code>slice</code>声明不初始化的话其指向的底层数组地址为<code>0</code>,第一次添加元素之后会给出一个内存地址。</p>
<h4 id="6-map承载多大大了之后怎么扩容">6. map承载多大,大了之后怎么扩容?</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// Maximum number of key/elem pairs a bucket can hold.
</span><span class="c1"></span><span class="nx">bucketCntBits</span> <span class="p">=</span> <span class="mi">3</span>
<span class="nx">bucketCnt</span> <span class="p">=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="nx">bucketCntBits</span>
<span class="c1">// 每个桶大小为 8
</span><span class="c1">// Maximum average load of a bucket that triggers growth is 6.5.
</span><span class="c1">// Represent as loadFactorNum/loadFactorDen, to allow integer math.
</span><span class="c1"></span><span class="nx">loadFactorNum</span> <span class="p">=</span> <span class="mi">13</span>
<span class="nx">loadFactorDen</span> <span class="p">=</span> <span class="mi">2</span>
<span class="c1">// 溢出因子大小为 6.5
</span></code></pre></td></tr></table>
</div>
</div><p>哈希表 <code>runtime.hmap</code> 的桶是 <code>runtime.bmap</code>。每一个 <code>runtime.bmap</code> 都能存储<strong>8</strong>个键值对,当哈希表中存储的数据过多,单个桶已经装满时就会使用 <code>extra.nextOverflow</code> 中桶存储溢出的数据。 而发生扩容的条件是:</p>
<ol>
<li>触发 <code>load factor</code> 的最大值,负载因子已达到当前界限。负载因子越大,证明空间效率越高,同时发生冲突的概率也越大。</li>
<li>溢出桶 <code>overflow buckets</code> 过多。即溢出桶和全部正常桶数量的比值。比值过大就证明溢出桶过多。</li>
</ol>
<p>而map的扩容也是分为两种情况进行扩容的,如果是负载因子达到最大值,则是直接动态扩容当前大小两倍作为新容量的大小。而如果是溢出桶过多,则是不改变大小的扩容。而扩容并不是一步到位,而是先申请扩容空间,但是不会进行初始化,而是等到有新的访问落到某个桶中,才会对这个桶进行扩容,也就是将<code>oldbucket</code>迁移到<code>bucket</code>。</p>
<h4 id="7-map的iterator是否安全能不能一边delete一边遍历">7. map的iterator是否安全?能不能一边delete一边遍历?</h4>
<p>map的iterator是不安全的,我们需要手动对其进行并发约束来使其到达在并发中的数据安全。一般是使用<code>sync.RWMutex</code>或者是使用<code>channel chan</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">var</span> <span class="nx">myMap</span> <span class="kd">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="kt">string</span>
<span class="kd">func</span> <span class="nf">myGoRoutine</span><span class="p">(</span><span class="nx">id</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">numKeys</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">wg</span> <span class="o">*</span><span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span><span class="p">)</span> <span class="p">{</span>
<span class="k">defer</span> <span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
<span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">myMap</span> <span class="p">{</span>
<span class="nx">myMap</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="p">=</span> <span class="nx">strconv</span><span class="p">.</span><span class="nf">Itoa</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">value</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">myMap</span> <span class="p">{</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Goroutine #%d -&gt; Key: %d, Value: %s\n&#34;</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">UnSafeMap</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Initially set some values
</span><span class="c1"></span> <span class="nx">myMap</span> <span class="p">=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">int</span><span class="p">]</span><span class="kt">string</span><span class="p">)</span>
<span class="nx">myMap</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">=</span> <span class="s">&#34;test&#34;</span>
<span class="nx">myMap</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="p">=</span> <span class="s">&#34;sample&#34;</span>
<span class="nx">myMap</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="p">=</span> <span class="s">&#34;GoLang is Fun!&#34;</span>
<span class="c1">// Get the number of keys
</span><span class="c1"></span> <span class="nx">numKeys</span> <span class="o">:=</span> <span class="nb">len</span><span class="p">(</span><span class="nx">myMap</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">wg</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span>
<span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="p">&lt;</span> <span class="mi">3</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
<span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">go</span> <span class="nf">myGoRoutine</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">numKeys</span><span class="p">,</span> <span class="o">&amp;</span><span class="nx">wg</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// Blocking wait
</span><span class="c1"></span> <span class="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
<span class="c1">// Iterate over all keys
</span><span class="c1"></span> <span class="k">for</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">value</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">myMap</span> <span class="p">{</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;Key: %d, Value: %s\n&#34;</span><span class="p">,</span> <span class="nx">key</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="cm">/*
</span><span class="cm">结果
</span><span class="cm">Goroutine #2 -&gt; Key: 0, Value: 2
</span><span class="cm">Goroutine #2 -&gt; Key: 2, Value: 2
</span><span class="cm">Goroutine #2 -&gt; Key: 1, Value: 2
</span><span class="cm">Goroutine #1 -&gt; Key: 0, Value: 1
</span><span class="cm">Goroutine #1 -&gt; Key: 2, Value: 1
</span><span class="cm">Goroutine #1 -&gt; Key: 1, Value: 1
</span><span class="cm">Goroutine #0 -&gt; Key: 0, Value: 0
</span><span class="cm">Goroutine #0 -&gt; Key: 2, Value: 1
</span><span class="cm">Goroutine #0 -&gt; Key: 1, Value: 1
</span><span class="cm">Key: 0, Value: 1
</span><span class="cm">Key: 2, Value: 1
</span><span class="cm">Key: 1, Value: 1
</span><span class="cm">*/</span>
</code></pre></td></tr></table>
</div>
</div><p>同时go中的map是可以一边进行操作然后一边进行遍历的。但是虽然不会出错,但是当前遍历不会受到影响。不像java他们的迭代器具有Fail-Fast性质。</p>
<h4 id="8-怎么判断一个数组是否有序">8. 怎么判断一个数组是否有序</h4>
<p>第一种方法是实现<code>sort.Interface</code>的接口类型,然后直接调用<code>sort.IsSorted()</code>方法即可。或者直接使用<code>sort.SliceIsSorted</code>函数。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">jungeSorted</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">arr</span> <span class="o">:=</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="mi">5</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">}</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">sort</span><span class="p">.</span><span class="nf">SliceIsSorted</span><span class="p">(</span><span class="nx">arr</span><span class="p">,</span> <span class="kd">func</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">j</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">arr</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="p">&gt;</span> <span class="nx">arr</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span>
<span class="p">}))</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="9-array和slice的区别">9. array和slice的区别</h4>
<p>数组<code>array</code>是值类型的,其作为参数传递给函数,就是将数组拷贝一份,而切片<code>slice</code>是一个引用类型,是一个动态指向数组切片的指针,不定长。声明数组的时候,方括号内写明了数组长度或者使用<code>...</code>进行代替,而声名切片的时候方括号内部为空。作为函数参数时候,切片传递的是指针,所以在函数内部改动,外部切片也会发生相应的变化。</p>
<h4 id="10-json包变量不加tag会怎么样">10. json包变量不加tag会怎么样?</h4>
<ul>
<li>
<p>如果变量<code>首字母小写</code>,则为<code>private</code>。无论如何<code>不能转</code>,因为取不到<code>反射信息</code>。</p>
</li>
<li>
<p>如果变量<code>首字母大写</code>,则为<code>public</code>。</p>
</li>
<li>
<ul>
<li><code>不加tag</code>,可以正常转为<code>json</code>里的字段,<code>json</code>内字段名跟结构体内字段<code>原名一致</code>。</li>
<li><code>加了tag</code>,从<code>struct</code>转<code>json</code>的时候,<code>json</code>的字段名就是<code>tag</code>里的字段名,原字段名已经没用。</li>
</ul>
</li>
</ul>
<p><code>tag</code>信息是可以通过<code>reflect</code>获取的。即:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">J</span> <span class="kd">struct</span> <span class="p">{</span> <span class="nx">a</span> <span class="kt">string</span> <span class="c1">//小写无tag b string `json:&#34;B&#34;` //小写+tag C string //大写无tag D string `json:&#34;DD&#34; otherTag:&#34;good&#34;` //大写+tag}func printTag(stru interface{}) { t := reflect.TypeOf(stru).Elem() for i := 0; i &lt; t.NumField(); i++ { fmt.Printf(&#34;结构体内第%v个字段 %v 对应的json tag是 %v , 还有otherTag? = %v \n&#34;, i+1, t.Field(i).Name, t.Field(i).Tag.Get(&#34;json&#34;), t.Field(i).Tag.Get(&#34;otherTag&#34;)) }}func main() { j := J{ a: &#34;1&#34;, b: &#34;2&#34;, C: &#34;3&#34;, D: &#34;4&#34;, } printTag(&amp;j)}
</span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>printTag</code>方法传入的是<code>j</code>的指针。</li>
<li><code>reflect.TypeOf(stru).Elem()</code>获取指针指向的值对应的结构体内容。</li>
<li><code>NumField()</code>可以获得该结构体的含有几个字段。</li>
<li>遍历结构体内的字段,通过<code>t.Field(i).Tag.Get(&quot;json&quot;)</code>可以获取到<code>tag</code>为<code>json</code>的字段。</li>
<li>如果结构体的字段有<code>多个tag</code>,比如叫<code>otherTag</code>,同样可以通过<code>t.Field(i).Tag.Get(&quot;otherTag&quot;)</code>获得</li>
</ul>
<h4 id="11-深拷贝和浅拷贝">11. 深拷贝和浅拷贝</h4>
<p> 一般简单的拷贝,即指针指向转换,即虽然是两个切片,但是他们指向同一个底层数组,此为浅拷贝,即通过其中一个切片修改数据,另一个切片的内容也会发生变化。而深拷贝,则是进行了内存拷贝,底层数组的拷贝,两个切片指向的地址是不相同的。同时需要注意引用切片,其中的引用如果不进行递归深拷贝,则还是会出现问题。</p>
<h4 id="12-make和new的区别">12. make和new的区别</h4>
<p> new可以用于任何类型的分配空间,指定内存,并返回该类型的指针。同时 new 函数会把分配的内存置为零,也就是类型的零值。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// The new built-in function allocates memory. The first argument is a type,// not a value, and the value returned is a pointer to a newly// allocated zero value of that type.func new(Type) *Type
</span></code></pre></td></tr></table>
</div>
</div><p><code>make</code>只能用于<code>slice, map, channel</code>的初始化。这三个刚好为引用类型,并且<strong>Unlike new, make&rsquo;s return type is the same as the type of its
argument, not a pointer to it.</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// The make built-in function allocates and initializes an object of type// slice, map, or chan (only). Like new, the first argument is a type, not a// value. Unlike new, make&#39;s return type is the same as the type of its// argument, not a pointer to it. The specification of the result depends on// the type:// Slice: The size specifies the length. The capacity of the slice is// equal to its length. A second integer argument may be provided to// specify a different capacity; it must be no smaller than the// length. For example, make([]int, 0, 10) allocates an underlying array// of size 10 and returns a slice of length 0 and capacity 10 that is// backed by this underlying array.// Map: An empty map is allocated with enough space to hold the// specified number of elements. The size may be omitted, in which case// a small starting size is allocated.// Channel: The channel&#39;s buffer is initialized with the specified// buffer capacity. If zero, or the size is omitted, the channel is// unbuffered.func make(t Type, size ...IntegerType) Type
</span></code></pre></td></tr></table>
</div>
</div><h4 id="13--slicemapchannel创建的时候的几个参数什么含义">13. slice,map,channel创建的时候的几个参数什么含义?</h4>
<p> 由于切片的底层即<code>SliceHeader</code>的结构如下所示。而创建切片的使用<code>make(type, len, cap)</code>,<code>cap</code>通常可以省略,省略情况下<code>cap=len</code>。因为两者之间的关系为<code>cap&gt;=len&gt;=0</code>。其中<code>cap</code>代表容量,<code>len</code>代表当前切片的长度。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">SliceHeader</span> <span class="kd">struct</span> <span class="p">{</span> <span class="nx">Data</span> <span class="kt">uintptr</span> <span class="nx">Len</span> <span class="kt">int</span> <span class="nx">Cap</span> <span class="kt">int</span><span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><p>而我们创建<code>map</code>通常使用<code>make(map[Type]Type,size)</code>,<code>size</code>表示map的存储能力,可以省略。使用<code>make(chan Type, size)</code>创建channel而<code>size</code>表示的具有通道的缓冲区大小,如果不设置,则表示该通道不具有缓冲区,默认<code>size=0</code>。</p>
<h4 id="14-slice扩容">14 slice扩容</h4>
<p>源代码如下:可以看出当当前的容量小于扩容之后的容量的长度的时候,并且当前的长度小于1024,则扩容为当前的两倍,否则扩容四分之一大小。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">grow</span><span class="p">(</span><span class="nx">s</span> <span class="nx">Value</span><span class="p">,</span> <span class="nx">extra</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="nx">Value</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span> <span class="nx">i0</span> <span class="o">:=</span> <span class="nx">s</span><span class="p">.</span><span class="nf">Len</span><span class="p">()</span> <span class="nx">i1</span> <span class="o">:=</span> <span class="nx">i0</span> <span class="o">+</span> <span class="nx">extra</span> <span class="k">if</span> <span class="nx">i1</span> <span class="p">&lt;</span> <span class="nx">i0</span> <span class="p">{</span> <span class="nb">panic</span><span class="p">(</span><span class="s">&#34;reflect.Append: slice overflow&#34;</span><span class="p">)</span> <span class="p">}</span> <span class="nx">m</span> <span class="o">:=</span> <span class="nx">s</span><span class="p">.</span><span class="nf">Cap</span><span class="p">()</span> <span class="k">if</span> <span class="nx">i1</span> <span class="o">&lt;=</span> <span class="nx">m</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">s</span><span class="p">.</span><span class="nf">Slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">i1</span><span class="p">),</span> <span class="nx">i0</span><span class="p">,</span> <span class="nx">i1</span> <span class="p">}</span> <span class="k">if</span> <span class="nx">m</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span> <span class="nx">m</span> <span class="p">=</span> <span class="nx">extra</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">for</span> <span class="nx">m</span> <span class="p">&lt;</span> <span class="nx">i1</span> <span class="p">{</span> <span class="k">if</span> <span class="nx">i0</span> <span class="p">&lt;</span> <span class="mi">1024</span> <span class="p">{</span> <span class="nx">m</span> <span class="o">+=</span> <span class="nx">m</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="nx">m</span> <span class="o">+=</span> <span class="nx">m</span> <span class="o">/</span> <span class="mi">4</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="nx">t</span> <span class="o">:=</span> <span class="nf">MakeSlice</span><span class="p">(</span><span class="nx">s</span><span class="p">.</span><span class="nf">Type</span><span class="p">(),</span> <span class="nx">i1</span><span class="p">,</span> <span class="nx">m</span><span class="p">)</span> <span class="nf">Copy</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">s</span><span class="p">)</span> <span class="k">return</span> <span class="nx">t</span><span class="p">,</span> <span class="nx">i0</span><span class="p">,</span> <span class="nx">i1</span><span class="p">}</span>
</code></pre></td></tr></table>
</div>