-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
839 lines (757 loc) · 240 KB
/
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
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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title></title>
<url>/2023/04/09/C++%E8%B0%83%E7%94%A8Python3.7/</url>
<content><![CDATA[<p>@<a href="C++%E8%B0%83%E7%94%A8Python3.7">TOC</a></p>
<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近在做一个项目,涉及到了如何用C#调用Python文件。汇总了一下网上找来的资料,具体参考了这篇博客<a href="https://blog.csdn.net/qq_42063091/article/details/82418630">c#调用python的四种方法(尝试了四种,只详细讲解本人成功的后两种,其余方法只列出,详细用法请自行谷歌百度)</a>。<br>对于第一种方法,使用IronPython2.7的方法,我找到了更详细的博客<a href="https://blog.csdn.net/cw19901024/article/details/73526402">C#如何调用Python执行脚本,并将执行结果显示值显示至C#界面</a>,不过Python2.7可能无法满足我们项目的需求,当然我也找到了类似的另外两种可以使用Python3的方法,还没有试过,在这里提供给大家参考<a href="https://blog.csdn.net/Micusd/article/details/81605593">C#使用公共语言拓展(CLE)调用Python3(使用TensorFlow训练的模型)</a>、<a href="https://blog.csdn.net/weixin_42388228/article/details/89681870">pythonnet c#调用并集成python代码</a>。<br>对于第三和第四种方法,因为要使用命令行窗口,而且还要考虑不同用户的python安装情况如何,在项目实际使用时效果肯定是很不好的,所以在这里不做过多的介绍,原博主也给出了他自己的源代码,大家可以自己尝试一下。<br>重点说一下第二种方法。我在CSDN上找了好多博客,大家的方法都大同小异,可能真的是看人品吧,我试了好几次都失败了,最后在朋友的帮助下才成功……</p>
<h1 id="配置环境"><a href="#配置环境" class="headerlink" title="配置环境"></a>配置环境</h1><p>这里先说一下,我是win10+VS2017+Python3.7.4。</p>
<h2 id="第一步新建一个控制台项目,修改属性页"><a href="#第一步新建一个控制台项目,修改属性页" class="headerlink" title="第一步新建一个控制台项目,修改属性页"></a>第一步新建一个控制台项目,修改属性页</h2><p>选择Debug|x64<br><img src="https://img-blog.csdnimg.cn/2019081916113616.JPG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述">第一个修改的是C/C++——常规——附加包含目录:添加你所安装的Python目录下的include目录路径。<br><img src="https://img-blog.csdnimg.cn/201908191614311.JPG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述">第二个修改的是链接器——常规——附加库目录:添加你所安装的Python目录下的libs目录路径。</p>
<h2 id="第二步修改Python安装目录下文件"><a href="#第二步修改Python安装目录下文件" class="headerlink" title="第二步修改Python安装目录下文件"></a>第二步修改Python安装目录下文件</h2><p><img src="https://img-blog.csdnimg.cn/20190819161713384.JPG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>找到Python安装目录,找到libs目录复制python37.lib到本目录,改名为python37_d.lib。</p>
<h1 id="代码测试"><a href="#代码测试" class="headerlink" title="代码测试"></a>代码测试</h1><p>现在我们可以来简单测试一下</p>
<h2 id="测试用Python3语法输出“Hello-World!”"><a href="#测试用Python3语法输出“Hello-World!”" class="headerlink" title="测试用Python3语法输出“Hello World!”"></a>测试用Python3语法输出“Hello World!”</h2><p>我们定义一个print(),里面用了Python3的语法。</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"pch.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><Python.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"></span><br><span class="line">using namespace <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">print</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> Py_Initialize();</span><br><span class="line"> PyRun_SimpleString(<span class="string">"print('Hello World!')\n"</span>);<span class="comment">//Python3语法</span></span><br><span class="line"> Py_Finalize();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> print();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="测试用Python文件输出“Hello-World!”"><a href="#测试用Python文件输出“Hello-World!”" class="headerlink" title="测试用Python文件输出“Hello World!”"></a>测试用Python文件输出“Hello World!”</h2><p>定义一个Hello(),里面调用了Test001.py文件。</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"pch.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><Python.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"></span><br><span class="line">using namespace <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">print</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> Py_Initialize();</span><br><span class="line"> PyRun_SimpleString(<span class="string">"print('Hello Python!')\n"</span>);</span><br><span class="line"> Py_Finalize();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">Hello</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> Py_Initialize();<span class="comment">//调用Py_Initialize()进行初始化</span></span><br><span class="line"> PyObject * pModule = <span class="literal">NULL</span>;</span><br><span class="line"> PyObject * pFunc = <span class="literal">NULL</span>;</span><br><span class="line"> pModule = PyImport_ImportModule(<span class="string">"Test001"</span>);<span class="comment">//调用的Python文件名</span></span><br><span class="line"> pFunc = PyObject_GetAttrString(pModule, <span class="string">"Hello"</span>);<span class="comment">//调用的函数名</span></span><br><span class="line"> PyEval_CallObject(pFunc, <span class="literal">NULL</span>);<span class="comment">//调用函数,NULL表示参数为空</span></span><br><span class="line"> Py_Finalize();<span class="comment">//调用Py_Finalize,和Py_Initialize相对应的.</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> print();</span><br><span class="line"> Hello();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Test001.py文件内容如下:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">Hello</span>():</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"Hello World!"</span>)</span><br></pre></td></tr></table></figure>
<p>注意,要把Test001.py文件放到ConsoleApplication1.exe同级目录<br><img src="https://img-blog.csdnimg.cn/2019081916354339.JPG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20190819163559667.JPG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h1 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h1><p>如果一切顺利的话,那你现在已经在控制台看到输出了;如果不顺利的话,可以找找其他的博客,或者换一个方法,不要拘泥于这一个思路……<br>从今天开始,这个博客会把我之前做项目遇到的一些问题的解决办法总结一下,也算是一种积累吧,估计等我项目做完,会写成一本《扑街实录》。</p>
<h1 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h1><p><a href="https://blog.csdn.net/qq_42063091/article/details/82418630">c#调用python的四种方法(尝试了四种,只详细讲解本人成功的后两种,其余方法只列出,详细用法请自行谷歌百度)</a><br><a href="https://blog.csdn.net/cw19901024/article/details/73526402">C#如何调用Python执行脚本,并将执行结果显示值显示至C#界面</a><br><a href="https://blog.csdn.net/Micusd/article/details/81605593">C#使用公共语言拓展(CLE)调用Python3(使用TensorFlow训练的模型)</a><br><a href="https://blog.csdn.net/weixin_42388228/article/details/89681870">pythonnet c#调用并集成python代码</a></p>
]]></content>
</entry>
<entry>
<title>C++ vector基本操作</title>
<url>/2023/04/09/C++%20vector%E6%9F%A5%E6%94%B9%E5%A2%9E%E5%88%A0%E6%93%8D%E4%BD%9C/</url>
<content><![CDATA[<h1 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h1><p>在c++中,vector是一个类模板,当使用模板的时候,我们需要指出编译器应该把类和函数实例化成何种类型。</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line">vector<<span class="type">int</span>> ivec;<span class="comment">//vector的元素是int型数据</span></span><br><span class="line">vector<vector<string>> file;<span class="comment">//vector的元素还是是vector对象,这个vector对象的元素是string型数据</span></span><br></pre></td></tr></table></figure>
<span id="more"></span>
<h2 id="默认初始化"><a href="#默认初始化" class="headerlink" title="默认初始化"></a>默认初始化</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line">vector<T> v1;<span class="comment">//v1是一个空vector,它潜在的元素是T类型的,执行默认初始化</span></span><br></pre></td></tr></table></figure>
<h2 id="拷贝初始化"><a href="#拷贝初始化" class="headerlink" title="拷贝初始化"></a>拷贝初始化</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">//针对的是变量</span></span><br><span class="line"><span class="function">vector<T> <span class="title">v2</span><span class="params">(v1)</span></span>;<span class="comment">//v2中包含v1所有元素的副本</span></span><br><span class="line">vector<T> v2=v1;<span class="comment">//等价于v2(v1),v2中包含有v1所有元素的副本</span></span><br></pre></td></tr></table></figure>
<h2 id="列表初始化(花括号)"><a href="#列表初始化(花括号)" class="headerlink" title="列表初始化(花括号)"></a>列表初始化(花括号)</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">//针对的是变量的元素</span></span><br><span class="line">vector<T> v3{a,b,c...};<span class="comment">//v3包含了初始值个数的元素,每个元素被赋予相应的初始值</span></span><br><span class="line">vector<T> v3={a,b,c};<span class="comment">//等价于上一个</span></span><br></pre></td></tr></table></figure>
<h2 id="值初始化(小括号)"><a href="#值初始化(小括号)" class="headerlink" title="值初始化(小括号)"></a>值初始化(小括号)</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">//针对的是变量的元素数量</span></span><br><span class="line"><span class="comment">//输入的n应该是给构造函数的</span></span><br><span class="line"><span class="function">vector<T> <span class="title">v4</span><span class="params">(n,val)</span></span>;<span class="comment">//v5中包含着n个重复的,值为val的元素</span></span><br><span class="line"><span class="function">vector<T> <span class="title">v5</span><span class="params">(n)</span></span>;<span class="comment">//v5包含了n个重复的,默认值的元素</span></span><br></pre></td></tr></table></figure>
<p><strong>注意,使用花括号进行值初始化时,编译器也能理解</strong></p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line">vector<string> v6{<span class="string">"hi"</span>};<span class="comment">//列表初始化:v6有一个元素</span></span><br><span class="line"><span class="function">vector<string> <span class="title">v7</span><span class="params">(<span class="string">"hi"</span>)</span></span>;<span class="comment">//错误,不可以用元素值来构建vector对象</span></span><br><span class="line">vector<string> v8{<span class="number">10</span>};<span class="comment">//v8有10个默认初始化的元素</span></span><br><span class="line">vector<string> v9{<span class="number">10</span>,<span class="string">"hi"</span>};<span class="comment">//v9有10个值为hi的元素</span></span><br></pre></td></tr></table></figure>
<h1 id="查找元素"><a href="#查找元素" class="headerlink" title="查找元素"></a>查找元素</h1><p>我们可以通过遍历vector,返回所查找元素的下标。</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">findElement</span><span class="params">(vector<<span class="type">int</span>> v, <span class="type">int</span> key)</span></span>{</span><br><span class="line"> <span class="comment">// 获取vector的长度。</span></span><br><span class="line"> <span class="type">int</span> len = v.<span class="built_in">size</span>();</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i < len; i++){</span><br><span class="line"> <span class="keyword">if</span>(v[i] == key){</span><br><span class="line"> <span class="keyword">return</span> i;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="修改元素"><a href="#修改元素" class="headerlink" title="修改元素"></a>修改元素</h1><p>直接对应下标指向位置进行修改。</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line">v[<span class="number">1</span>] = v[<span class="number">0</span>];</span><br></pre></td></tr></table></figure>
<h1 id="增加元素"><a href="#增加元素" class="headerlink" title="增加元素"></a>增加元素</h1><p>在vector中增加元素包括两种,一种是在尾部增加元素,另一种是在指定位置增加元素。</p>
<h2 id="尾部增加"><a href="#尾部增加" class="headerlink" title="尾部增加"></a>尾部增加</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 使用push_back()函数</span></span><br><span class="line">vector<<span class="type">int</span>> v;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++)</span><br><span class="line">{</span><br><span class="line"> v.<span class="built_in">push_back</span>(i);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="指定位置增加"><a href="#指定位置增加" class="headerlink" title="指定位置增加"></a>指定位置增加</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 使用insert()函数</span></span><br><span class="line"><span class="comment">// 在v[2]位置插入10</span></span><br><span class="line">v.<span class="built_in">insert</span>(v.<span class="built_in">begin</span>() + <span class="number">2</span>, <span class="number">10</span>);</span><br></pre></td></tr></table></figure>
<h1 id="删除元素"><a href="#删除元素" class="headerlink" title="删除元素"></a>删除元素</h1><p>在vector中删除元素包括三种,第一种是删除尾部的元素,第二种是删除指定的元素,第三种是删除所有元素。</p>
<h2 id="尾部删除"><a href="#尾部删除" class="headerlink" title="尾部删除"></a>尾部删除</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 使用pop_back()函数</span></span><br><span class="line">v.<span class="built_in">pop_back</span>();</span><br></pre></td></tr></table></figure>
<h2 id="指定位置删除"><a href="#指定位置删除" class="headerlink" title="指定位置删除"></a>指定位置删除</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 使用erase()函数</span></span><br><span class="line"><span class="comment">// 删除开始位置的元素,并不会回收空间</span></span><br><span class="line">v.<span class="built_in">erase</span>(v.<span class="built_in">begin</span>());</span><br><span class="line"><span class="comment">// 删除区间[i,j-1]的元素</span></span><br><span class="line">v.<span class="built_in">erase</span>(v.<span class="built_in">begin</span>() + i, v.<span class="built_in">end</span>() - j);</span><br></pre></td></tr></table></figure>
<h2 id="删除所有元素"><a href="#删除所有元素" class="headerlink" title="删除所有元素"></a>删除所有元素</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 使用clear()函数</span></span><br><span class="line"><span class="comment">// 并不会回收空间,但v.size()变成0</span></span><br><span class="line">v.<span class="built_in">clear</span>();</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>计算机技术</category>
</categories>
</entry>
<entry>
<title></title>
<url>/2023/04/09/ILSVRC2012%E4%B8%8B%E8%BD%BD+%E8%AE%AD%E7%BB%83/</url>
<content><![CDATA[<p>@<a href="ILSVRC2012%E4%B8%8B%E8%BD%BD+%E8%AE%AD%E7%BB%83">TOC</a></p>
<h1 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h1><h2 id="官网下载"><a href="#官网下载" class="headerlink" title="官网下载"></a>官网下载</h2><p>直接在<a href="http://www.image-net.org/challenges/LSVRC/2012/downloads">ILSVRC2012</a>官网进行下载,需要注册账号登陆。<br><strong>训练集</strong><br>训练集下载地址:<a href="http://www.image-net.org/challenges/LSVRC/2012/dd31405981ef5f776aa17412e1f0c112/ILSVRC2012_img_train.tar">http://www.image-net.org/challenges/LSVRC/2012/dd31405981ef5f776aa17412e1f0c112/ILSVRC2012_img_train.tar</a><br><strong>验证集</strong><br>验证集下载地址:<a href="http://www.image-net.org/challenges/LSVRC/2012/dd31405981ef5f776aa17412e1f0c112/ILSVRC2012_img_val.tar">http://www.image-net.org/challenges/LSVRC/2012/dd31405981ef5f776aa17412e1f0c112/ILSVRC2012_img_val.tar</a></p>
<h2 id="迅雷下载"><a href="#迅雷下载" class="headerlink" title="迅雷下载"></a>迅雷下载</h2><p><strong>训练集</strong><br>训练集种子:<a href="http://academictorrents.com/download/a306397ccf9c2ead27155983c254227c0fd938e2.torrent">http://academictorrents.com/download/a306397ccf9c2ead27155983c254227c0fd938e2.torrent</a><br><strong>验证集</strong><br>验证集种子:<a href="http://academictorrents.com/download/5d6d0df7ed81efd49ca99ea4737e0ae5e3a5f2e5.torrent">http://academictorrents.com/download/5d6d0df7ed81efd49ca99ea4737e0ae5e3a5f2e5.torren</a></p>
<h2 id="使用aria2加速下载"><a href="#使用aria2加速下载" class="headerlink" title="使用aria2加速下载"></a>使用aria2加速下载</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">aria2c -x 16 -s 16 <span class="string">'http://academictorrents.com/download/5d6d0df7ed81efd49ca99ea4737e0ae5e3a5f2e5.torren'</span> <span class="string">'http://academictorrents.com/download/a306397ccf9c2ead27155983c254227c0fd938e2.torrent'</span></span><br></pre></td></tr></table></figure>
<h2 id="数据集校验"><a href="#数据集校验" class="headerlink" title="数据集校验"></a>数据集校验</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">md5sum</span> ILSVRC2012_img_val.tar ILSVRC2012_img_train.tar</span><br><span class="line">29b22e2961454d5413ddabcf34fc5622 ILSVRC2012_img_val.tar</span><br><span class="line">1d675b47d978889d74fa0da5fadfb00e ILSVRC2012_img_train.tar</span><br></pre></td></tr></table></figure>
<h1 id="训练"><a href="#训练" class="headerlink" title="训练"></a>训练</h1><h2 id="解压训练集"><a href="#解压训练集" class="headerlink" title="解压训练集"></a>解压训练集</h2><p>将ILSVRC2012_img_train.tar解压,1000个类别的*.tar包。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> train</span><br><span class="line">tar -xvf ILSVRC2012_img_train.tar -C train</span><br></pre></td></tr></table></figure>
<p>然后可以使用下面这段python代码,将训练集的1000个.tar包解压缩,并删除源.tar包。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> glob</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line">filelist = glob.glob(<span class="string">'./train/*.tar'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> f <span class="keyword">in</span> filelist:</span><br><span class="line"> os.system(<span class="string">"mkdir ./train/"</span> + f.split(<span class="string">'.'</span>)[<span class="number">0</span>])</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> f <span class="keyword">in</span> filelist:</span><br><span class="line"> os.system(<span class="string">"tar -xvf "</span> + f + <span class="string">" -C ./train/"</span> + f.split(<span class="string">'.'</span>)[<span class="number">0</span>])</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> f <span class="keyword">in</span> filelist:</span><br><span class="line"> os.system(<span class="string">"rm ./train/"</span> + f)</span><br></pre></td></tr></table></figure>
<h2 id="解压验证集"><a href="#解压验证集" class="headerlink" title="解压验证集"></a>解压验证集</h2><p>将ILSVRC2012_img_val.tar解压,得到没有种类标签的图片。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> val</span><br><span class="line">tar -xvf ILSVRC2012_img_val.tar -C val</span><br></pre></td></tr></table></figure>
<p>然后使用<a href="https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh">valprep.sh</a>文件,将验证集整理为和训练集相同的格式,按照种类标签划分文件夹。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> val</span><br><span class="line">aria2c -x 16 -s 16 ‘https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh’</span><br><span class="line">sh valprep.sh</span><br></pre></td></tr></table></figure>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/Jetson%20Nano%20&%20TX2%E9%85%8D%E7%BD%AE%E6%95%99%E7%A8%8B/</url>
<content><![CDATA[<p>@[TOC](Jetson Nano & TX2配置教程)<br>更新于2021年4月10日。本文介绍了Jetson Nano 和 Jetson TX2两种设备的配置教程,前一部分以Jetson Nano为例,后半部分以Jetson TX2为例。这两种设备的配置教程,大体上是相近的。</p>
<h1 id="Jetson-Nano-激活"><a href="#Jetson-Nano-激活" class="headerlink" title="Jetson Nano 激活"></a>Jetson Nano 激活</h1><p>首先,拿到一张64GB/128GB(12GB的卡不够用)的micro-SD card,并进行格式化。SD卡的格式化工具,直接从<a href="https://www.sdcard.org/chs/downloads/formatter/index.html">官网</a>下载即可,使用时选择“快速格式化”。</p>
<p>然后,从<a href="https://developer.nvidia.com/zh-cn/embedded/jetpack#install">Nvidia官网</a>下载你需要的jetson nano镜像。</p>
<p>注意确定安装的jetpack版本,这关系到其自带的cuda版本。简单来说,jetpack4.4以上,只能安装pytorch1.6以上<a href="https://forums.developer.nvidia.com/t/pytorch-for-jetson-version-1-8-0-now-available/72048">PyTorch for Jetson - version 1.8.0 now available</a>。而且在pytorch1.6环境下保存的模型,没办法在更低版本的pytorch中打开。</p>
<p>旧版本可以从官网<a href="https://developer.nvidia.com/embedded/jetpack-archive">JetPack Archive</a>寻找。<br>最后,根据<a href="https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit">Nvidia官网教程</a>完成镜像的烧录,大概需要半个小时的时间。</p>
<h1 id="Jetson-TX2-烧录"><a href="#Jetson-TX2-烧录" class="headerlink" title="Jetson TX2 烧录"></a>Jetson TX2 烧录</h1><p>这里给出两个链接,一个是官网链接<a href="https://docs.nvidia.com/sdk-manager/install-with-sdkm-jetson/index.html">使用SDK Manager安装Jetson软件</a>,另一个是知乎上的链接<a href="https://zhuanlan.zhihu.com/p/94071423">Jetson TX2 入门教程(镜像烧写)</a>。</p>
<h1 id="更新系统国内源"><a href="#更新系统国内源" class="headerlink" title="更新系统国内源"></a>更新系统国内源</h1><p>在使用系统之前,我们先将系统更换为国内安装源。<br>首先,备份source.list。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">sudo <span class="built_in">cp</span> /etc/apt/sources.list /etc/apt/sources.list.bak</span><br></pre></td></tr></table></figure>
<p>然后,修改source.list。推荐用gedit,十分方便。如果没有安装的话,需要先安装一下。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">sudo apt<span class="literal">-get</span> install gedit</span><br><span class="line">sudo gedit /etc/apt/sources.list</span><br></pre></td></tr></table></figure>
<p>接着,替换list中的内容。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu<span class="literal">-ports</span>/ bionic main multiverse restricted universe</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu<span class="literal">-ports</span>/ bionic<span class="literal">-security</span> main multiverse restricted universe</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu<span class="literal">-ports</span>/ bionic<span class="literal">-updates</span> main multiverse restricted universe</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu<span class="literal">-ports</span>/ bionic<span class="literal">-backports</span> main multiverse restricted universe</span><br><span class="line">deb<span class="literal">-src</span> http://mirrors.tuna.tsinghua.edu.cn/ubuntu<span class="literal">-ports</span>/ bionic main multiverse restricted universe</span><br><span class="line">deb<span class="literal">-src</span> http://mirrors.tuna.tsinghua.edu.cn/ubuntu<span class="literal">-ports</span>/ bionic<span class="literal">-security</span> main multiverse restricted universe</span><br><span class="line">deb<span class="literal">-src</span> http://mirrors.tuna.tsinghua.edu.cn/ubuntu<span class="literal">-ports</span>/ bionic<span class="literal">-updates</span> main multiverse restricted universe</span><br><span class="line">deb<span class="literal">-src</span> http://mirrors.tuna.tsinghua.edu.cn/ubuntu<span class="literal">-ports</span>/ bionic<span class="literal">-backports</span> main multiverse restricted universe</span><br></pre></td></tr></table></figure>
<p>最后,更新软件。update和upgrade的区别可以参考<a href="https://www.cnblogs.com/fenglongyu/p/8654991.html">linux命令系列 sudo apt-get update和upgrade的区别</a>。<br>这一步可能需要花一段时间。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">sudo apt<span class="literal">-get</span> update </span><br><span class="line">sudo apt<span class="literal">-get</span> upgrade </span><br></pre></td></tr></table></figure>
<h1 id="安装系统工具jtop"><a href="#安装系统工具jtop" class="headerlink" title="安装系统工具jtop"></a>安装系统工具jtop</h1><p>Jetson Nano中有个工具jtop, 可以查看CPU和GPU资源,还可以显示系统的jetpack版本,十分好用。<br>首先,安装pip3.</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">sudo apt<span class="literal">-get</span> install python3<span class="literal">-pip</span></span><br></pre></td></tr></table></figure>
<p>同样的,我们也可以将pip修改为国内源。<br>第一种方式,长期修改。我以阿里源为例,其他国内源只需要修改链接即可。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">pip3 config <span class="built_in">set</span> global.index-url https://mirrors.aliyun.com/pypi/simple/</span><br></pre></td></tr></table></figure>
<p>然后,使用pip安装jetson-stats。<br>第二种方式,一次性修改。我以清华源为例,其他国内源只需要修改链接即可。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">sudo pip3 install jetson<span class="literal">-stats</span> <span class="literal">-i</span> https://pypi.tuna.tsinghua.edu.cn/simple</span><br></pre></td></tr></table></figure>
<p>安装好之后,我们来看一下效果如何。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">sudo jtop</span><br></pre></td></tr></table></figure>
<h1 id="从源代码编译opencv"><a href="#从源代码编译opencv" class="headerlink" title="从源代码编译opencv"></a>从源代码编译opencv</h1><p>刷机后的Nano已经预装了opencv,但是预装版本不支持CUDA,所以我们还要在Jetson Nano上手动安装OpenCV。</p>
<p><strong>方法一</strong><br>安装已编译的opencv,简单方便,但是这个版本过低,且不能指定其他版本。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo apt-get install opencv-python</span><br></pre></td></tr></table></figure>
<p><strong>方法二</strong><br>从源代码安装,但是使用别人写好的脚本,如<a href="https://github.com/jetsonhacks/buildOpenCVXavier">buildOpenCVXavier</a>,<a href="https://github.com/mdegans/nano_build_opencv">nano_build_opencv</a>。但是报错之后,可能不知道自己为什么错了,因为脚本不是你自己写的。</p>
<p><strong>方法三</strong><br>自己从源代码编译安装,有很多坑要踩啊。<br>不能先安装archconda等虚拟环境管理包,否则会有问题!参考<a href="https://forums.developer.nvidia.com/t/install-opencv-for-python3-in-jetson-nano/74042">在Jetson Nano中为python3安装OpenCV</a></p>
<ol>
<li>增加交换空间</li>
</ol>
<p>opencv的编译时生成的中间文件很大,Jetson Nano原始空间放不下。这里介绍一种永久生效的方法。要是只想临时生效,可以参考<a href="https://qengineering.eu/install-opencv-4.5-on-jetson-nano.html">Enlarge memory swap</a>。</p>
<p>查看当前系统的交换空间。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo swapon --show</span><br></pre></td></tr></table></figure>
<p>查看内存大小。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">free -h</span><br></pre></td></tr></table></figure>
<p>创建用于swap的文件。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo fallocate -l 2G /swapfile</span><br></pre></td></tr></table></figure>
<p>设置交换空间。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo mkswap /swapfile</span><br></pre></td></tr></table></figure>
<p>激活交换空间。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo swapon /swapfile</span><br><span class="line"><span class="comment">#为了使这个激活永久有效</span></span><br><span class="line">sudo gedit /etc/fstab</span><br><span class="line"><span class="comment">#粘贴 /swapfile swap swap defaults 0 0</span></span><br></pre></td></tr></table></figure>
<p>验证增加空间是否有效。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo swapon --show</span><br><span class="line">sudo free -h</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>安装依赖项<br> 这个依赖项的要求五花八门,取决于你对功能的要求,这里我只给出我使用的依赖项,参考<a href="https://pythops.com/post/compile-deeplearning-libraries-for-jetson-nano">compile deeplearning libraries for jetson nano</a>。如果遇到包冲突问题,参考<a href="https://www.cnblogs.com/klcf0220/p/10242810.html">aptitude与apt-get</a>解决。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">dependencies=(build-essential</span><br><span class="line"> cmake</span><br><span class="line"> pkg-config</span><br><span class="line"> libavcodec-dev</span><br><span class="line"> libavformat-dev</span><br><span class="line"> libopenblas-base</span><br><span class="line"> libopenmpi-dev</span><br><span class="line"> libswscale-dev</span><br><span class="line"> libv4l-dev</span><br><span class="line"> libxvidcore-dev</span><br><span class="line"> libavresample-dev</span><br><span class="line"> python3-dev</span><br><span class="line"> python3-numpy</span><br><span class="line"> libtbb2</span><br><span class="line"> libtbb-dev</span><br><span class="line"> libtiff-dev</span><br><span class="line"> libjpeg-dev</span><br><span class="line"> libpng-dev</span><br><span class="line"> libtiff-dev</span><br><span class="line"> libdc1394-22-dev</span><br><span class="line"> libgtk-3-dev</span><br><span class="line"> libcanberra-gtk3-module</span><br><span class="line"> libatlas-base-dev</span><br><span class="line"> gfortran</span><br><span class="line"> wget</span><br><span class="line"> unzip)</span><br><span class="line"></span><br><span class="line">sudo apt install -y <span class="variable">${dependencies[@]}</span></span><br></pre></td></tr></table></figure>
<ol start="3">
<li>下载源代码<br>安装所有第三方依赖项后,我们就需要下载OpenCV啦。需要两个压缩包:基本库和其他拓展库。在<a href="https://opencv.org/releases/">opencv官网</a>下载你需要的版本。这里以4.4.0版本为例。</li>
</ol>
<p>在github网址下载opencv-4.4.0.zip,复制下面的网址,在浏览器直接下载。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">https://github.com/opencv/opencv/archive/4.4.0.zip</span><br></pre></td></tr></table></figure>
<p>在github网址下载opencv_contrib-4.4.0.zip,复制下面的网址,在浏览器直接下载。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">https://github.com/opencv/opencv_contrib/archive/4.4.0.zip</span><br></pre></td></tr></table></figure>
<p>对下载后的opencv-4.4.0.zip和opencv_contrib-4.4.0.zip进行解压缩。<br>在opencv-4.4.0文件夹下打开命令行,新建一个build文件夹,并切换到build文件夹下。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> build</span><br><span class="line"><span class="built_in">cd</span> build</span><br></pre></td></tr></table></figure>
<ol start="4">
<li>编写cmake配置文件my_cmake.sh<br>这里是对opencv和cuda做的一些配置,和依赖库一样也是五花八门,看你的需求吧。这里我给出自己的配置,仅供参考。</li>
</ol>
<p>新建脚本文件。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">gedit my_cmake.sh</span><br></pre></td></tr></table></figure>
<p>粘贴cmake命令。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">cmake -D CMAKE_BUILD_TYPE=RELEASE \</span><br><span class="line"> -D WITH_CUDA=ON \</span><br><span class="line"> -D CUDA_ARCH_PTX=<span class="string">""</span> \</span><br><span class="line"> -D CUDA_ARCH_BIN=<span class="string">"5.3,6.2,7.2"</span> \</span><br><span class="line"> -D WITH_CUBLAS=ON \</span><br><span class="line"> -D WITH_LIBV4L=ON \</span><br><span class="line"> -D BUILD_opencv_python3=ON \</span><br><span class="line"> -D BUILD_opencv_python2=OFF \</span><br><span class="line"> -D BUILD_opencv_java=OFF \</span><br><span class="line"> -D WITH_GSTREAMER=OFF \</span><br><span class="line"> -D WITH_GTK=ON \</span><br><span class="line"> -D BUILD_TESTS=OFF \</span><br><span class="line"> -D BUILD_PERF_TESTS=OFF \</span><br><span class="line"> -D BUILD_EXAMPLES=OFF \</span><br><span class="line"> -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.4.0/modules \</span><br><span class="line"> ..</span><br></pre></td></tr></table></figure>
<p>具体每个选项的介绍,可以参考<a href="https://blog.csdn.net/weixin_40784980/article/details/105246509">Jetson Nano 从头配置OpenCV+CUDA+QT完整流程</a>。</p>
<p>执行make命令。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sh ./my_cmake.sh</span><br></pre></td></tr></table></figure>
<p>在我们进入实际编译步骤之前,请确保检查CMake的输出!参考<a href="https://blog.csdn.net/qq_27971677/article/details/90400118">树莓派安装OpenCV-4.1.0及Contrib</a></p>
<ol start="5">
<li>开始构建<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ make -j4</span><br></pre></td></tr></table></figure>
-j4表示4个CPU核心同时运行。<br>查看CPU核心数,参考<a href="https://www.cnblogs.com/chenzhen0530/p/12109868.html">Ubuntu 18.04配置OpenCV 4.2.0</a>。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">nproc</span></span><br></pre></td></tr></table></figure>
<p>经过漫长的等待,约两小时。<br>可能遇到错误,这是网络问题导致部分依赖包没有下载。<br><strong>错误一</strong><br>参考<a href="https://blog.csdn.net/weixin_40784980/article/details/105246509">Jetson Nano 从头配置OpenCV+CUDA+QT完整流程</a>中相关部分的解决方案。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">fatal error: boostdesc_bgm.i: No such file or directory</span><br></pre></td></tr></table></figure>
<p><strong>错误二</strong></p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">fatal error: opencv2/xfeatures2d/cuda.hpp: No such file or directory</span><br></pre></td></tr></table></figure>
<p>参考<a href="https://blog.csdn.net/hongge_smile/article/details/104372783?utm_medium=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-2.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-2.nonecase">opencv安装opencv_contrib出现无法打开包括文件: “opencv2/xfeatures2d/cuda.hpp”</a>中的解决方案。记得加在最开始,不要加在最后面!</p>
<p><strong>错误三</strong></p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">CMakeFiles/example_gpu_surf_keypoint_matcher.dir/surf_keypoint_matcher.cpp.o: In <span class="keyword">function</span> `main<span class="string">':</span></span><br><span class="line"><span class="string">surf_keypoint_matcher.cpp:(.text.startup.main+0x352): undefined reference to `cv::cuda::SURF_CUDA::SURF_CUDA()'</span></span><br><span class="line">surf_keypoint_matcher.cpp:(.text.startup.main+0x579): undefined reference to `cv::cuda::SURF_CUDA::operator()(cv::cuda::GpuMat const&, cv::cuda::GpuMat const&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, bool)<span class="string">'</span></span><br><span class="line"><span class="string">surf_keypoint_matcher.cpp:(.text.startup.main+0x60d): undefined reference to `cv::cuda::SURF_CUDA::operator()(cv::cuda::GpuMat const&, cv::cuda::GpuMat const&, cv::cuda::GpuMat&, cv::cuda::GpuMat&, bool)'</span></span><br><span class="line">surf_keypoint_matcher.cpp:(.text.startup.main+0x6af): undefined reference to `cv::cuda::SURF_CUDA::defaultNorm() const<span class="string">'</span></span><br><span class="line"><span class="string">surf_keypoint_matcher.cpp:(.text.startup.main+0x7ca): undefined reference to `cv::cuda::SURF_CUDA::downloadKeypoints(cv::cuda::GpuMat const&, std::vector<cv::KeyPoint, std::allocator<cv::KeyPoint> >&)'</span></span><br><span class="line">surf_keypoint_matcher.cpp:(.text.startup.main+0x7ea): undefined reference to `cv::cuda::SURF_CUDA::downloadKeypoints(cv::cuda::GpuMat const&, std::vector<cv::KeyPoint, std::allocator<cv::KeyPoint> >&)<span class="string">'</span></span><br><span class="line"><span class="string">surf_keypoint_matcher.cpp:(.text.startup.main+0x800): undefined reference to `cv::cuda::SURF_CUDA::downloadDescriptors(cv::cuda::GpuMat const&, std::vector<float, std::allocator<float> >&)'</span></span><br><span class="line">surf_keypoint_matcher.cpp:(.text.startup.main+0x812): undefined reference to `cv::cuda::SURF_CUDA::downloadDescriptors(cv::cuda::GpuMat const&, std::vector<<span class="built_in">float</span>, std::allocator<<span class="built_in">float</span>> >&)<span class="string">'</span></span><br><span class="line"><span class="string">collect2: error: ld returned 1 exit status</span></span><br><span class="line"><span class="string">samples/gpu/CMakeFiles/example_gpu_surf_keypoint_matcher.dir/build.make:132: recipe for target '</span>bin/example_gpu_surf_keypoint_matcher<span class="string">' failed</span></span><br><span class="line"><span class="string">make[2]: *** [bin/example_gpu_surf_keypoint_matcher] Error 1</span></span><br></pre></td></tr></table></figure>
<p>参考<a href="https://blog.csdn.net/GungnirsPledge/article/details/108597474#5CMakeFilesexample_gpu_surf_keypoint_matcherdirsurf_keypoint_matchercppo_In_function_main_252">源码编译安装OpenCV4.5+ CUDA11 带python 遇到的错误总结</a>中的解决方案。</p>
<ol start="6">
<li>安装</li>
</ol>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">make install</span><br></pre></td></tr></table></figure>
<ol start="7">
<li>验证</li>
</ol>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 -c <span class="string">"import cv2; print(cv2.__version__)"</span></span><br><span class="line">4.4.0</span><br></pre></td></tr></table></figure>
<h1 id="安装archconda"><a href="#安装archconda" class="headerlink" title="安装archconda"></a>安装archconda</h1><p>anaconda是深度学习的好工具。在arm64框架平台上,对应有一个archconda,是大神编译好的工具,我们可以直接使用。<br>从大神<a href="https://github.com/Archiconda/build-tools/releases">github网址</a>上下载sh文件,然后就像在普通linux上安装即可。</p>
<p>如果需要在虚拟环境中使用opencv,有两种方法。<br><strong>方法一</strong><br>链接,参考<a href="https://www.bojankomazec.com/2019/12/installing-opencv-4-on-nvidia-jetson.html">Installing OpenCV 4 on NVIDIA Jetson Nano</a>。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Go to the folder where OpenCV's native library is built</span></span><br><span class="line"><span class="built_in">cd</span> /usr/local/lib/python3.6/site-packages/cv2/python-3.6</span><br><span class="line"><span class="comment"># Rename</span></span><br><span class="line"><span class="built_in">mv</span> cv2.cpython-36m-xxx-linux-gnu.so cv2.so</span><br><span class="line"><span class="comment"># Go to your virtual environments site-packages folder if previously set</span></span><br><span class="line"><span class="built_in">cd</span> ~/env/lib/python3.6/site-packages/</span><br><span class="line"><span class="comment"># Or just go to your home folder if not set a venv site-packages folder</span></span><br><span class="line"><span class="built_in">cd</span> ~</span><br><span class="line"><span class="comment"># Symlink the native library</span></span><br><span class="line"><span class="built_in">ln</span> -s /usr/local/lib/python3.6/site-packages/cv2/python-3.6/cv2.so cv2.so</span><br></pre></td></tr></table></figure>
<p><strong>方法二</strong><br>拷贝,参考<a href="https://github.com/mdegans/nano_build_opencv/issues/32">How to check for successful install including in virtualenv. #32</a>。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Go to the folder where OpenCV's native library is built</span></span><br><span class="line"><span class="built_in">cd</span> /usr/local/lib/python3.6/site-packages/cv2/python-3.6</span><br><span class="line"><span class="comment"># copy</span></span><br><span class="line"><span class="built_in">cp</span> usr/local/lib/python3.6/site-packages/cv2/python-3.6 [path to venv]/lib/python3.6/site-packages/cv2/python-3.6</span><br></pre></td></tr></table></figure>
<p>在虚拟环境中导入cv2,可能会遇到下面一个错误。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">from .cv2 import *</span><br><span class="line">ImportError: numpy.core.multiarray failed to import</span><br></pre></td></tr></table></figure>
<p>这主要是在编译opencv的时候使用的numpy,和虚拟环境中安装的numpy版本不一致,根据安装时的numpy版本修改一下即可,参考<a href="https://zhuanlan.zhihu.com/p/280702247">cv2: numpy.core.multiarray failed to import</a>。<br>查看编译opencv的时候使用的numpy版本,可以进入系统自带的python环境,输出numpy版本号。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">>>> import numpy</span><br><span class="line">>>> <span class="built_in">print</span>(numpy.__version__)</span><br></pre></td></tr></table></figure>
<p>还有可能遇到另一个问题。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">>>> import numpy</span><br><span class="line">>>> Illegal instruction (core dumped)</span><br></pre></td></tr></table></figure>
<p>这是numpy版本的问题,将numpy=1.19.5降级到numpy=1.19.4或更低版本即可,参考<a href="https://forums.developer.nvidia.com/t/illegal-instruction-core-dumped/165488">Illegal instruction (core dumped)</a></p>
<h1 id="安装mmdetection"><a href="#安装mmdetection" class="headerlink" title="安装mmdetection"></a>安装mmdetection</h1><p>这一部分使用的是Jetson TX2,参考<a href="https://blog.csdn.net/qq_24282081/article/details/107285072#STEP1%20%E5%AE%89%E8%A3%85pytorch%C2%A0">在Jetson tx2安装 mmdetection环境</a>。</p>
<p>这里我遇到了一个小问题,TX2接上网线但是连不上网,解决方法参考<a href="https://blog.csdn.net/tao_fuqiang/article/details/79741317">Jetson TX2 有线网络网线不识别,灯不亮问题</a>。</p>
<p>其实,安装完opencv后,要运行mmdetection的代码,还有4个重要的包需要安装:torch,torchvision,mmcv-full,mmdet。</p>
<ol>
<li>安装torch</li>
</ol>
<p>去NVIDIA官网下载配套的版本<a href="https://forums.developer.nvidia.com/t/pytorch-for-jetson-version-1-7-0-now-available/72048">PyTorch for Jetson - version 1.7.0 now available</a>,这一步需要翻墙。<br>注意查看自己的Jetpack版本号,4.4要用torch1.6,否则会报错cudnn版本不合适。<br>查看Jetson设备的信息可以用之前提到的jtop,也可以使用<a href="http://www.gpus.cn/gpus_list_page_techno_support_content?id=39">查询Jetson设备与开发环境版本的基础信息</a>。<br>下载好pytorch之后,激活虚拟环境,使用pip命令安装。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">pip install torch-1.6.0-cp36-cp36m-linux_aarch64.whl</span><br></pre></td></tr></table></figure>
<p>有可能遇到问题</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">OSError: libmpi_cxx.so<span class="number">.20</span>: cannot <span class="built_in">open</span> shared <span class="built_in">object</span> file: No such file <span class="keyword">or</span> directory</span><br></pre></td></tr></table></figure>
<p>参考<a href="https://forums.developer.nvidia.com/t/cannot-install-pytorch/149226">Cannot install pytorch</a>,安装两个依赖。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo apt-get install libopenblas-base libopenmpi-dev </span><br></pre></td></tr></table></figure>
<ol start="2">
<li>安装torchvision</li>
</ol>
<p>需要根据torch版本来选择对应版本的torchvision进行安装,参考<a href="https://www.jianshu.com/p/afc502b5a67d">Jetson Nano 安装torch和torchvision</a>。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">git <span class="built_in">clone</span> --branch v0.7.0 https://github.com/pytorch/vision torchvision</span><br><span class="line"><span class="built_in">cd</span> torchvision</span><br><span class="line"><span class="built_in">export</span> BUILD_VERSION=0.7.0</span><br><span class="line">sudo python setup.py install</span><br></pre></td></tr></table></figure>
<ol start="3">
<li>安装mmcv-full和mmdet</li>
</ol>
<p>这里的教程跟<a href="https://github.com/open-mmlab/mmdetection/blob/master/docs/get_started.md">mmdetection官方教程</a>来走就好了。</p>
<p>安装mmcv-full</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/open-mmlab/mmcv.git</span><br><span class="line"><span class="built_in">cd</span> mmcv</span><br><span class="line">MMCV_WITH_OPS=1 pip install -e . <span class="comment"># 安装full版本</span></span><br></pre></td></tr></table></figure>
<p>安装mmdetection</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/open-mmlab/mmdetection.git</span><br><span class="line"><span class="built_in">cd</span> mmdetection</span><br><span class="line">pip install -r requirements/build.txt</span><br><span class="line">pip install -v -e .</span><br></pre></td></tr></table></figure>
<p><strong>注意</strong>:</p>
<ul>
<li>mmcv-full和mmdet的版本号要对应,官方教程已经给出来了对应关系。</li>
<li>安装mmcv-full,而不是mmcv,否则后面可能会有奇怪的错误。</li>
</ul>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">MMCV_WITH_OPS=1 pip install -e . -i https://pypi.tuna.tsinghua.edu.cn/simple</span><br></pre></td></tr></table></figure>
<ul>
<li>在使用pip命令时,后面跟上国内源,这样下载其他依赖包会更快一些。</li>
<li>上面两个包安装完,也要花挺长时间的。</li>
<li>有可能遇到安装matplotlib,scipy,pillow等包的时候,与已经安装的numpy版本冲突。这种情况下不能修改numpy的版本,要修改其他包的版本。</li>
<li>可以使用下面这条命令,查看哪个版本的包时候你的numpy,包和版本号可以更改,参考<a href="https://www.cnblogs.com/DLarTisan/p/11749043.html">conda查看某个安装包的依赖项</a>。</li>
</ul>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">conda search scipy=1.0.0 -info</span><br></pre></td></tr></table></figure>
<ol start="4">
<li>测试</li>
</ol>
<p>按照官网的代码,做了一些修改。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> mmdet.apis <span class="keyword">import</span> inference_detector, init_detector, show_result_pyplot</span><br><span class="line"></span><br><span class="line">config_file = <span class="string">'configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'</span></span><br><span class="line"><span class="comment"># download the checkpoint from model zoo and put it in `checkpoints/`</span></span><br><span class="line"><span class="comment"># url: http://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth</span></span><br><span class="line">checkpoint_file = <span class="string">'checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'</span></span><br><span class="line">device = <span class="string">'cuda:0'</span></span><br><span class="line"><span class="comment"># init a detector</span></span><br><span class="line">model = init_detector(config_file, checkpoint_file, device=device)</span><br><span class="line"><span class="comment"># inference the demo image</span></span><br><span class="line">result = inference_detector(model, <span class="string">'demo/demo.jpg'</span>)</span><br><span class="line"><span class="comment"># show the results</span></span><br><span class="line">show_result_pyplot(model, <span class="string">'demo/demo.jpg'</span>, result, score_thr=<span class="number">0.3</span>)</span><br></pre></td></tr></table></figure>
<p><strong>参考</strong><br><a href="https://blog.csdn.net/u011119817/article/details/99679350">【Jetson-Nano】jetson_nano安装环境配置及tensorflow和pytorch安装教程</a><br><a href="https://www.jianshu.com/p/6dbf979533ca">Jetson Nano配置与使用(1)开机</a><br><a href="https://zhuanlan.zhihu.com/p/64868319">在Jetson Nano (TX1/TX2)上使用Anaconda与PyTorch 1.1.0</a><br><a href="https://qengineering.eu/install-opencv-4.5-on-jetson-nano.html">Install OpenCV 4.5.0 on Jetson Nano</a><br><a href="https://pythops.com/post/compile-deeplearning-libraries-for-jetson-nano">compile deeplearning libraries for jetson nano</a><br><a href="https://www.cnblogs.com/fenglongyu/p/8654991.html">linux命令系列 sudo apt-get update和upgrade的区别</a><a href="https://github.com/jetsonhacks/buildOpenCVXavier">buildOpenCVXavier</a><br><a href="https://github.com/mdegans/nano_build_opencv">nano_build_opencv</a><br><a href="https://forums.developer.nvidia.com/t/install-opencv-for-python3-in-jetson-nano/74042">在Jetson Nano中为python3安装OpenCV</a><br><a href="https://www.bojankomazec.com/2019/12/installing-opencv-4-on-nvidia-jetson.html">Installing OpenCV 4 on NVIDIA Jetson Nano</a><br><a href="https://blog.csdn.net/weixin_40784980/article/details/105246509">Jetson Nano 从头配置OpenCV+CUDA+QT完整流程</a><br><a href="https://blog.csdn.net/qq_27971677/article/details/90400118">树莓派安装OpenCV-4.1.0及Contrib</a><br><a href="https://www.cnblogs.com/chenzhen0530/p/12109868.html">Ubuntu 18.04配置OpenCV 4.2.0</a><br><a href="https://blog.csdn.net/hongge_smile/article/details/104372783?utm_medium=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-2.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-2.nonecase">opencv安装opencv_contrib出现无法打开包括文件: “opencv2/xfeatures2d/cuda.hpp”</a><br><a href="https://blog.csdn.net/GungnirsPledge/article/details/108597474#5CMakeFilesexample_gpu_surf_keypoint_matcherdirsurf_keypoint_matchercppo_In_function_main_252">源码编译安装OpenCV4.5+ CUDA11 带python 遇到的错误总结</a><br><a href="https://zhuanlan.zhihu.com/p/280702247">cv2: numpy.core.multiarray failed to import</a><br><a href="https://blog.csdn.net/qq_24282081/article/details/107285072#STEP1%20%E5%AE%89%E8%A3%85pytorch%C2%A0">在Jetson tx2安装 mmdetection环境</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE2/</url>
<content><![CDATA[<p>@<a href="LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE2">TOC</a></p>
<p>接上文<a href="https://blog.csdn.net/qq_41214610/article/details/105508002">LeetCode算法题解——二分查找1</a>,本篇总结LeetCode中部分题目的二分查找解法。</p>
<h1 id="第四题(寻找左边界)"><a href="#第四题(寻找左边界)" class="headerlink" title="第四题(寻找左边界)"></a>第四题(寻找左边界)</h1><p><a href="https://leetcode.cn/problems/first-bad-version/">278. 第一个错误的版本</a></p>
<p>题目描述:<br>你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。</p>
<p>假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。</p>
<p>你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:n = 5, bad = 4</span><br><span class="line">输出:4</span><br><span class="line">解释:</span><br><span class="line">调用 isBadVersion(3) -> false </span><br><span class="line">调用 isBadVersion(5) -> true </span><br><span class="line">调用 isBadVersion(4) -> true</span><br><span class="line">所以,4 是第一个错误的版本。</span><br></pre></td></tr></table></figure>
<h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>如果将n个版本的true和false放到一个数组里,应该是[false, false, …, true, true],前面都是false,后面都是true。这道题可以看作是找到最后一个false,也可以看作是找到第一个true。在这里,我将它当作找到第一个true来做,也就是寻找true的左边界。</p>
<h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Solution</span> <span class="keyword">extends</span> <span class="title class_">VersionControl</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">firstBadVersion</span><span class="params">(<span class="type">int</span> n)</span> {</span><br><span class="line"> <span class="comment">// 左闭右闭</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> n;</span><br><span class="line"> <span class="comment">// 寻找true的左边界</span></span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="comment">// 能找到,缩小右边界</span></span><br><span class="line"> <span class="keyword">if</span>(isBadVersion(m) == <span class="literal">true</span>){</span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 找不到,缩小左边界</span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(isBadVersion(m) == <span class="literal">false</span>){</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> l;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">firstBadVersion</span>(<span class="params">self, n: <span class="built_in">int</span></span>) -> <span class="built_in">int</span>:</span><br><span class="line"> l, r = <span class="number">1</span>, n</span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> isBadVersion(m):</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> l</span><br></pre></td></tr></table></figure>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>在寻找左边界的时候,和之前中点值找到target一样,找到就收缩右边界。拓展一下,在寻找左/右边界,找到了target,但还没有到达其边界,应该向你要搜索的边界靠近,进一步压缩搜索空间。</p>
<h1 id="第五题(寻找右边界)"><a href="#第五题(寻找右边界)" class="headerlink" title="第五题(寻找右边界)"></a>第五题(寻找右边界)</h1><p><a href="https://leetcode.cn/problems/find-smallest-letter-greater-than-target/">744. 寻找比目标字母大的最小字母</a></p>
<p>题目描述:<br>给你一个字符数组 letters,该数组按非递减顺序排序,以及一个字符 target。letters 里至少有两个不同的字符。</p>
<p>返回 letters 中大于 target 的最小的字符。如果不存在这样的字符,则返回 letters 的第一个字符。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入: letters = ["c", "f", "j"],target = "a"</span><br><span class="line">输出: "c"</span><br><span class="line">解释:letters 中字典上比 'a' 大的最小字符是 'c'。</span><br></pre></td></tr></table></figure>
<h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><p>按照题意,寻找第一个比target大的字母。在前面寻找右边界时我们已经提到,当循环停止时右边界r以右的元素都大于target,则右边界r以左的元素都小于等于target,右边界r即最后一个target。所以,第一个比target大的字母就是r+1处的字母。但是当target比数组中所有数字都要大的时候,r+1会越界,这里需要做特别处理。</p>
<h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">char</span> <span class="title function_">nextGreatestLetter</span><span class="params">(<span class="type">char</span>[] letters, <span class="type">char</span> target)</span> {</span><br><span class="line"> <span class="comment">// 左闭右闭</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> letters.length - <span class="number">1</span>;</span><br><span class="line"> <span class="comment">// 寻找右边界</span></span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l) / <span class="number">2</span> ;</span><br><span class="line"> <span class="comment">// 收缩左边界</span></span><br><span class="line"> <span class="keyword">if</span>(target >= letters[m]){</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 收缩右边界</span></span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 防止越界,当不存在这样的字符,即target最大</span></span><br><span class="line"> <span class="keyword">if</span>(r == letters.length - <span class="number">1</span>){</span><br><span class="line"> <span class="keyword">return</span> letters[<span class="number">0</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> letters[r + <span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">nextGreatestLetter</span>(<span class="params">self, letters: <span class="type">List</span>[<span class="built_in">str</span>], target: <span class="built_in">str</span></span>) -> <span class="built_in">str</span>:</span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">len</span>(letters) - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> target >= letters[m]:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> letters[(r + <span class="number">1</span>) % <span class="built_in">len</span>(letters)]</span><br></pre></td></tr></table></figure>
<h3 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h3><p>这道题,需要将大于 target 的最小的字符理解成第一个比target大的字符,并且知道可以通过寻找target的右边界来求解。</p>
<h1 id="第六题(找一个数)"><a href="#第六题(找一个数)" class="headerlink" title="第六题(找一个数)"></a>第六题(找一个数)</h1><p><a href="https://leetcode.cn/problems/valid-perfect-square/">367. 有效的完全平方数</a></p>
<p>题目描述:<br>给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。</p>
<p>完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。</p>
<p>不能使用任何内置的库函数,如 sqrt 。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:num = 16</span><br><span class="line">输出:true</span><br><span class="line">解释:返回 true ,因为 4 * 4 = 16 且 4 是一个整数。</span><br></pre></td></tr></table></figure>
<h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><p>首先思考一种暴力算法。以num=16为例,我们先从1开始穷举。1*1=1,1<16,不满足。2*2=4,4<16,不满足。3*3=9,9<16,不满足。4*4=16,16==16,满足!5*5=25,25>16,不满足。显然,比4小的数和比4大的数,都不满足,我们可以通过二分法筛选掉比4小的数和比4大的数。</p>
<p>值得注意的是,如果直接比较x*x和num,可能x*x会超过int的范围。可以转化为比较x和num/x。如果是这样的话,考虑到整数除法结果仍然为整数,当x=num/x时,num可能是x*x,x*x+1,…,x*x+(x-1)。此时只需要再次比较x*x和num,即可。</p>
<h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isPerfectSquare</span><span class="params">(<span class="type">int</span> num)</span> {</span><br><span class="line"> <span class="comment">// 左闭右闭</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> num;</span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">sqrt</span> <span class="operator">=</span> num / m;</span><br><span class="line"> <span class="comment">// 找到target并进行判断</span></span><br><span class="line"> <span class="keyword">if</span>((m == sqrt) && (m * sqrt == num)){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(m < sqrt){</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">isPerfectSquare</span>(<span class="params">self, num: <span class="built_in">int</span></span>) -> <span class="built_in">bool</span>: </span><br><span class="line"> l, r = <span class="number">1</span>, num</span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> sqrt = num // m</span><br><span class="line"> <span class="keyword">if</span> sqrt < m:</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> r * r == num</span><br></pre></td></tr></table></figure>
<h3 id="总结-2"><a href="#总结-2" class="headerlink" title="总结"></a>总结</h3><p>这道题,我们可以先思考一个穷举的办法,然后考虑可以用二分法进行优化。防止溢出是一个需要注意的点。这道题里,m是中点,sqrt是target。和以前不同,这道题的target是会变的。</p>
<h1 id="第七题(找右边界)"><a href="#第七题(找右边界)" class="headerlink" title="第七题(找右边界)"></a>第七题(找右边界)</h1><p><a href="https://leetcode.cn/problems/sqrtx/">69. x 的平方根 </a></p>
<p>题目描述:<br>给你一个非负整数 x ,计算并返回 x 的 算术平方根 。</p>
<p>由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。</p>
<p>注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:x = 8</span><br><span class="line">输出:2</span><br><span class="line">解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。</span><br></pre></td></tr></table></figure>
<h3 id="思路-3"><a href="#思路-3" class="headerlink" title="思路"></a>思路</h3><p>这题和上一题不同。在上一题中,完全平方数,如16,一定能找到整数4*4=16。但是在这题里,将平方根的小数部分舍去了,那么就不能通过x*x=num来进行判断。同样的,我们先思考一种暴力算法。以num=8为例,我们先从1开始穷举。1*1=1,1<8;2*2=4,4<8;3*3=9,9>8。显然,前面的平方数都比8小,后面的平方数都比8大,我们需要找到最后一个比8小的平方数。问题转化为了找比8小的平方数的右边界。</p>
<p>和上一题一样,如果直接比较x*x和num,可能x*x会超过int的范围,可以转化为比较x和num/x。</p>
<h3 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">mySqrt</span><span class="params">(<span class="type">int</span> x)</span> {</span><br><span class="line"> <span class="keyword">if</span>(x <= <span class="number">1</span>){</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 左闭右闭</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> x;</span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">sqrt</span> <span class="operator">=</span> x / m;</span><br><span class="line"> <span class="keyword">if</span>(m > sqrt){</span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> r;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">mySqrt</span>(<span class="params">self, x: <span class="built_in">int</span></span>) -> <span class="built_in">int</span>:</span><br><span class="line"> <span class="keyword">if</span> x == <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> x</span><br><span class="line"></span><br><span class="line"> l, r = <span class="number">1</span>, x</span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> sqrt = x // m</span><br><span class="line"> <span class="keyword">if</span> sqrt < m:</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> r</span><br></pre></td></tr></table></figure>
<h3 id="总结-3"><a href="#总结-3" class="headerlink" title="总结"></a>总结</h3><p>同样的,这道题我们先思考一个穷举的办法,然后考虑可以用二分法进行优化。防止溢出依旧是一个需要注意的点。这道题里,m是中点,sqrt是target,会发生改变。</p>
<p>下一篇博客<a href="https://blog.csdn.net/qq_41214610/article/details/128875429">LeetCode算法题解——二分查找3</a>中,我将分享LeetCode中几道比较难想到使用二分查找解法的题目。</p>
<p>参考:</p>
<p><a href="https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/er-fen-cha-zhao-suan-fa-xi-jie-xiang-jie-by-labula/">二分查找算法细节详解,顺便写了首诗</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE3/</url>
<content><![CDATA[<p>@<a href="LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE3">TOC</a><br>接上文<a href="https://blog.csdn.net/qq_41214610/article/details/105508002">LeetCode算法题解——二分查找2</a>,本篇分享LeetCode中几道比较难想到使用二分查找解法的题目。</p>
<h1 id="第八题"><a href="#第八题" class="headerlink" title="第八题"></a>第八题</h1><p><a href="https://leetcode.cn/problems/single-element-in-a-sorted-array/">540. 有序数组中的单一元素</a></p>
<p>题目描述:<br>给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。</p>
<p>请你找出并返回只出现一次的那个数。</p>
<p>你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入: nums = [1,1,2,3,3,4,4,8,8]</span><br><span class="line">输出: 2</span><br></pre></td></tr></table></figure>
<h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>我们先思考一下,没有单一元素的nums,如[1,1,3,3,4,4,8,8]具有什么样的规律。不难发现,对于每一个偶数下标i=2k的nums[i],它的值都等于后一位nums[i+1]的值。但是在插入2之后,这种规律只会在2之前存在。在2之后,所有奇数下标i=2k+1的nums[i],都等于nums[i+1]。</p>
<p>所以,我们只需要找到中点m附近的偶数下标,通过判断nums[i]=nums[i+1]这种规律是否存在,就可以判断中点m是在插入的单一元素之前还是之后。如果这种规律存在,那么说明中点m在单一元素之前,需要收缩左边界;如果这种规律不存在,那么说明中点m在单一元素之后,需要收缩右边界。</p>
<p>收缩左边界时,因为已经知道nums[m] = nums[m+1],所以l=m+2。收缩右边界时,nums[m] != nums[m+1],则必定有nums[m+1]= nums[m+2],所以r=m。</p>
<p>最后,搜索区间不断缩小,不断将成对的元素排除在区间之外。当区间长度为1时,区间内的元素就是单一元素。</p>
<h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">singleNonDuplicate</span><span class="params">(<span class="type">int</span>[] nums)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>, h = nums.length - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (l < h) {</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (h - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (m % <span class="number">2</span> == <span class="number">1</span>) {</span><br><span class="line"> m--; <span class="comment">// 保证 l/h/m 都在偶数位,使得查找区间大小一直都是奇数</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (nums[m] == nums[m + <span class="number">1</span>]) {</span><br><span class="line"> l = m + <span class="number">2</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> h = m;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> nums[l];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">singleNonDuplicate</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>]</span>) -> <span class="built_in">int</span>:</span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">len</span>(nums) - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l < r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> m % <span class="number">2</span> == <span class="number">1</span>:</span><br><span class="line"> m -= <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> nums[m] == nums[m + <span class="number">1</span>]:</span><br><span class="line"> l = m + <span class="number">2</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> r = m</span><br><span class="line"> <span class="keyword">return</span> nums[l]</span><br></pre></td></tr></table></figure>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>之前的二分查找是查找一个target,这道题的二分查找是查找一种关系。某个点之前,这种关系满足,在某个点之后,这种关系不满足。我们需要通过判断关系的满足与否,缩小搜索区间,找出这个点。</p>
<h1 id="第九题"><a href="#第九题" class="headerlink" title="第九题"></a>第九题</h1><p><a href="https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/">153. 寻找旋转排序数组中的最小值</a></p>
<p>题目描述:<br>已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:<br>若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]<br>若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]<br>注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。</p>
<p>给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。</p>
<p>你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:nums = [3,4,5,1,2]</span><br><span class="line">输出:1</span><br><span class="line">解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。</span><br></pre></td></tr></table></figure>
<h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><p>根据单调性,对于升序nums,其任意一点m,其右侧任意一点都大于等于左侧任意一点,即nums[m+] >= nums[m-]。如果发生旋转,则在旋转点k,其右侧任意一点都小于等于左侧任意一点,即nums[k+] <= nums[k-]。通过上一题,我们可以知道,二分查找可以通过缩小搜索区间,找出这种使关系发生变化的点。</p>
<p>旋转点左侧为第一分枝,右侧为第二分枝。我们的目标就是,通过缩小收缩区间,找到第二分枝的左端点,即为旋转点。如果中点m在第二分枝上,根据单调性,有r > m && nums[r] >= nums[m],那么收缩r=m,使得r保持在第二分枝上。如果r=m-1的话,无法保证还在第二分枝,因为我们只验证过r和m的单调性,没有验证r和m-1的单调性。如果中点m在第一分枝上,则恰好r在旋转点(即第二分枝左端点)右侧,m在旋转点左侧,有nums[r] < nums[m],那么抛弃中点m及其左边的点,l=m+1。</p>
<h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">findMin</span><span class="params">(<span class="type">int</span>[] nums)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>, h = nums.length - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (l < h) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (h - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (nums[m] <= nums[h]) {</span><br><span class="line"> h = m;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> nums[l];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">findMin</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>]</span>) -> <span class="built_in">int</span>:</span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">len</span>(nums) - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> nums[m] == nums[r]:</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="keyword">elif</span> nums[r] < nums[m]:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> r = m </span><br><span class="line"> <span class="keyword">return</span> nums[l]</span><br></pre></td></tr></table></figure>
<h3 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h3><p>上面两道题使用二分查找解题的关键都在于,能够将要找的target与某种关系联系起来。在target的左侧,满足某种关系;在target的右侧,不满足这种关系。</p>
<h1 id="第十题"><a href="#第十题" class="headerlink" title="第十题"></a>第十题</h1><p><a href="https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array-ii/">154. 寻找旋转排序数组中的最小值 II</a></p>
<h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">findMin</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>]</span>) -> <span class="built_in">int</span>:</span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">len</span>(nums) - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> nums[r] == nums[m]:</span><br><span class="line"> r -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">elif</span> nums[r] > nums[m]:</span><br><span class="line"> r = m</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> nums[l]</span><br></pre></td></tr></table></figure>
<h1 id="第十一题"><a href="#第十一题" class="headerlink" title="第十一题"></a>第十一题</h1><p><a href="https://leetcode.cn/problems/search-a-2d-matrix-ii/">240. 搜索二维矩阵 II</a></p>
<p>题目描述:<br>编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:</p>
<p>每行的元素从左到右升序排列。<br>每列的元素从上到下升序排列。</p>
<p>示例1:<br><img src="https://img-blog.csdnimg.cn/48aadf584cf843678ce58565911ae3b2.png" alt="在这里插入图片描述"></p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5</span><br><span class="line">输出:true</span><br></pre></td></tr></table></figure>
<h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><p>在上面两道题中我已经谈到了,可以使用二分查找将target与某种关系联系起来,在target的左侧满足某种关系,而在target的右侧不满足这种关系。在这道题中,这种关系是结构上的。对于任意一个元素,其所在行自左向右递增,所在列自上而下递增。特别的,对于每一行最右的元素m,其左的所在行元素都比它小,其下的所在列元素都比它大。因此,如果给定一个target和m进行比较,target小于m则应该向其左的所在行元素继续比较;target大于m则应该向其下的所在列元素继续比较。如果m的位置超出矩阵的合法范围,则说明找不到target。</p>
<h3 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">searchMatrix</span><span class="params">(<span class="type">int</span>[][] matrix, <span class="type">int</span> target)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> matrix.length, n = matrix[<span class="number">0</span>].length;</span><br><span class="line"> <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>, j = n - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span>(i < m && j >= <span class="number">0</span>){</span><br><span class="line"> <span class="keyword">if</span>(target == matrix[i][j]){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(target < matrix[i][j]){</span><br><span class="line"> j--;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>; </span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">searchMatrix</span>(<span class="params">self, matrix: <span class="type">List</span>[<span class="type">List</span>[<span class="built_in">int</span>]], target: <span class="built_in">int</span></span>) -> <span class="built_in">bool</span>:</span><br><span class="line"> m = <span class="built_in">len</span>(matrix)</span><br><span class="line"> n = <span class="built_in">len</span>(matrix[<span class="number">0</span>])</span><br><span class="line"> x, y = <span class="number">0</span>, n - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> x < m <span class="keyword">and</span> y >= <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">if</span> matrix[x][y] == target:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"> <span class="keyword">elif</span> matrix[x][y] < target:</span><br><span class="line"> x += <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> y -= <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br></pre></td></tr></table></figure>
<h3 id="总结-2"><a href="#总结-2" class="headerlink" title="总结"></a>总结</h3><p>这一题和前面两题一样,都需要寻找一种关系作为突破口。在某个点之前,这种关系存在;在某个点之后,这种关系不存在。</p>
<h1 id="第十二题"><a href="#第十二题" class="headerlink" title="第十二题"></a>第十二题</h1><p><a href="https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/">378. 有序矩阵中第 K 小的元素</a></p>
<p>题目描述:<br>给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。<br>请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。</p>
<p>你必须找到一个内存复杂度优于 O(n2) 的解决方案。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8</span><br><span class="line">输出:13</span><br><span class="line">解释:矩阵中的元素为 [1,5,9,10,11,12,13,13,15],第 8 小元素是 13</span><br></pre></td></tr></table></figure>
<h3 id="思路-3"><a href="#思路-3" class="headerlink" title="思路"></a>思路</h3><p>我们先分析这道题<strong>为什么可以用二分查找来解决</strong>。正如前面三题所示,能够用二分查找解决的问题都存在一种关系,在target之前满足这种关系,在target之后不满足这种关系。让我们来看示例1,在数组[1,5,9,10,11,12,13,13,15]中,如果一个元素是target,那么数组中比它小的元素有8个;如果一个元素小于target,那么数组中比它小的元素小于8个;如果一个元素大于target,那么数组中比它小的元素大于8个。这种关系的存在,使得我们可以用二分查找来解决这道题。在这里,给出一个二分查找的思路作为参考,<a href="https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/solution/er-fen-chao-ji-jian-dan-by-jacksu1024/">二分,超级简单</a>。</p>
<p>关于这个思路,很多人会纠结的一点是,<strong>如何验证最后求得的l在数组中</strong>?其实就是在问,如果一个元素是target,那么数组中比它小的元素有8个;反过来,如果数组中比一个数小的元素有8个,那么这个元素到底是不是target?不难发现,“一个元素是target,那么数组中比它小的元素有8个”是个充分不必要条件。不妨把数组[1,5,9,10,11,12,13,13,15]最后的15改成30来讨论这个问题。对于数组[1,5,9,10,11,12,13,13,30],我们还是寻找第8小的元素,正确答案应该是13。但是,在13和30中间,其实还有很多个数满足“数组中比一个数小的元素有8个”这个条件。准确来说,14,15,…,29都满足这个条件。我称这些数为“影子target”。很多人就会纠结,按照<a href="https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/solution/er-fen-chao-ji-jian-dan-by-jacksu1024/">二分,超级简单</a>的思路,那么如何排除掉这些“影子target”?这里我们就得先想明白,为什么会存在“影子target”。简单来说,“影子target”就是target和target后一位之间的间隙。如果我们把最后一位改成20,那么正确答案还是13,“影子target”是14,15,…,19。如果我们把数组改成[1,5,9,10,11,12,13,16,20],那么正确答案是16,“影子target”是17,18,19。那么,我们会发现,<strong>16是满足“数组中比一个数小的元素有8个”这个条件的最小的数</strong>。</p>
<p>让我们<strong>从头思考一下这个问题</strong>。<strong>为什么我们可以用二分查找来解决这道问题</strong>?因为在数组中,如果一个元素是target,那么数组中比它小的元素个数cnt等于8;如果一个元素小于target,那么数组中比它小的元素个数cnt小于8;如果一个元素大于target,那么数组中比它小的元素cnt大于8。所以,我们可以用二分查找解决这道题。cnt小于8,则l=m+1;cnt大于8,则r=m-1。<strong>但是,cnt等于8时,我们就找到target了吗</strong>?上面已经分析过了,如果cnt等于8,那么这个元素不一定是target,还有可能是“影子target”。因为在target和target后一位之间,还有间隙。那么我们如何找到正确的target呢?我们已经发现,真实target就是满足cnt等于8的最小值,所以<strong>我们就是在找满足cnt等于8这个条件的左边界</strong>。既然是找左边界,在上一篇博客中我已经讨论过了,其实就是在找到满足cnt等于8这个条件的元素时,不要直接返回结果,而是继续收缩右边界。</p>
<h3 id="代码-4"><a href="#代码-4" class="headerlink" title="代码"></a>代码</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">kthSmallest</span><span class="params">(<span class="type">int</span>[][] matrix, <span class="type">int</span> k)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">n</span> <span class="operator">=</span> matrix.length, l = matrix[<span class="number">0</span>][<span class="number">0</span>], r = matrix[n - <span class="number">1</span>][n - <span class="number">1</span>], cnt = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l) / <span class="number">2</span>;</span><br><span class="line"> cnt = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < n; i++){</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> <span class="number">0</span>; j < n && matrix[i][j] <= m; j++){</span><br><span class="line"> cnt++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(cnt < k){</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> l;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">kthSmallest</span>(<span class="params">self, matrix: <span class="type">List</span>[<span class="type">List</span>[<span class="built_in">int</span>]], k: <span class="built_in">int</span></span>) -> <span class="built_in">int</span>:</span><br><span class="line"> n = <span class="built_in">len</span>(matrix)</span><br><span class="line"> l = matrix[<span class="number">0</span>][<span class="number">0</span>]</span><br><span class="line"> r = matrix[n - <span class="number">1</span>][n - <span class="number">1</span>]</span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> count = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> row <span class="keyword">in</span> matrix:</span><br><span class="line"> <span class="keyword">for</span> col <span class="keyword">in</span> row:</span><br><span class="line"> <span class="keyword">if</span> col <= m:</span><br><span class="line"> count += <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> k > count:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> l</span><br></pre></td></tr></table></figure>
<h3 id="总结-3"><a href="#总结-3" class="headerlink" title="总结"></a>总结</h3><p>这道题不难想到用二分查找来解决。一般人或许可以想到用官方题解差不多的二分法。但是,上面介绍的二分法,需要对为什么可以用二分法,用二分法是查找target还是左/右边界有深刻的理解。</p>
<p>参考:<br><a href="https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.md">Leetcode 题解 - 二分查找</a><br><a href="https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/solution/er-fen-chao-ji-jian-dan-by-jacksu1024/">二分,超级简单</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E5%8F%8C%E6%8C%87%E9%92%881/</url>
<content><![CDATA[<p>@<a href="LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E5%8F%8C%E6%8C%87%E9%92%881">TOC</a></p>
<p>这里介绍双指针在数组中的第一类题型:一个数组当两个用。</p>
<h1 id="第一题"><a href="#第一题" class="headerlink" title="第一题"></a>第一题</h1><p><a href="https://leetcode.cn/problems/merge-sorted-array/">88. 合并两个有序数组</a></p>
<p>题目描述:<br>给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。</p>
<p>请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。</p>
<p>注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3</span><br><span class="line">输出:[1,2,2,3,5,6]</span><br><span class="line">解释:需要合并 [1,2,3] 和 [2,5,6] 。</span><br><span class="line">合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。</span><br></pre></td></tr></table></figure>
<h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>一个简单的想法,借助新建数组nums3来完成nums1和nums2的合并。如果nums1[0]小于nums2[0],则将nums1[0]放入nums3[0],继续比较nums1[1]和nums2[0]。同样的,如果nums2[0]小于nums1[0],则将nums2[0]放入nums3[0],继续比较nums2[1]和nums1[0]。直到将nums1或nums2遍历完,剩下未遍历的部分可以直接放入nums3。</p>
<p>但是,题目要返回的是nums1而不是nums3。那么我们有两个办法来对上述的方法进行优化。第一个办法,最后遍历nums3,用nums3的元素替换nums1的元素。第二个办法,直接在nums1上进行上述的操作。如果要在nums1上进行上述的操作,那么就需要从大到小比较,先把最大的元素放到nums1最右侧,以免覆盖了未参与比较的nums1元素。</p>
<p><strong>直接把nums1数组当nums3数组来用,就是双指针的精髓所在</strong>。</p>
<h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">merge</span><span class="params">(<span class="type">int</span>[] nums1, <span class="type">int</span> m, <span class="type">int</span>[] nums2, <span class="type">int</span> n)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">idx1</span> <span class="operator">=</span> m-<span class="number">1</span>, idx2 = n - <span class="number">1</span>, idx = m + n - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span>(idx1>=<span class="number">0</span> || idx2 >=<span class="number">0</span>){</span><br><span class="line"> <span class="keyword">if</span>(idx1 < <span class="number">0</span>){</span><br><span class="line"> nums1[idx--] = nums2[idx2--];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(idx2 < <span class="number">0</span>){</span><br><span class="line"> nums1[idx--] = nums1[idx1--];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(nums1[idx1] > nums2[idx2]){</span><br><span class="line"> nums1[idx--] = nums1[idx1--];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> nums1[idx--] = nums2[idx2--]; </span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">merge</span>(<span class="params">self, nums1: <span class="type">List</span>[<span class="built_in">int</span>], m: <span class="built_in">int</span>, nums2: <span class="type">List</span>[<span class="built_in">int</span>], n: <span class="built_in">int</span></span>) -> <span class="literal">None</span>:</span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> Do not return anything, modify nums1 in-place instead.</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> idx1, idx2, idx3 = m - <span class="number">1</span>, n - <span class="number">1</span>, m + n - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> idx1 >= <span class="number">0</span> <span class="keyword">and</span> idx2 >= <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">if</span> nums1[idx1] > nums2[idx2]:</span><br><span class="line"> nums1[idx3] = nums1[idx1]</span><br><span class="line"> idx3 -= <span class="number">1</span></span><br><span class="line"> idx1 -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> nums1[idx3] = nums2[idx2]</span><br><span class="line"> idx3 -= <span class="number">1</span></span><br><span class="line"> idx2 -= <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">while</span> idx3 >= <span class="number">0</span> <span class="keyword">and</span> idx2 >= <span class="number">0</span>:</span><br><span class="line"> nums1[idx3] = nums2[idx2]</span><br><span class="line"> idx3 -= <span class="number">1</span></span><br><span class="line"> idx2 -= <span class="number">1</span></span><br></pre></td></tr></table></figure>
<h1 id="第二题"><a href="#第二题" class="headerlink" title="第二题"></a>第二题</h1><p><a href="https://leetcode.cn/problems/remove-element/">27. 移除元素</a></p>
<p>题目描述:<br>给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。</p>
<p>不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。</p>
<p>元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:nums = [3,2,2,3], val = 3</span><br><span class="line">输出:2, nums = [2,2]</span><br><span class="line">解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。</span><br></pre></td></tr></table></figure>
<h2 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h2><p>如果不要求原地修改,那很简单。只需要新建数组nums1,从左到右扫描nums的元素,如果nums的元素不等于val,则将其放入nums1;如果等于val,则跳过。</p>
<p>但是,现在要求原地修改,也就是要<strong>一个数组当作两个用</strong>。和上一题一样,有两种办法。第一种办法,可以先把元素放在数组nums1,然后再用nums1的元素去覆盖nums的元素。第二种办法,可以<strong>直接把nums数组当nums1数组</strong>。但是,这样<strong>会不会导致nums原有的元素被覆盖</strong>呢?实际上是不会的,我们思考一下,如果用idx1扫描nums,非val元素通过idx2存放到nums1,那么<strong>idx1总是大于等于idx2</strong>的。也就是说,<strong>idx2使用的区域,idx1早就扫描过了</strong>。</p>
<h2 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h2><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">removeElement</span><span class="params">(<span class="type">int</span>[] nums, <span class="type">int</span> val)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">slow</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">fast</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(; fast < nums.length; fast++){</span><br><span class="line"> <span class="keyword">if</span>(nums[fast] != val){</span><br><span class="line"> nums[slow] = nums[fast];</span><br><span class="line"> slow++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> slow;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">removeElement</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>], val: <span class="built_in">int</span></span>) -> <span class="built_in">int</span>:</span><br><span class="line"> n = <span class="built_in">len</span>(nums)</span><br><span class="line"> slow, fast = <span class="number">0</span>, <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> fast < n:</span><br><span class="line"> <span class="keyword">if</span> nums[fast] != val:</span><br><span class="line"> nums[slow] = nums[fast]</span><br><span class="line"> slow += <span class="number">1</span></span><br><span class="line"> fast += <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> slow</span><br></pre></td></tr></table></figure>
<h1 id="第三题"><a href="#第三题" class="headerlink" title="第三题"></a>第三题</h1><p><a href="https://leetcode.cn/problems/move-zeroes/">283. 移动零</a></p>
<p>题目描述:<br>给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。</p>
<p>请注意 ,必须在不复制数组的情况下原地对数组进行操作。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入: nums = [0,1,0,3,12]</span><br><span class="line">输出: [1,3,12,0,0]</span><br></pre></td></tr></table></figure>
<h2 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h2><p>这题和上一题很相似,都是遇到val(0)就跳过。但是不同的是,这道题不仅要跳过val,还要把val放到后面去。有两种办法,第一种是和第二题一样,遇到val的时候就跳过val,然后再把后面都填充为val;第二种是让val和非val进行交换。</p>
<h2 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h2><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">moveZeroes</span><span class="params">(<span class="type">int</span>[] nums)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">slow</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">fast</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">val</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(; fast < nums.length; fast++){</span><br><span class="line"> <span class="keyword">if</span>(nums[fast] != val){</span><br><span class="line"> <span class="type">int</span> <span class="variable">temp</span> <span class="operator">=</span> nums[slow];</span><br><span class="line"> nums[slow] = nums[fast];</span><br><span class="line"> nums[fast] = temp;</span><br><span class="line"> slow++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">moveZeroes</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>]</span>) -> <span class="literal">None</span>:</span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> Do not return anything, modify nums in-place instead.</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> n = <span class="built_in">len</span>(nums)</span><br><span class="line"> slow, fast = <span class="number">0</span>, <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> fast < n:</span><br><span class="line"> <span class="keyword">if</span> nums[fast] != <span class="number">0</span>:</span><br><span class="line"> nums[slow], nums[fast] = nums[fast], nums[slow]</span><br><span class="line"> slow += <span class="number">1</span></span><br><span class="line"> fast += <span class="number">1</span></span><br></pre></td></tr></table></figure>
<h1 id="第四题"><a href="#第四题" class="headerlink" title="第四题"></a>第四题</h1><p><a href="https://leetcode.cn/problems/remove-duplicates-from-sorted-array/">26. 删除有序数组中的重复项</a></p>
<p>题目描述:<br>给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。</p>
<p>由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。</p>
<p>将最终结果插入 nums 的前 k 个位置后返回 k 。</p>
<p>不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:nums = [1,1,2]</span><br><span class="line">输出:2, nums = [1,2,_]</span><br><span class="line">解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。</span><br></pre></td></tr></table></figure>
<h2 id="思路-3"><a href="#思路-3" class="headerlink" title="思路"></a>思路</h2><p>如果不是原地修改,那我们还是考虑新建数组nums1。nums[0]肯定是不重复的,可以放到nums1[0]。因为nums是有序的,从nums[1]开始,如果和前面的元素相同,那么说明是重复的,可以跳过;如果和前面的元素不同,那么说明不重复,放入nums1数组。</p>
<p>如果要原地修改,还是同样的情况,有两种办法。第一种办法就是用nums1去覆盖nums。第二种办法,要<strong>一个数组当作两个用</strong>。我们总是要思考,<strong>会不会覆盖未扫描的元素</strong>?看得出,fast总是比slow跑得快,所以不会覆盖。</p>
<h2 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h2><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">removeDuplicates</span><span class="params">(<span class="type">int</span>[] nums)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">slow</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">fast</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(; fast < nums.length; fast++){</span><br><span class="line"> <span class="keyword">if</span>(nums[fast] != nums[slow]){</span><br><span class="line"> slow += <span class="number">1</span>;</span><br><span class="line"> nums[slow] = nums[fast];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> slow + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">removeDuplicates</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>]</span>) -> <span class="built_in">int</span>:</span><br><span class="line"> n = <span class="built_in">len</span>(nums)</span><br><span class="line"> slow, fast = <span class="number">0</span>, <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> fast < n:</span><br><span class="line"> <span class="keyword">if</span> nums[fast] != nums[slow]:</span><br><span class="line"> slow += <span class="number">1</span></span><br><span class="line"> nums[slow] = nums[fast]</span><br><span class="line"></span><br><span class="line"> fast += <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> slow + <span class="number">1</span></span><br></pre></td></tr></table></figure>
<p>下一篇博客<a href="">LeetCode算法题解——双指针2</a>中,我将分享LeetCode中另一种类型的双指针问题。</p>
<p>参考:</p>
<p><a href="https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E5%8F%8C%E6%8C%87%E9%92%88.md">Leetcode 题解 - 双指针</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE1/</url>
<content><![CDATA[<p>@<a href="LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE1">TOC</a><br>常用的二分查找包括:寻找一个数、插入target、寻找左右边界。</p>
<h1 id="第一题(寻找一个数)"><a href="#第一题(寻找一个数)" class="headerlink" title="第一题(寻找一个数)"></a>第一题(寻找一个数)</h1><p><a href="https://leetcode.cn/problems/binary-search/">704. 二分查找</a></p>
<p>题目描述:<br>给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入: nums = [-1,0,3,5,9,12], target = 9</span><br><span class="line">输出: 4</span><br><span class="line">解释: 9 出现在 nums 中并且下标为 4</span><br></pre></td></tr></table></figure>
<h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>二分法,如果找到target,直接返回;如果target比中点值小,说明在左区间,则缩小右端点;如果target比中点值大,说明在右区间,则缩小左端点。</p>
<h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>c++版本</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">binarySearch</span><span class="params">(vector<<span class="type">int</span>> nums, <span class="type">int</span> target)</span> </span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// 查找区间</span></span><br><span class="line"> <span class="type">int</span> l = <span class="number">0</span>; </span><br><span class="line"> <span class="type">int</span> r = nums.<span class="built_in">size</span>() - <span class="number">1</span>;</span><br><span class="line"> <span class="comment">// 终止条件</span></span><br><span class="line"> <span class="keyword">while</span>(l <= r) </span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// 中点计算</span></span><br><span class="line"> <span class="type">int</span> m = l + (r - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="comment">// 区间缩减</span></span><br><span class="line"> <span class="keyword">if</span>(nums[m] == target)</span><br><span class="line"> <span class="keyword">return</span> m; </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (nums[m] < target)</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (nums[m] > target)</span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">search</span><span class="params">(<span class="type">int</span>[] nums, <span class="type">int</span> target)</span> {</span><br><span class="line"> <span class="comment">// 左闭右闭</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> nums.length - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span>(target == nums[m]){</span><br><span class="line"> <span class="comment">// 如果找到,直接返回</span></span><br><span class="line"> <span class="keyword">return</span> m;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(target > nums[m]){</span><br><span class="line"> <span class="comment">// 右边界缩小</span></span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(target > nums[m]){</span><br><span class="line"> <span class="comment">// 左边界缩小</span></span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 未找到,返回-1</span></span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">search</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>], target: <span class="built_in">int</span></span>) -> <span class="built_in">int</span>:</span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">len</span>(nums) - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> target == nums[m]:</span><br><span class="line"> <span class="keyword">return</span> m</span><br><span class="line"> <span class="keyword">elif</span> target < nums[m]:</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span></span><br></pre></td></tr></table></figure>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>本题有两点需要注意。<br>第一点,搜索区间是“左闭右闭”。之所以选择“左闭右闭”的搜索区间,是为了在缩小左、右端点的时候可以统一操作。此外,因为搜索区间是“左闭右闭”的,所以循环条件是左端点小于等于右端点。<br>第二点,取中点的计算要防溢出。</p>
<h1 id="第二题(插入target)"><a href="#第二题(插入target)" class="headerlink" title="第二题(插入target)"></a>第二题(插入target)</h1><p><a href="https://leetcode.cn/problems/search-insert-position/">35. 搜索插入位置</a></p>
<p>题目描述:<br>给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。</p>
<p>请必须使用时间复杂度为 O(log n) 的算法。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入: nums = [1,3,5,6], target = 2</span><br><span class="line">输出: 1</span><br></pre></td></tr></table></figure>
<h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><p>如果找得到,则参考上题代码。如果找不到,循环停止时,左边界l以左(不包含l)的元素都小于target,右边界r以右(不包含r)的元素都大于target。所以,target应该插入左边界l的位置,这样其左侧元素皆小于target,其右侧元素皆大于target。</p>
<h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">searchInsert</span><span class="params">(<span class="type">int</span>[] nums, <span class="type">int</span> target)</span> {</span><br><span class="line"> <span class="comment">// 左闭右闭</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> nums.length - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l)/<span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span>(target == nums[m]){</span><br><span class="line"> <span class="comment">// 如果找到,直接返回</span></span><br><span class="line"> <span class="keyword">return</span> m;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(target > nums[m]){</span><br><span class="line"> <span class="comment">// 右边界缩小</span></span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(target > nums[m]){</span><br><span class="line"> <span class="comment">// 左边界缩小</span></span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 返回左边界</span></span><br><span class="line"> <span class="keyword">return</span> l;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">searchInsert</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>], target: <span class="built_in">int</span></span>) -> <span class="built_in">int</span>:</span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">len</span>(nums) - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> nums[m] == target:</span><br><span class="line"> <span class="keyword">return</span> m</span><br><span class="line"> <span class="keyword">elif</span> target < nums[m]:</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> l</span><br></pre></td></tr></table></figure>
<h3 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h3><p>循环停止时,左边界l以左(不包含l)的元素都小于target,右边界r以右(不包含r)的元素都大于target。所以,target应该插入左边界l的位置,这样其左侧元素皆小于target,其右侧元素皆大于target。</p>
<h1 id="第三题(寻找左右边界)"><a href="#第三题(寻找左右边界)" class="headerlink" title="第三题(寻找左右边界)"></a>第三题(寻找左右边界)</h1><p><a href="https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/">34. 在排序数组中查找元素的第一个和最后一个位置</a></p>
<p>题目描述:<br>给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。</p>
<p>如果数组中不存在目标值 target,返回 [-1, -1]。</p>
<p>你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:nums = [5,7,7,8,8,10], target = 8</span><br><span class="line">输出:[3,4]</span><br></pre></td></tr></table></figure>
<h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><p>先考虑左边界。和前面两题不同,这题找到target不能直接返回,要继续寻找,直到找到第一个target。当循环停止时,左边界l以左的元素都小于target,则左边界l以右的元素都大于等于target,左边界l即第一个target。所以,当找到target的时候,仍然缩小右边界,向左边界靠拢。</p>
<p>同理,搜索右边界时,当找到target不能直接返回,要继续寻找,直到找到最后一个target。当循环停止时,右边界r以右的元素都大于target,则右边界r以左的元素都小于等于target,右边界r即最后一个target。所以,当找到target的时候,仍然缩小左边界,向右边界靠拢。</p>
<p>得到了左右边界,也只是说明如果有target,那第一个和最后一个target就是左右边界。但是,存在没有target的可能,所以还需要对左右边界进行判断。值得注意的是,可能target比所有的元素都大,此时左边界l等于数组长度,需要先判断是否越界,再判断左边界是否为target。同样的,可能target比所有的元素都小,此时右边界l等于-1,需要先判断是否越界,再判断右边界是否为target。</p>
<h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span>[] searchRange(<span class="type">int</span>[] nums, <span class="type">int</span> target) {</span><br><span class="line"> <span class="type">int</span> results[] = <span class="keyword">new</span> <span class="title class_">int</span>[]{-<span class="number">1</span>, -<span class="number">1</span>};</span><br><span class="line"> <span class="comment">// 左闭右闭</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> nums.length - <span class="number">1</span>;</span><br><span class="line"> <span class="comment">// 寻找第一个target</span></span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="comment">// 缩小右边界</span></span><br><span class="line"> <span class="keyword">if</span>(target <= nums[m]){</span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 缩小左边界</span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(target > nums[m]){</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 防止越界</span></span><br><span class="line"> <span class="keyword">if</span>((l < nums.length) && (nums[l] == target)){</span><br><span class="line"> results[<span class="number">0</span>] = l;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 左闭右闭</span></span><br><span class="line"> l = <span class="number">0</span>;</span><br><span class="line"> r = nums.length - <span class="number">1</span>;</span><br><span class="line"> <span class="comment">// 寻找最后一个target</span></span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="comment">// 防止溢出</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> l + (r - l) / <span class="number">2</span>;</span><br><span class="line"> <span class="comment">// 缩小左边界</span></span><br><span class="line"> <span class="keyword">if</span>(target >= nums[m]){</span><br><span class="line"> l = m + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 缩小右边界</span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(target < nums[m]){</span><br><span class="line"> r = m - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 防止越界</span></span><br><span class="line"> <span class="keyword">if</span>((r >= <span class="number">0</span>) && (nums[r] == target)){</span><br><span class="line"> results[<span class="number">1</span>] = r;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> results;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">searchRange</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>], target: <span class="built_in">int</span></span>) -> <span class="type">List</span>[<span class="built_in">int</span>]:</span><br><span class="line"> <span class="keyword">if</span> nums == <span class="literal">None</span> <span class="keyword">or</span> <span class="built_in">len</span>(nums) == <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> [-<span class="number">1</span>, -<span class="number">1</span>]</span><br><span class="line"> </span><br><span class="line"> result = [-<span class="number">1</span>, -<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">len</span>(nums) - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> target <= nums[m]:</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> l < <span class="built_in">len</span>(nums) <span class="keyword">and</span> nums[l] == target:</span><br><span class="line"> result[<span class="number">0</span>] = l</span><br><span class="line"> </span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">len</span>(nums) - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l + (r - l) // <span class="number">2</span></span><br><span class="line"> <span class="keyword">if</span> target >= nums[m]:</span><br><span class="line"> l = m + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> r = m - <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> r >= <span class="number">0</span> <span class="keyword">and</span> nums[r] == target:</span><br><span class="line"> result[<span class="number">1</span>] = r</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> result</span><br></pre></td></tr></table></figure>
<h3 id="总结-2"><a href="#总结-2" class="headerlink" title="总结"></a>总结</h3><p>本题有三点需要注意。</p>
<p>第一点,理解为什么左右边界就是第一个和最后一个target。当循环停止时,左边界l以左的元素都小于target,则左边界l以右的元素都大于等于target,左边界l即第一个target。当循环停止时,右边界r以右的元素都大于target,则右边界r以左的元素都小于等于target,右边界r即最后一个target。</p>
<p>第二点,当找到target的时候左右边界如何移动。寻找左边界时,需要右边界向左边界靠拢,所以找到target时仍然缩小右边界。寻找右边界时,需要左边界向右边界靠拢,所以找到target时仍然缩小左边界。</p>
<p>第三点,防止左右边界越界。左右边界是target“应该”出现的第一个和最后一个位置,到底是不是还需要经过验证。验证之前,记得考虑左右边界是否越界。</p>
<p>下一篇博客<a href="https://blog.csdn.net/qq_41214610/article/details/128852619">LeetCode算法题解——二分查找2</a>,我将总结LeetCode中部分题目的二分查找解法。</p>
<p>参考:</p>
<p><a href="https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/er-fen-cha-zhao-suan-fa-xi-jie-xiang-jie-by-labula/">二分查找算法细节详解,顺便写了首诗</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E5%8F%8C%E6%8C%87%E9%92%882/</url>
<content><![CDATA[<p>@<a href="LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E5%8F%8C%E6%8C%87%E9%92%882">TOC</a></p>
<p>这里介绍双指针在数组中的第二类题型:两端夹击。</p>
<h1 id="第五题"><a href="#第五题" class="headerlink" title="第五题"></a>第五题</h1><p><a href="https://leetcode.cn/problems/squares-of-a-sorted-array/">977. 有序数组的平方</a></p>
<p>题目描述:<br>给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:nums = [-4,-1,0,3,10]</span><br><span class="line">输出:[0,1,9,16,100]</span><br><span class="line">解释:平方后,数组变为 [16,1,0,9,100]</span><br><span class="line">排序后,数组变为 [0,1,9,16,100]</span><br></pre></td></tr></table></figure>
<h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>因为是排序每个数字的平方,根据二次函数图像y=x^2开口向上可得,最大值在两端,最小值在中间。所以,最左和最右进行比较,<strong>两端夹击</strong>,看谁的平方值更大。</p>
<h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span>[] sortedSquares(<span class="type">int</span>[] nums) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">n</span> <span class="operator">=</span> nums.length;</span><br><span class="line"> <span class="type">int</span>[] result = <span class="keyword">new</span> <span class="title class_">int</span>[n];</span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> n - <span class="number">1</span>;</span><br><span class="line"> <span class="type">int</span> <span class="variable">k</span> <span class="operator">=</span> n - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="keyword">if</span>(nums[l] * nums[l] > nums[r] * nums[r]){</span><br><span class="line"> result[k] = nums[l] * nums[l];</span><br><span class="line"> l++;</span><br><span class="line"> k--;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> result[k] = nums[r] * nums[r];</span><br><span class="line"> r--;</span><br><span class="line"> k--;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">sortedSquares</span>(<span class="params">self, nums: <span class="type">List</span>[<span class="built_in">int</span>]</span>) -> <span class="type">List</span>[<span class="built_in">int</span>]:</span><br><span class="line"> n = <span class="built_in">len</span>(nums)</span><br><span class="line"> result = [<span class="number">0</span>] * n</span><br><span class="line"> l, r, idx = <span class="number">0</span>, n - <span class="number">1</span>, n - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> numl = nums[l] * nums[l]</span><br><span class="line"> numr = nums[r] * nums[r]</span><br><span class="line"> <span class="keyword">if</span> numl > numr:</span><br><span class="line"> result[idx] = numl</span><br><span class="line"> idx -= <span class="number">1</span></span><br><span class="line"> l += <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> result[idx] = numr</span><br><span class="line"> idx -= <span class="number">1</span></span><br><span class="line"> r -= <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> result</span><br></pre></td></tr></table></figure>
<h1 id="第六题"><a href="#第六题" class="headerlink" title="第六题"></a>第六题</h1><p><a href="https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/">167. 两数之和 II - 输入有序数组</a></p>
<p>题目描述:<br>给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。<br>函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:numbers = [2,7,11,15], target = 9</span><br><span class="line">输出:[1,2]</span><br><span class="line">解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。</span><br></pre></td></tr></table></figure>
<h2 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h2><p>可以先考虑边界情况。升序数组中任意两个元素求和,最小为nums[0]+nums[1],最大为nums[n-2]+nums[n-1]。target的范围一定在这两者之间,否则找不到答案。所以,我们可以<strong>两端夹击</strong>,一直手抓nums[0],另一只手抓nums[n-1]。如果是最小的情况,那么让nums[n-1]向nums[1]靠拢;如果是最大的情况,那么让nums[1]向nums[n-2]靠拢。</p>
<h2 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h2><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span>[] twoSum(<span class="type">int</span>[] numbers, <span class="type">int</span> target) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>, r = numbers.length - <span class="number">1</span>;</span><br><span class="line"> <span class="type">int</span>[] result = <span class="keyword">new</span> <span class="title class_">int</span>[]{<span class="number">0</span>, <span class="number">0</span>};</span><br><span class="line"> <span class="keyword">while</span>(l < r){</span><br><span class="line"> <span class="type">int</span> <span class="variable">sum</span> <span class="operator">=</span> numbers[l] + numbers[r];</span><br><span class="line"> <span class="keyword">if</span>(sum == target){</span><br><span class="line"> result[<span class="number">0</span>] = l + <span class="number">1</span>;</span><br><span class="line"> result[<span class="number">1</span>] = r + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(sum < target){</span><br><span class="line"> l++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> r--;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">twoSum</span>(<span class="params">self, numbers: <span class="type">List</span>[<span class="built_in">int</span>], target: <span class="built_in">int</span></span>) -> <span class="type">List</span>[<span class="built_in">int</span>]:</span><br><span class="line"> n = <span class="built_in">len</span>(numbers)</span><br><span class="line"> l, r = <span class="number">0</span>, n - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> l < r:</span><br><span class="line"> m = numbers[l] + numbers[r]</span><br><span class="line"> <span class="keyword">if</span> m == target:</span><br><span class="line"> <span class="keyword">return</span> [l + <span class="number">1</span>, r + <span class="number">1</span>]</span><br><span class="line"> <span class="keyword">elif</span> target > m:</span><br><span class="line"> l += <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> r -= <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> [-<span class="number">1</span>, -<span class="number">1</span>]</span><br></pre></td></tr></table></figure>
<h1 id="第七题"><a href="#第七题" class="headerlink" title="第七题"></a>第七题</h1><p><a href="https://leetcode.cn/problems/sum-of-square-numbers/">633. 平方数之和</a></p>
<p>题目描述:<br>给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a^2 + b^2 = c 。</p>
<p>示例1:</p>
<figure class="highlight text"><table><tr><td class="code"><pre><span class="line">输入:c = 5</span><br><span class="line">输出:true</span><br><span class="line">解释:1 * 1 + 2 * 2 = 5</span><br></pre></td></tr></table></figure>
<h2 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h2><p>上一题是两个数的和是否为target,这道题是两个数的平方和是否为target。一样的思路,考虑最大最小值。若两个数的平方和为target,则最小为0,最大为target的平方根。同样的,<strong>两端夹击</strong>。</p>
<h2 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h2><p>java版本</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">judgeSquareSum</span><span class="params">(<span class="type">int</span> c)</span> {</span><br><span class="line"> <span class="type">long</span> <span class="variable">l</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="type">long</span> <span class="variable">r</span> <span class="operator">=</span> (<span class="type">long</span>) Math.sqrt(c);</span><br><span class="line"> <span class="keyword">while</span>(l <= r){</span><br><span class="line"> <span class="type">long</span> <span class="variable">m</span> <span class="operator">=</span> l * l + r * r;</span><br><span class="line"> <span class="keyword">if</span>(m == c){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(m < c){</span><br><span class="line"> l++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> r--;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">judgeSquareSum</span>(<span class="params">self, c: <span class="built_in">int</span></span>) -> <span class="built_in">bool</span>:</span><br><span class="line"> l, r = <span class="number">0</span>, <span class="built_in">int</span>(sqrt(c))</span><br><span class="line"> <span class="keyword">while</span> l <= r:</span><br><span class="line"> m = l * l + r * r</span><br><span class="line"> <span class="keyword">if</span> m == c:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"> <span class="keyword">elif</span> m < c:</span><br><span class="line"> l += <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> r -= <span class="number">1</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br></pre></td></tr></table></figure>
<p>下一篇博客<a href="">LeetCode算法题解——双指针3</a>中,我将分享LeetCode中关于字符串的双指针问题。</p>
<p>参考:</p>
<p><a href="https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3%20-%20%E5%8F%8C%E6%8C%87%E9%92%88.md">Leetcode 题解 - 双指针</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/Linux%E7%B3%BB%E7%BB%9F%E6%8A%A5%E9%94%99%EF%BC%9AFailed%20to%20execute%20default%20Terminal%20Emulator.%20Input_output%20error./</url>
<content><![CDATA[<p>@[TOC](Linux系统报错:Failed to execute default Terminal Emulator. Input/output error.)<br>最近新配了一个服务器环境,之前使用的是配置好anconda和pytorch等库的环境,但是这次申请忘记了之前那个环境是哪一个,所以要重新配置。<br>一登陆之后,打算打开命令行,开始配tensorflow环境,就遇到了一个问题:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">Failed to execute default Terminal Emulator. Input/output error.</span><br></pre></td></tr></table></figure>
<p>命令行打不开了!<br>查询资料之后得知,是Linux系统默认的命令行不对,需要自己手动修改一下:</p>
<ol>
<li>点击桌面左上角的Applications</li>
</ol>
<p><img src="https://img-blog.csdnimg.cn/20200526220342989.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_5,color_FFFFFF,t_20" alt="在这里插入图片描述"></p>
<ol start="2">
<li>点击Settings,选择Settings Manager<br><img src="https://img-blog.csdnimg.cn/20200526220825366.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></li>
<li>点击Preferred Applications</li>
</ol>
<p><img src="https://img-blog.csdnimg.cn/20200526220935289.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>4. 点击Utilities下的Terminal Emulator,选择Xfce Terminal<br><img src="https://img-blog.csdnimg.cn/20200526221002714.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>然后就可以正常使用了。<br>参考链接:<a href="https://ubuntuforums.org/showthread.php?t=1894293">Failed to execute default Terminal Emulator. Input/output error.</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/Mac%E4%B8%8B%E5%AE%9E%E7%8E%B0Word%E6%96%87%E6%A1%A3%E6%89%B9%E9%87%8F%E8%BD%AC%E6%8D%A2%E4%B8%BAPDF/</url>
<content><![CDATA[<ol>
<li>使用Adobe Acrobat(首推)<br><a href="https://zhuanlan.zhihu.com/p/89370385">有招啦!轻松实现Word文档批量转换为PDF</a></li>
<li>使用Mac的自动操作<br><a href="https://zhuanlan.zhihu.com/p/391820589">Mac下实现批量Word或PPT转PDF</a></li>
<li>使用LibreOffice<br><a href="https://sspai.com/post/44140#!">如何在 macOS 上一键批量把 PPT 和 Word 文件转成 PDF</a></li>
</ol>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/Mac%E4%BD%BF%E7%94%A8ssh%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6%E5%88%B0%E6%9C%8D%E5%8A%A1%E5%99%A8/</url>
<content><![CDATA[<p>@<a href="Mac%E4%BD%BF%E7%94%A8ssh%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6%E5%88%B0%E6%9C%8D%E5%8A%A1%E5%99%A8">TOC</a></p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">scp <span class="literal">-P</span> 端口号 本地文件 服务器用户名<span class="selector-tag">@</span>服务器ip:目标文件夹</span><br></pre></td></tr></table></figure>
<p>然后,输入”yes”,回车。<br>最后,输入密码,回车。</p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/YOLOv3%E6%98%BE%E7%A4%BA%E7%B1%BB%E5%88%AB%E4%BD%86%E6%98%AF%E4%B8%8D%E6%98%BE%E7%A4%BAbounding%20box/</url>
<content><![CDATA[<p>@[TOC](YOLOv3显示类别但是不显示bounding box)<br>这两天在跑YOLOv3的源代码,试着用自己的数据集训练并测试。之前测试了好几个数据集都没问题,今天遇到一个数据集,测试结果只显示类别,但是不显示bounding box。而且奇怪的是,并不是所有结果都这样,只是有的类别有,有的类别没有。<br>在原作者GitHub的issues里面找到了答案。<br>原来,bounding box的线条宽度,依赖于输入图片的高度。当输入图片的尺寸太小,bounding box的线条太细,就没法显示了。这个时候需要手动修改src文件夹下image.c/draw_detections函数,将width调大。记得修改文件后,make。</p>
<p><strong>参考</strong><br><a href="https://github.com/pjreddie/darknet/issues/1247">no boxes is shown in predictions.jpg #1247</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/YOLOv3%E8%AE%AD%E7%BB%83+%E4%BF%AE%E6%94%B9/</url>
<content><![CDATA[<p>@<a href="YOLOv3%E8%AE%AD%E7%BB%83+%E4%BF%AE%E6%94%B9">TOC</a><br>最近参加2020年(第13届)中国大学生计算机设计大赛,选择了人工智能挑战赛的赛题二,基于 CT 影像的结直肠息肉检测。<br>赛题要求是,设计算法,判断图像中是否存在息肉,并实现息肉的准确检测,利用矩形方框将所检测出的息肉包含在检测框内。<br>乍一看,是一道标准的目标检测题,再看看官方给出的数据集标注,是YOLO格式的,那就直接用YOLOv3进行训练。最后再根据题目的需求,增加了一些功能。<br>我们这个版本,是在c语言的YOLOv3框架上进行修改的;网上还有很多基于pytorch、tensorflow构建的YOLOv3,以后有时间也写一下。</p>
<h1 id="YOLOv3训练自己的数据集"><a href="#YOLOv3训练自己的数据集" class="headerlink" title="YOLOv3训练自己的数据集"></a>YOLOv3训练自己的数据集</h1><h2 id="标记数据"><a href="#标记数据" class="headerlink" title="标记数据"></a>标记数据</h2><p>如果是训练自己的数据集,即还未对数据集进行标注,那么推荐使用<a href="https://github.com/tzutalin/labelImg">LabelImg</a>工具进行标注,可以得到适用于PascalVOC(xml)或者YOLO(txt)格式的标注。<br>因为官方给出的数据集已经是YOLO格式的标注,我们可以直接用。当然,考虑到后面某个功能使用了PascalVOC格式的标注,这里给出一个从YOLO(txt)格式转换成PascalVOC(xml)格式的代码<a href="https://github.com/LU-K-Brant/yolov3_modify/blob/master/txt2xml.py">txt2xml.py</a>。<br>此时,原始图像放在JPEGImages目录下,YOLO(txt)格式标注放在labels目录下,PascalVOC(xml)格式标注放在Annotations目录下。</p>
<h2 id="制作-yolo-需要的txt文件"><a href="#制作-yolo-需要的txt文件" class="headerlink" title="制作 yolo 需要的txt文件"></a>制作 yolo 需要的txt文件</h2><p>这一步需要制作四个文件:train.txt、val.txt、object_train.txt、object_val.txt。<br>train.txt、val.txt这两个文件保存了用于训练、验证图片的名字,每行一个名字(不带后缀.jpg)。这里参考了一个别人的代码<a href="https://github.com/yehengchen/Object-Detection-and-Tracking/blob/master/OneStage/yolo/yolov3/img2train.py">img2train.py</a>。<br>object_train.txt、object_val.txt这两个文件保存了用于训练、验证图片的绝对路径,每行一个路径。这里参考了一个别人的代码<a href="https://github.com/yehengchen/Object-Detection-and-Tracking/blob/master/OneStage/yolo/yolov3/voc_label.py">voc_label.py</a>。这个代码不仅可以划分文件,还可以将PascalVOC(xml)格式标注转换成YOLO(txt)格式标注。</p>
<h2 id="制作-yolo-需要的配置文件"><a href="#制作-yolo-需要的配置文件" class="headerlink" title="制作 yolo 需要的配置文件"></a>制作 yolo 需要的配置文件</h2><p>这一步需要制作三个文件:ct.names、ct.data、ct.cfg(ct是自己定义的,因为我用的是ct数据集,所以有此定义)。<br>ct.names包含数据集中的种类,每行一个。注意,这个顺序代表了之后预测时的种类顺序。<br>ct.data包含以下几个内容</p>
<blockquote>
<p>classes= 1 # 类别数<br> train = data/object_train.txt # obj_train.txt 路径<br> valid = data/object_val.txt # obj_val.txt 路径<br> names = data/ct.names # ct.names 路径<br> backup = backup/ # 建一个 backup 文件夹用于存放 weights 结果</p>
</blockquote>
<p>注意,这里放的是object_train.txt和object_val.txt,是写有绝对路径的txt文本。<br>ct.cfg包含的是与YOLOv3训练或测试相关的配置,有几个地方需要注意</p>
<blockquote>
<p>1.注意文档开头training和testing的切换;<br>2.直接搜索‘classes’,修改三处对应位置:<br>[convolutional]<br> filters = 3*(classes + 5) #修改filters数量<br> [yolo]<br> classes=5 #修改类别数;<br> 3.修改max_batches = 2000 * classes</p>
</blockquote>
<h2 id="训练"><a href="#训练" class="headerlink" title="训练"></a>训练</h2><p>首先,下载预训练权重。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="built_in">wget</span> https://pjreddie.com/media/files/darknet53.conv.<span class="number">74</span></span><br></pre></td></tr></table></figure>
<p>然后,执行训练命令。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">./darknet detector train ./cfg/ct.data ./cfg/ct.cfg darknet53.conv.<span class="number">74</span></span><br></pre></td></tr></table></figure>
<h1 id="增加功能"><a href="#增加功能" class="headerlink" title="增加功能"></a>增加功能</h1><h2 id="在图像上添加置信度"><a href="#在图像上添加置信度" class="headerlink" title="在图像上添加置信度"></a>在图像上添加置信度</h2><p>YOLOv3单张图像检测的结果,默认设定只包含目标类别。我们可以通过修改src/image.c文件draw_detections()函数,添加目标置信度。修改片段如下:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span>(i = <span class="number">0</span>; i < num; ++i)</span><br><span class="line">{</span><br><span class="line"> <span class="type">char</span> labelstr[<span class="number">4096</span>] = {<span class="number">0</span>};</span><br><span class="line"> <span class="type">char</span> s1[]={<span class="string">" "</span>};<span class="comment">// 为了name与置信度之间加空格</span></span><br><span class="line"> <span class="type">int</span> <span class="class"><span class="keyword">class</span> =</span> <span class="number">-1</span>;</span><br><span class="line"> <span class="type">char</span> possible[<span class="number">5</span>];<span class="comment">// 存放检测的置信值</span></span><br><span class="line"> <span class="keyword">for</span>(j = <span class="number">0</span>; j < classes; ++j)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">sprintf</span>(possible,<span class="string">"%.2f"</span>,dets[i].prob[j]);<span class="comment">//置信值截取小数点后两位赋给possible</span></span><br><span class="line"> <span class="keyword">if</span> (dets[i].prob[j] > thresh)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (class < <span class="number">0</span>) </span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">strcat</span>(labelstr, names[j]);</span><br><span class="line"> <span class="built_in">strcat</span>(labelstr, s1); <span class="comment">//加空格</span></span><br><span class="line"> <span class="built_in">strcat</span>(labelstr, possible);<span class="comment">//标签中加入置信值</span></span><br><span class="line"> <span class="class"><span class="keyword">class</span> =</span> j;</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">strcat</span>(labelstr, <span class="string">", "</span>);</span><br><span class="line"> <span class="built_in">strcat</span>(labelstr, names[j]);</span><br><span class="line"> <span class="built_in">strcat</span>(labelstr, s1);<span class="comment">//加空格</span></span><br><span class="line"> <span class="built_in">strcat</span>(labelstr, possible);<span class="comment">//标签中加入置信值</span></span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s: %.0f%%\n"</span>, names[j], dets[i].prob[j]*<span class="number">100</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">} </span><br></pre></td></tr></table></figure>
<p>单张图像检测命令</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">./darknet detector test ./cfg/ct.data ./cfg/ct_test.cfg ct_final.weights test.jpg</span><br></pre></td></tr></table></figure>
<h2 id="批量检测图像"><a href="#批量检测图像" class="headerlink" title="批量检测图像"></a>批量检测图像</h2><p>首先,修改example/detector.c文件,在开头添加一个获取图片名字的函数:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">GetFilename</span><span class="params">(<span class="type">char</span> *p)</span></span><br><span class="line">{ </span><br><span class="line"> <span class="type">static</span> <span class="type">char</span> name[<span class="number">50</span>]={<span class="string">""</span>};</span><br><span class="line"> <span class="type">char</span> *q = <span class="built_in">strrchr</span>(p,<span class="string">'/'</span>) + <span class="number">1</span>;</span><br><span class="line"> <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>(q[i] != <span class="string">'\0'</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(q[i] == <span class="string">'.'</span>) <span class="keyword">break</span>;</span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">strncpy</span>(name,q,i);<span class="comment">// i是图片名的长度</span></span><br><span class="line"> name[i] = <span class="string">'\0'</span>;</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在这里,为了对不同长度的文件名能够兼容处理,设置name数组长度为50,可以根据需要修改。<br>然后,替换examples/detector.c 中的test_detector函数:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">test_detector</span><span class="params">(<span class="type">char</span> *datacfg, <span class="type">char</span> *cfgfile, <span class="type">char</span> *weightfile, <span class="type">char</span> *filename, <span class="type">float</span> thresh, <span class="type">float</span> hier_thresh, <span class="type">char</span> *outfile, <span class="type">int</span> fullscreen)</span></span><br><span class="line">{</span><br><span class="line"> <span class="built_in">list</span> *options = read_data_cfg(datacfg);</span><br><span class="line"> <span class="type">char</span> *name_list = option_find_str(options, <span class="string">"names"</span>, <span class="string">"data/names.list"</span>);</span><br><span class="line"> <span class="type">char</span> **names = get_labels(name_list);</span><br><span class="line"> </span><br><span class="line"> image **alphabet = load_alphabet();</span><br><span class="line"> network *net = load_network(cfgfile, weightfile, <span class="number">0</span>);</span><br><span class="line"> set_batch_network(net, <span class="number">1</span>);</span><br><span class="line"> srand(<span class="number">2222222</span>);</span><br><span class="line"> <span class="type">double</span> time;</span><br><span class="line"> <span class="type">char</span> buff[<span class="number">256</span>];</span><br><span class="line"> <span class="type">char</span> *input = buff;</span><br><span class="line"> <span class="type">float</span> nms=<span class="number">.45</span>;</span><br><span class="line"> <span class="type">int</span> i=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>){</span><br><span class="line"> <span class="keyword">if</span>(filename){</span><br><span class="line"> <span class="built_in">strncpy</span>(input, filename, <span class="number">256</span>);</span><br><span class="line"> image im = load_image_color(input,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line"> image sized = letterbox_image(im, net->w, net->h);</span><br><span class="line"> layer l = net->layers[net->n<span class="number">-1</span>];</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="type">float</span> *X = sized.data;</span><br><span class="line"> time=what_time_is_it_now();</span><br><span class="line"> network_predict(net, X);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s: Predicted in %f seconds.\n"</span>, input, what_time_is_it_now()-time);</span><br><span class="line"> <span class="type">int</span> nboxes = <span class="number">0</span>;</span><br><span class="line"> detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, <span class="number">0</span>, <span class="number">1</span>, &nboxes);</span><br><span class="line"> <span class="keyword">if</span> (nms) do_nms_sort(dets, nboxes, l.classes, nms);</span><br><span class="line"> draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);</span><br><span class="line"> free_detections(dets, nboxes);</span><br><span class="line"> <span class="keyword">if</span>(outfile)</span><br><span class="line"> {</span><br><span class="line"> save_image(im, outfile);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> save_image(im, <span class="string">"predictions"</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> OPENCV</span></span><br><span class="line"> cvNamedWindow(<span class="string">"predictions"</span>, CV_WINDOW_NORMAL); </span><br><span class="line"> <span class="keyword">if</span>(fullscreen){</span><br><span class="line"> cvSetWindowProperty(<span class="string">"predictions"</span>, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);</span><br><span class="line"> }</span><br><span class="line"> show_image(im, <span class="string">"predictions"</span>,<span class="number">0</span>);</span><br><span class="line"> cvWaitKey(<span class="number">0</span>);</span><br><span class="line"> cvDestroyAllWindows();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"> free_image(im);</span><br><span class="line"> free_image(sized);</span><br><span class="line"> <span class="keyword">if</span> (filename) <span class="keyword">break</span>;</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Enter Image Path: "</span>);</span><br><span class="line"> fflush(<span class="built_in">stdout</span>);</span><br><span class="line"> input = fgets(input, <span class="number">256</span>, <span class="built_in">stdin</span>);</span><br><span class="line"> <span class="keyword">if</span>(!input) <span class="keyword">return</span>;</span><br><span class="line"> strtok(input, <span class="string">"\n"</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">list</span> *plist = get_paths(input);</span><br><span class="line"> <span class="type">char</span> **paths = (<span class="type">char</span> **)list_to_array(plist);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Start Testing!\n"</span>);</span><br><span class="line"> <span class="type">int</span> m = plist->size;</span><br><span class="line"> <span class="keyword">if</span>(access(<span class="string">"/home/lzm/data/test_folder/darknet/car_person/out"</span>,<span class="number">0</span>)==<span class="number">-1</span>)<span class="comment">//"/homelzm/......"修改成自己要保存图片的的路径</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (mkdir(<span class="string">"/home/lzm/data/test_folder/darknet/car_person/out"</span>,<span class="number">0777</span>))<span class="comment">//"/homelzm/......"修改成自己要保存图片的的路径</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"creat folder failed!!!"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(i = <span class="number">0</span>; i < m; ++i){</span><br><span class="line"> <span class="type">char</span> *path = paths[i];</span><br><span class="line"> image im = load_image_color(path,<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line"> image sized = letterbox_image(im, net->w, net->h);</span><br><span class="line"> <span class="comment">//image sized = resize_image(im, net->w, net->h);</span></span><br><span class="line"> <span class="comment">//image sized2 = resize_max(im, net->w);</span></span><br><span class="line"> <span class="comment">//image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);</span></span><br><span class="line"> <span class="comment">//resize_network(net, sized.w, sized.h);</span></span><br><span class="line"> layer l = net->layers[net->n<span class="number">-1</span>];</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="type">float</span> *X = sized.data;</span><br><span class="line"> time=what_time_is_it_now();</span><br><span class="line"> network_predict(net, X);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Try Very Hard:"</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s: Predicted in %f seconds.\n"</span>, path, what_time_is_it_now()-time);</span><br><span class="line"> <span class="type">int</span> nboxes = <span class="number">0</span>;</span><br><span class="line"> detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, <span class="number">0</span>, <span class="number">1</span>, &nboxes);</span><br><span class="line"> <span class="comment">//printf("%d\n", nboxes);</span></span><br><span class="line"> <span class="comment">//if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);</span></span><br><span class="line"> <span class="keyword">if</span> (nms) do_nms_sort(dets, nboxes, l.classes, nms);</span><br><span class="line"> draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);</span><br><span class="line"> free_detections(dets, nboxes);</span><br><span class="line"> <span class="keyword">if</span>(outfile){</span><br><span class="line"> save_image(im, outfile);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> </span><br><span class="line"> <span class="type">char</span> b[<span class="number">2048</span>];</span><br><span class="line"> <span class="built_in">sprintf</span>(b,<span class="string">"/home/lzm/data/test_folder/darknet/car_person/out/%s"</span>,GetFilename(path));<span class="comment">//"/homelzm/......"修改成自己要保存图片的的路径</span></span><br><span class="line"> </span><br><span class="line"> save_image(im, b);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"OJBK!\n"</span>,GetFilename(path));</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> OPENCV</span></span><br><span class="line"> cvNamedWindow(<span class="string">"predictions"</span>, CV_WINDOW_NORMAL); </span><br><span class="line"> <span class="keyword">if</span>(fullscreen){</span><br><span class="line"> cvSetWindowProperty(<span class="string">"predictions"</span>, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);</span><br><span class="line"> }</span><br><span class="line"> show_image(im, <span class="string">"predictions"</span>,<span class="number">0</span>);</span><br><span class="line"> cvWaitKey(<span class="number">0</span>);</span><br><span class="line"> cvDestroyAllWindows();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> free_image(im);</span><br><span class="line"> free_image(sized);</span><br><span class="line"> <span class="keyword">if</span> (filename) <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>最后,在命令行输入make,更新文件。<br>批量检测命令,输入的路径为那些图片路径的txt。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">./darknet detector test ./cfg/ct.data ./cfg/ct_test.cfg ct_final.weights</span><br></pre></td></tr></table></figure>
<h2 id="保存批量检测结果为txt文件"><a href="#保存批量检测结果为txt文件" class="headerlink" title="保存批量检测结果为txt文件"></a>保存批量检测结果为txt文件</h2><p>YOLOv3有自带的命令进行这个操作。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">./darknet detector valid ./cfg/ct.data ./cfg/ct_test.cfg ct_final.weights results</span><br></pre></td></tr></table></figure>
<h2 id="计算recall"><a href="#计算recall" class="headerlink" title="计算recall"></a>计算recall</h2><p>修改examples/detector.c的validate_detector_recall函数。<br>首先,将validate_detector_recall函数定义和调用修改如下:</p>
<blockquote>
<p>void validate_detector_recall(char *datacfg, char *cfgfile, char *weightfile)<br>validate_detector_recall(datacfg, cfg, weights);</p>
</blockquote>
<p>然后,将如下内容:</p>
<blockquote>
<p>list *plist = get_paths(“data/coco_val_5k.list”);<br>char **paths = (char **)list_to_array(plist);</p>
</blockquote>
<p>修改成</p>
<blockquote>
<p>list *options = read_data_cfg(datacfg);<br>char *valid_images = option_find_str(options, “valid”, “data/train.list”);<br>list *plist = get_paths(valid_images);<br>char **paths = (char **)list_to_array(plist);</p>
</blockquote>
<p>最后,记得make。<br>使用YOLOv3的命令调用方式。</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">./darknet detector recall ./cfg/ct.data ./cfg/ct_test.cfg ct_final.weights</span><br></pre></td></tr></table></figure>
<h2 id="计算mAP"><a href="#计算mAP" class="headerlink" title="计算mAP"></a>计算mAP</h2><p>需要用到PascalVOC(xml)格式的注释,可以用文章开始提到的代码<a href="https://github.com/LU-K-Brant/yolov3_modify/blob/master/txt2xml.py">txt2xml.py</a>进行转换。<br>可以先借助py-faster-rcnn下的<a href="https://github.com/LU-K-Brant/yolov3_modify/blob/master/voc_eval.py">voc_eval.py</a>计算出单个类别的AP,然后求平均得到mAP。<br>新建一个<a href="https://github.com/LU-K-Brant/yolov3_modify/blob/master/all_map.py">all_map.py</a>文件用于计算mAP,这边提供了别的博主的一个例子。<br>如果需要重复计算mAP,需要删除生成的annots.pkl。</p>
<p><strong>参考</strong><br><a href="https://www.cnblogs.com/luzeming/p/10657823.html">YOLOv3:训练自己的数据(附优化与问题总结)</a><br><a href="https://github.com/yehengchen/Object-Detection-and-Tracking/tree/master/OneStage/yolo/yolov3">How to train YOLOv3 model</a><br><a href="https://www.cnblogs.com/xieqi/p/9818056.html">YOLO-V3实战(darknet)</a></p>
]]></content>
</entry>
<entry>
<title></title>
<url>/2023/04/09/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E9%93%BE%E8%A1%A8%E6%9F%A5%E6%94%B9%E5%A2%9E%E5%88%A0/</url>
<content><![CDATA[<p>@<a href="LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%E2%80%94%E2%80%94%E9%93%BE%E8%A1%A8%E6%9F%A5%E6%94%B9%E5%A2%9E%E5%88%A0">TOC</a></p>
<h1 id="第一题"><a href="#第一题" class="headerlink" title="第一题"></a>第一题</h1><p><a href="https://leetcode.cn/problems/design-linked-list/">707. 设计链表 - 力扣(LeetCode)</a></p>
<h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyLinkedList</span>:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line"> self.dummy = ListNode(-<span class="number">1</span>)</span><br><span class="line"> self.size = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">get</span>(<span class="params">self, index: <span class="built_in">int</span></span>) -> <span class="built_in">int</span>:</span><br><span class="line"> <span class="keyword">if</span> index < <span class="number">0</span> <span class="keyword">or</span> index >= self.size:</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span></span><br><span class="line"></span><br><span class="line"> cur = self.dummy.<span class="built_in">next</span></span><br><span class="line"> i = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> i < index:</span><br><span class="line"> cur = cur.<span class="built_in">next</span></span><br><span class="line"> i += <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> cur.val</span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">addAtHead</span>(<span class="params">self, val: <span class="built_in">int</span></span>) -> <span class="literal">None</span>:</span><br><span class="line"> self.addAtIndex(<span class="number">0</span>, val)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">addAtTail</span>(<span class="params">self, val: <span class="built_in">int</span></span>) -> <span class="literal">None</span>:</span><br><span class="line"> self.addAtIndex(self.size, val)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">addAtIndex</span>(<span class="params">self, index: <span class="built_in">int</span>, val: <span class="built_in">int</span></span>) -> <span class="literal">None</span>:</span><br><span class="line"> <span class="keyword">if</span> index < <span class="number">0</span>:</span><br><span class="line"> index = <span class="number">0</span></span><br><span class="line"> <span class="keyword">elif</span> index > self.size:</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"></span><br><span class="line"> pre = self.dummy</span><br><span class="line"> i = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> i < index:</span><br><span class="line"> pre = pre.<span class="built_in">next</span></span><br><span class="line"> i += <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> pre.<span class="built_in">next</span> = ListNode(val, pre.<span class="built_in">next</span>)</span><br><span class="line"> self.size += <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">deleteAtIndex</span>(<span class="params">self, index: <span class="built_in">int</span></span>) -> <span class="literal">None</span>:</span><br><span class="line"> <span class="keyword">if</span> index < <span class="number">0</span> <span class="keyword">or</span> index >= self.size:</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"></span><br><span class="line"> pre = self.dummy</span><br><span class="line"> i = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> i < index:</span><br><span class="line"> pre = pre.<span class="built_in">next</span></span><br><span class="line"> i += <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> pre.<span class="built_in">next</span> = pre.<span class="built_in">next</span>.<span class="built_in">next</span></span><br><span class="line"> self.size -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span></span><br></pre></td></tr></table></figure>
<h1 id="第二题"><a href="#第二题" class="headerlink" title="第二题"></a>第二题</h1><p><a href="https://leetcode.cn/problems/middle-of-the-linked-list/">876. 链表的中间结点 - 力扣(LeetCode)</a></p>
<h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">middleNode</span>(<span class="params">self, head: <span class="type">Optional</span>[ListNode]</span>) -> <span class="type">Optional</span>[ListNode]:</span><br><span class="line"> slow = fast = head</span><br><span class="line"> <span class="keyword">while</span> fast <span class="keyword">and</span> fast.<span class="built_in">next</span>:</span><br><span class="line"> fast = fast.<span class="built_in">next</span>.<span class="built_in">next</span></span><br><span class="line"> slow = slow.<span class="built_in">next</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> slow</span><br></pre></td></tr></table></figure>
<h1 id="第三题"><a href="#第三题" class="headerlink" title="第三题"></a>第三题</h1><p><a href="https://leetcode.cn/problems/remove-linked-list-elements/">203. 移除链表元素 - 力扣(LeetCode)</a></p>
<h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">removeElements</span>(<span class="params">self, head: <span class="type">Optional</span>[ListNode], val: <span class="built_in">int</span></span>) -> <span class="type">Optional</span>[ListNode]:</span><br><span class="line"> dummy = ListNode(-<span class="number">1</span>, head)</span><br><span class="line"> cur = dummy</span><br><span class="line"> <span class="keyword">while</span> cur.<span class="built_in">next</span>:</span><br><span class="line"> <span class="keyword">if</span> cur.<span class="built_in">next</span>.val == val:</span><br><span class="line"> cur.<span class="built_in">next</span> = cur.<span class="built_in">next</span>.<span class="built_in">next</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> cur = cur.<span class="built_in">next</span></span><br><span class="line"> <span class="keyword">return</span> dummy.<span class="built_in">next</span></span><br></pre></td></tr></table></figure>
<h1 id="第四题"><a href="#第四题" class="headerlink" title="第四题"></a>第四题</h1><p><a href="https://leetcode.cn/problems/remove-duplicates-from-sorted-list/">83. 删除排序链表中的重复元素 - 力扣(LeetCode)</a></p>
<h3 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h3><p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">deleteDuplicates</span>(<span class="params">self, head: <span class="type">Optional</span>[ListNode]</span>) -> <span class="type">Optional</span>[ListNode]:</span><br><span class="line"> dummy = ListNode(-<span class="number">101</span>, head)</span><br><span class="line"> cur = dummy</span><br><span class="line"> <span class="keyword">while</span> cur.<span class="built_in">next</span>:</span><br><span class="line"> <span class="keyword">if</span> cur.val == cur.<span class="built_in">next</span>.val:</span><br><span class="line"> cur.<span class="built_in">next</span> = cur.<span class="built_in">next</span>.<span class="built_in">next</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> cur = cur.<span class="built_in">next</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> dummy.<span class="built_in">next</span></span><br></pre></td></tr></table></figure>
<h1 id="第五题"><a href="#第五题" class="headerlink" title="第五题"></a>第五题</h1><p><a href="https://leetcode.cn/problems/remove-nth-node-from-end-of-list/">19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)</a></p>
<h3 id="代码-4"><a href="#代码-4" class="headerlink" title="代码"></a>代码</h3><p>python版本</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">removeNthFromEnd</span>(<span class="params">self, head: <span class="type">Optional</span>[ListNode], n: <span class="built_in">int</span></span>) -> <span class="type">Optional</span>[ListNode]:</span><br><span class="line"> dummy = ListNode(-<span class="number">1</span>, head)</span><br><span class="line"> slow = fast = dummy</span><br><span class="line"></span><br><span class="line"> i = <span class="number">0</span></span><br><span class="line"> <span class="keyword">while</span> i < n:</span><br><span class="line"> fast = fast.<span class="built_in">next</span></span><br><span class="line"> i += <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> fast.<span class="built_in">next</span>:</span><br><span class="line"> fast = fast.<span class="built_in">next</span></span><br><span class="line"> slow = slow.<span class="built_in">next</span></span><br><span class="line"></span><br><span class="line"> slow.<span class="built_in">next</span> = slow.<span class="built_in">next</span>.<span class="built_in">next</span></span><br><span class="line"> <span class="keyword">return</span> dummy.<span class="built_in">next</span></span><br></pre></td></tr></table></figure>
]]></content>
</entry>
<entry>
<title>“How the economic machine works”观后感</title>
<url>/2021/04/25/how%20the%20economic%20machine%20works/</url>
<content><![CDATA[<h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>不同于传统复杂的经济模型,Ray Dalio总结出一个简单易懂的经济模型,包括经济运行的三种规模、四类个体和三股动力。此外,Ray Dalio还给出避免陷入经济困境的三条经验法则。</p>
<span id="more"></span>
<h1 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h1><p>大家都听过一句话,经济基础决定上层建筑。<!--这一句过渡有点不自然。-->那么这里的“经济”是如何运行的呢?有很多经济学著作已经给出了答案,无论是西方经济学,抑或是社会主义经济学。<!--这里举几个例子。-->但是这些经济学著作,无一不长篇大论,让人一时难以摸到门槛。那么能不能用一个简单易懂的模型,来描述经济的运行呢?</p>
<p>在视频“How the economic machine works”中,Ray Dalio用30分钟描绘出一个简单易懂的经济模型。<!--Ray Dalio,2020年福布斯富豪排行榜第46位,身价180亿美元。-->在Ray Dalio的经济模型中,根据对经济运行起作用的时间范围,经济运行可以看作由三股动力支持:生产率、短期债务周期和长期债务周期。为了更细致地介绍,Ray Dalio将经济运行分为三种规模:交易、市场和经济。按照在经济中所起的作用不同,经济中的主体可以分成四类:个体、企业、银行和政府。在三股动力的共同影响下,不同主体在各种规模的经济活动中作出反应,经济机器便不停地运行起来。</p>
<h1 id="Ray-Dalio的经济模型"><a href="#Ray-Dalio的经济模型" class="headerlink" title="Ray Dalio的经济模型"></a>Ray Dalio的经济模型</h1><h2 id="经济运行的三种规模"><a href="#经济运行的三种规模" class="headerlink" title="经济运行的三种规模"></a>经济运行的三种规模</h2><h3 id="交易"><a href="#交易" class="headerlink" title="交易"></a>交易</h3><p>我们先来假设最简单的一种经济运行——只有买方和卖方两个人参与的经济运行。买方提供货币或信贷,卖方提供商品、服务或金融资产,如此便完成了一次交易。这里,货币和信贷也称为支出总额,商品、服务和金融资产称为产销总量,支出总额/产销总量=价格。一个人走进了一间酒吧,要了一杯啤酒,留下了十块钱,那这个人和酒吧老板就完成了一次交易。可见,交易是规模最小、情况最简单的经济运行。</p>
<h3 id="市场"><a href="#市场" class="headerlink" title="市场"></a>市场</h3><p>当交易某一种商品(广义,包括服务和金融资产)的所有买方和卖方聚集在一起,就形成了市场。例如,炎炎夏日的一个公园里,所有卖冰淇淋的商贩和买冰淇淋的小屁孩,就构成了一个小小的冰淇淋市场。<!--如果没有垄断的话,那他们就是一个自由市场。--></p>
<h3 id="经济"><a href="#经济" class="headerlink" title="经济"></a>经济</h3><p>当我们把所有市场中的全部交易都考虑进来,那么我们所谈论的就是经济。</p>
<h2 id="经济运行的四类个体"><a href="#经济运行的四类个体" class="headerlink" title="经济运行的四类个体"></a>经济运行的四类个体</h2><p>按照在经济中所起的作用不同,经济中的主体大致可以分成四类:个体、企业、银行和政府。</p>
<h3 id="个体"><a href="#个体" class="headerlink" title="个体"></a>个体</h3><p>每一个普通人,都是经济运行中的个体。正如前文所提到的,买啤酒的人和买冰淇淋的小朋友,他们是经济运行中的个体。</p>
<h3 id="企业"><a href="#企业" class="headerlink" title="企业"></a>企业</h3><p>企业的职能是组织工人进行生产和销售。</p>
<h3 id="银行"><a href="#银行" class="headerlink" title="银行"></a>银行</h3><p>银行的职能是储蓄和贷款。</p>
<h3 id="政府"><a href="#政府" class="headerlink" title="政府"></a>政府</h3><p>在这里,Ray Dalio将政府又进一步细分成了中央政府和中央银行。中央政府的职能是收税、发行国债和发放救助金。中央银行的职能是调控利率和印发钞票。</p>
<h2 id="经济运行的三股动力"><a href="#经济运行的三股动力" class="headerlink" title="经济运行的三股动力"></a>经济运行的三股动力</h2><h3 id="生产率"><a href="#生产率" class="headerlink" title="生产率"></a>生产率</h3><p>让我们再次将目光聚焦于一场交易中。</p>
<p>我们先考虑交易中的卖方。我们假定卖方所出售的商品由卖方生产,那么商品的数量多少与质量好坏,只取决于卖方的生产率。如果卖方的生产率高,那么卖方就能生产出高于市场平均水平的商品,也就能获得高于市场平均水平的收入。</p>
<p>我们再来考虑交易中的买方。我们假定买方所用于购买商品的货币只来自收入(这里不考虑信贷),那么参考上面卖方的情况我们可以得知,买方可用于购买商品的货币多少,也只取决于买方的生产率。如果买方的生产率高,那么买方就能获得高于市场平均水平的收入,也就能购买高于市场平均水平的商品。</p>
<p>综上所述,在这种情况下,一个人的支出只取决于一个人的收入,而一个人的收入又只取决于他的生产率。要想提高生产率,就只有不断改进生产工艺、提高生产效率,这需要长时间的积累沉淀。所以,生产率是推动经济运行最长期、最根本的动力。</p>
<h3 id="短期债务周期"><a href="#短期债务周期" class="headerlink" title="短期债务周期"></a>短期债务周期</h3><p>我们现在考虑信贷对交易双方的影响。</p>
<p>在交易中的买方,通过信贷的方式获得了更多的货币。现在他能够购买商品的支出=收入+信贷,也就是他的支出能够大于收入。一个人的支出是另一个人的收入,买方的支出增加会让卖方的收入增加。支出-收入的链式法则不断传播,信贷的放大效应继续扩大,交易活动变得越来越多。在短时间内,有信贷的经济运行在只依赖生产率提高的经济运行更加活泼。</p>
<p>为什么是短时间内呢?因为出来混,总是要还的。在这个阶段你通过信贷的方式,使得支出能够超过收入,那么在下一个阶段偿还信贷时,你的支出必定会小于收入。在这一借一还之间,短期债务周期就产生了。</p>
<p>我们再来看看信贷对整个经济的影响。</p>
<p>我们之前说过,支出总额是由货币和信贷构成的。当信贷增加,那么整个市场的支出总额增加,在产销总量跟不上的情况下(要知道,生产出一个实实在在的商品可是要花时间的,短时间内不可能产量爆炸增长),价格就会飞升,我们称之为通货膨胀。此时就需要中央银行出手,上调利率,使得借债成本上升,那么信贷的数量就会下降,整个市场中流通的钱又会减少,价格回到正常的位置。</p>
<p>反过来,如果信贷减少,整个市场的支出总额减少,而产销总量却在上升(商品生产的变化可是比较慢的哟,不能说增产就增产,说减产就减产),那么价格就会骤降,我们称之为通货紧缩。此时又到了中央银行出手的时候,下调利率,使得借债成本下降,那么信贷的数量就会上升,整个市场中流通的钱又会增加,价格回到正常的位置。</p>
<p>在短期债务周期中,整个过程主要由中央银行控制,通过控制利率来调控信贷数量,经济增长的速度取决于信贷数量的多少。</p>
<p>既然如此,通胀的时候上调利率,通缩的时候下调利率,为什么还会有长期债务周期呢?这是由人的天性决定的。当一个人开始借钱之后,他就会倾向于借更多的钱,久而久之就会积累出难以偿还的债务,也就形成了长期债务周期。</p>
<p>但是请注意,这并不是说信贷不好。在之前已经说了,相比较只依赖生产率提高的经济运行,信贷能够在一段时间内促进经济发展。特别是。当你将信贷用于购买促进生产率提高的商品时,你的信贷会给你带来收入,使得你有能力偿还信贷,那么这一切就是良性的。可是,如果你将信贷用于购买满足消费欲望的商品,并且不断举债以丰富物质生活,那么你必然要面对难以承受的后果。</p>
<h3 id="长期债务周期"><a href="#长期债务周期" class="headerlink" title="长期债务周期"></a>长期债务周期</h3><p>人们在不断的借债过程中,发现用借来的钱进行投资是很不错的选择,于是金融资产的价格不断攀升,由此也就产生了“泡沫”。越来越多的人开始借越来越多的钱,越来越多的钱开始涌入越来越多的金融资产,越来越多的金融资产开始变得越来越值钱,世界经济一片欣欣向荣。</p>
<p>这一切都很美好,不是吗?是的,如果借钱不用还的话,这一切的确是很美好!</p>
<p>当人们借的钱越来越多,已经到了没办法拆东墙补西墙的时候,开始减少支出、出售金融资产以偿还债务。这里再一次强调,一个人的支出是另一个人的收入。当人们减少支出,经济活动开始减弱;当人们减少购买甚至出售金融资产时,金融资产的价格就会不断下跌。而当所有的个体、企业、银行和政府,都背负着极高的债务需要偿还时,经济萧条就在眼前。</p>
<p>那么我们可不可以采取在短期债务周期中使用过的办法,通过中央银行下调利率,让信贷增加,以此促进经济呢?答案是,不可以。因为在经历过多个短期债务周期后,利率已经处于极低的水平(不然怎么大家借的钱越来越多呢?);而且极高的债务负担削弱了借贷的欲望(有钱的不敢借出,没钱的也不敢借入,大家都怕还不上钱)。这个时候,我们就需要其他手段解决问题,我们称之为“去杠杆化”。</p>
<p>“去杠杆化”的办法总的来说有四种:削减支出、减少债务、财富再分配和发行货币。</p>
<p>削减支出,让收入尽可能多地用来偿还债务,那么不就可以减轻债务负担了吗?这个听上去很不错,但是不要忘记了,一个人的支出是另一个人的收入。当整个社会都背负高债务负担时,如果大家都选择削减支出,那么经济活动就会大量减少,市场上流通的钱减少,通货紧缩又一次形成了。</p>
<p>减少债务,让还款的时间延迟,或下调还款的利息,能不能解决问题呢?听上去很有道理,既然大家背负很重的债务负担还不起,那么大家能不能妥协一下,迟还或者少还一点。这里又遇到了和“削减支出”类似的问题,信贷是支出的重要组成部分,当信贷还款减少了,就意味着有人的收入减少了,市场上的流通的钱减少,通货紧缩又一次形成了。</p>
<p>既然问题出在钱减少了,那么我们找出更多的钱不就可以了?谁有更多的钱呢,很自然的,有钱人会有更多的钱。财富再分配,就是指中央政府(想想中央政府的职能)向有钱人征收更多的税,用以发放救助金和开展基建项目。可是当整个社会背负极高的债务负担时,地主家也没有多少余粮啊。有钱的企业家们,不仅要面对经济下行带来的影响(生意不好做),还要被中央政府收一笔税,他们的日子也不好过,经济会继续下行,带来通货紧缩。</p>
<p>哪里还能找到更多的钱呢,或者说,如何产生更多的钱?中央银行的一项重要职能就是印发钞票。只要让中央银行开动印钞机,就能源源不断地产生钱啦。用中央银行印出来的钞票,购买中央政府发行的国债(所以货币也可以看作是政府的信用),相当于把多出来的钱交到了中央政府手里,那么中央政府就有钱发放救助金和开展基建项目。就这样,凭空产生的钱就送到了大家的手上,大家可以用来偿还债务和购买商品。但是货币增长过快,超出了商品增长的速度,价格就会飞涨,带来通货膨胀。</p>
<p>“去杠杆化”的四种办法,前三种办法会导致通货紧缩,第四种办法会带来通货膨胀。只要我们能够合理利用这四种办法,平衡通缩和通胀,就能实现和谐的“去杠杆化”。“去杠杆化”的核心在于,要让收入的增长大于债务的增长,从而消化掉整个社会的高负债。在这个过程中,既不能形成严重的通胀,也不能形成严重的通缩。</p>
<p>纵观整个长期债务周期,“杠杆化”的时间大概是50年左右,其中由多个短期债务周期构成,整个社会都在不断举债消费;而萧条期大概持续2至3年,长期积累的债务危机爆发了;要想消化掉这一波债务,恢复到以前的经济水平,大概需要7到10年的“再膨胀”。从萧条到再膨胀,就是人们常说的“失去的十年”。</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>在最后,Ray Dalio给出了自己应对经济运行的三条经验法则。</p>
<p>经验一,不要让债务增长超过收入增长,否则无法偿还的债务会压垮你。</p>
<p>经验二,不要让收入增长超过生产率增长,否则你会在工作中失去竞争力。</p>
<p>经验三,尽一切努力提高生产率,因为长期来看生产率起决定作用。</p>
]]></content>
<categories>
<category>观/读后感</category>
</categories>
<tags>
<tag>经济</tag>
<tag>Ray Dalio</tag>
</tags>
</entry>
<entry>
<title></title>
<url>/2023/04/09/mac%E6%89%93%E5%BC%80%E7%BD%91%E9%A1%B5%E9%80%9F%E5%BA%A6%E7%89%B9%E5%88%AB%E6%85%A2/</url>
<content><![CDATA[<p><strong>问题描述</strong>:用MacBook Pro笔记本电脑,确定连接了网络,其他应用上网也没问题,就是浏览器打开网页的速度特别慢。换各种浏览器safari,firefox,chorme等打开网页都很慢。<br><strong>解决方案</strong>:不是电脑硬件的问题,不是网络连接的问题,那应该就是网络配置的问题了。<br><img src="https://img-blog.csdnimg.cn/20201026194145448.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70#pic_center" alt="系统偏好设置-网络"></p>
<p>打开系统偏好设置,点击网络,在上方的“位置”,选择“编辑位置”,编辑一个“家”。立马解决问题。</p>
<p><strong>参考</strong>:<br><a href="https://www.zhihu.com/question/24732601">mac打开网页速度特别慢?</a></p>
]]></content>
</entry>
<entry>
<title>全国第四轮学科评估结果查询</title>
<url>/2023/04/09/%E5%85%A8%E5%9B%BD%E7%AC%AC%E5%9B%9B%E8%BD%AE%E5%AD%A6%E7%A7%91%E8%AF%84%E4%BC%B0%E7%BB%93%E6%9E%9C%E6%9F%A5%E8%AF%A2/</url>
<content><![CDATA[<p>最近出了高考成绩,有些学弟学妹找我咨询志愿填报的问题。<br>无论是“地域优先论”,还是“学校优先论”,或者是“专业优先论”,我都持平等的看法。<br>读大学,说到底还是对一个人基本素质的培养,其他都是虚的。不过,为了满足学弟学妹们的需要,我也整理了一些资料,提供给大家。</p>
<span id="more"></span>
<p>分享一个<a href="https://souky.eol.cn/api/newapi/assess_result#">全国第四轮学科评估结果查询网址</a>。这个网址可以分专业查看不同大学的排名,或者分大学查看不同专业的排名。</p>
<p>其他资料,收集了再补充。</p>
]]></content>
<categories>
<category>杂谈</category>
</categories>
</entry>
<entry>
<title>为GitHub的私有项目添加合作者</title>
<url>/2023/04/09/%E4%B8%BAGitHub%E7%9A%84%E7%A7%81%E6%9C%89(Private)%E9%A1%B9%E7%9B%AE%E6%B7%BB%E5%8A%A0%E5%90%88%E4%BD%9C%E8%80%85(collaborator)/</url>
<content><![CDATA[<p>当你在GitHub中当仓库设置为private时,对外是不可见的,对方无法从GitHub主页查找你,也无法通过你分享的网址查找你。<br>想要让其他人加入到这个私人项目中,可以添加合作者。</p>
<span id="more"></span>
<p>首先,进入你的私人仓库,找到Settings。<br><img src="https://img-blog.csdnimg.cn/20200731110059523.png" alt="在这里插入图片描述"><br>然后,点击下方左侧的Manage access。<br><img src="https://img-blog.csdnimg.cn/20200731110328741.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>最后,选择右侧的Invite a collaborator。<br><img src="https://img-blog.csdnimg.cn/20200731110624119.png" alt="在这里插入图片描述"><br>添加对方的GitHub账号,然后确定。将邀请链接发给对方,对方打开同意即可。<br><img src="https://img-blog.csdnimg.cn/20200731111017794.png" alt="在这里插入图片描述"><br>合作者可以在Setting的Repositories最底部看到这个仓库。<br><img src="https://img-blog.csdnimg.cn/2020073111240098.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/20200731112707501.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br><strong>参考</strong><br><a href="https://blog.csdn.net/qq_35197701/article/details/106672583">github私有库授权</a><br><a href="https://blog.csdn.net/chenbetter1996/article/details/82871518">GitHub 私人private仓库添加成员(协作者Collaborators)</a></p>
]]></content>
<categories>
<category>计算机技术</category>
</categories>
</entry>
<entry>
<title>如何在word中插入LaTeX公式</title>
<url>/2021/04/29/%E5%A6%82%E4%BD%95%E5%9C%A8word%E4%B8%AD%E6%8F%92%E5%85%A5LaTeX%E5%85%AC%E5%BC%8F/</url>
<content><![CDATA[<h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>很多时候会遇到用LaTeX写好论文,然后要改写到Word中的情况,这个时候公式的处理是一个比较麻烦的事情。有三种办法可以简便地将LaTeX中的公式代码插入到Word中。第一种办法最方便,使用MathType,将LaTeX转成Word公式,可惜要收费。第二种是使用Word2019,可以直接插入LaTeX格式的公式;第三种是将LaTeX转成MathML格式插入Word。</p>
<span id="more"></span>
<h1 id="使用MathType"><a href="#使用MathType" class="headerlink" title="使用MathType"></a>使用MathType</h1><p>因为MathType只给了30天免试用,之后要收费,所以在这里不详细介绍,给出一个官网文章<a href="#refer-anchor-6"><sup>6</sup></a>作为参考。</p>
<h1 id="使用Word2019"><a href="#使用Word2019" class="headerlink" title="使用Word2019"></a>使用Word2019</h1><p>使用Word2019直接插入LaTeX格式的公式。<a href="#refer-anchor-1"><sup>1</sup></a><sup>,</sup><a href="#refer-anchor-2"><sup>2</sup></a></p>
<ol>
<li><p>在Word2019中新建一个文件,Windows系统下按“alt”+“=”插入公式编辑框,macOS系统下按“control”+“=”插入公式编辑框。</p>
</li>
<li><p>在菜单栏选择“插入”、“公式”,选择“{}LaTeX”。</p>
</li>
<li><p>将编辑好的LaTeX代码粘贴到公式编辑框中,按“回车键”。</p>
</li>
<li><p>选中公式,右键,选择“段落”,调整“行距”为“单倍行距”。<a href="#refer-anchor-3"><sup>3</sup></a></p>
</li>
</ol>
<h1 id="使用Mathpix-Snip或latexlive"><a href="#使用Mathpix-Snip或latexlive" class="headerlink" title="使用Mathpix Snip或latexlive"></a>使用Mathpix Snip或latexlive</h1><p>然后我们讲讲第二种方法,如何将LaTeX转成MathML格式的公式插入Word。</p>
<ol>
<li>使用Mathpix Snip<a href="#refer-anchor-4"><sup>4</sup></a>或latexlive<a href="#refer-anchor-5"><sup>5</sup></a>将LaTeX代码转成MathML格式。</li>
<li>在Word2019中新建一个文件,Windows系统下按“alt”+“=”插入公式编辑框,macOS系统下按“control”+“=”插入公式编辑框。</li>
<li>复制MathML格式的代码。以<strong>纯文本</strong>的格式粘贴到公式编辑框中,按“回车键”。</li>
<li>选中公式,右键,选择“段落”,调整“行距”为“单倍行距”。<a href="#refer-anchor-3"><sup>3</sup></a></li>
</ol>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><div id="refer-anchor-1"></div>
<p>[1] <a href="https://cloud.tencent.com/developer/article/1560570">Word2019插入LaTex编码的公式</a></p>
<div id="refer-anchor-2"></div>
<p>[2] <a href="https://www.jianshu.com/p/47152773e53c">如何在word中使用latex语言优雅的编辑数学公式?</a></p>
<div id="refer-anchor-3"></div>
<p>[3] <a href="https://www.jianshu.com/p/17ef28b1be49">在Word中优雅地插入Latex公式</a></p>
<div id="refer-anchor-4"></div>
<p>[4] <a href="https://zhuanlan.zhihu.com/p/137641360">Mathpix Snip 截图识别公式插入 Microsoft Word 中——无需mathtype</a></p>
<div id="refer-anchor-5"></div>
<p>[5] <a href="https://blog.csdn.net/weixin_45026882/article/details/107342524">【LaTeX】公式书写工具 | LaTeX转MathML(Word适用)| 公式截图转LaTeX| LaTeX学习(偏公式输入方面)</a></p>
<div id="refer-anchor-6"></div>
<p>[6] <a href="https://www.mathtype.cn/jiqiao/daima-bianji.html">如何在MathType中用LaTex代码编辑公式</a></p>
]]></content>
<categories>
<category>计算机技术</category>
</categories>
<tags>
<tag>论文写作</tag>
<tag>Word</tag>
<tag>LaTeX</tag>
</tags>
</entry>
<entry>
<title></title>
<url>/2023/04/09/linux%E4%B8%8Btensorflow%E4%B8%8Ecuda%E7%89%88%E6%9C%AC%E4%B8%8D%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98%EF%BC%8CImportError_%20libcublas.so.10.0_%20cannot%20open%20shared%20object%20file/</url>
<content><![CDATA[<p>@<a href="linux%E4%B8%8Btensorflow%E4%B8%8Ecuda%E7%89%88%E6%9C%AC%E4%B8%8D%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98">TOC</a><br>因为跑一个多目标跟踪的代码,要用到yolov3,所以作为pytorch用户的我,第一次用上了tensorflow。<br>但是我使用的镜像环境,是cuda10.1版本的:<br><img src="https://img-blog.csdnimg.cn/20200526222813753.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMjE0NjEw,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"><br>代码使用的tensorflow,是1.13.1版本的;需要将cuda降到10.0。<br>这里有一篇<a href="https://blog.csdn.net/omodao1/article/details/83241074">博客</a>,展示了Tensorflow不同版本要求与CUDA及CUDNN版本对应关系,一般我们都是装好了tensorflow-gpu,然后需要对应版本的CUDA及CUDNN,可以让大家参考一下。</p>
<p>用conda安装对应的cudatoolkit</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">conda install cudatoolkit=10.0 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/linux-64/</span><br></pre></td></tr></table></figure>
<p>用conda安装对应的cudnn</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">conda install cudnn=7.5.0 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/linux-64/</span><br></pre></td></tr></table></figure>
<p>这样每次运行时,会链接到这个版本的cuda和cudnn,实际的cuda版本没有变。</p>
<p>参考链接:<br><a href="https://www.cnblogs.com/sohuhome/p/11704529.html">tf-gpu报错:ImportError: libcublas.so.10.0: cannot open shared object file: No such file or directory</a><br><a href="https://blog.csdn.net/weixin_40588315/article/details/85881338?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase">Ubuntu下使用conda在虚拟环境中安装CUDA、CUDNN及Tensorflow</a><br><a href="https://blog.csdn.net/chr1341901410/article/details/104903016?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase">conda安装cudnn和cudatoolkit</a></p>
]]></content>
</entry>
<entry>
<title>如何批量删除PDF文件中所有注释/高亮</title>
<url>/2022/01/04/%E5%A6%82%E4%BD%95%E6%89%B9%E9%87%8F%E5%88%A0%E9%99%A4PDF%E6%96%87%E4%BB%B6%E4%B8%AD%E6%89%80%E6%9C%89%E6%B3%A8%E9%87%8A:%E9%AB%98%E4%BA%AE/</url>
<content><![CDATA[<h1 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h1><p>有时候我们拿到一份PDF学习资料,发现上面有前人留下的很多注释/高亮,干扰了我们对资料的阅读。对于一条注释/高亮,我们可以选择直接删除;对于多条注释/高亮,我们可以选择全选删除。遗憾的是,直接使用ctrl+A无法全选所有注释/高亮。这里介绍一种方法,使用shift键,只需4步批量删除PDF文件中所有注释/高亮。</p>
<span id="more"></span>
<h2 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h2><ol>
<li>使用Adobe Acrobat打开PDF文件,点击右侧黄色的“注释”功能;</li>
<li>按照时间或类型排序,单击鼠标左键选择需要批量删除的注释/高亮的第一条;</li>
<li>按住shift键,单击鼠标左键选择需要批量删除的注释/高亮的最后一条;</li>
<li>按删除键删除,鼠标右键选择“删除”。</li>
</ol>
<p>以上是从Adobe Support Community找到的答案,在这里给出社区链接<a href="#refer-anchor-1"><sup>1</sup></a><sup>,</sup><a href="#refer-anchor-2"><sup>2</sup></a>作为参考。</p>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><div id="refer-anchor-1"></div>
[1] [How to delete ALL highlighted text in pdf](https://community.adobe.com/t5/acrobat-reader-discussions/how-to-delete-all-highlighted-text-in-pdf/m-p/8361894)
<div id="refer-anchor-2"></div>
[2] [Can I delete all comments on a PDF with one click?](https://community.adobe.com/t5/acrobat-discussions/can-i-delete-all-comments-on-a-pdf-with-one-click/m-p/10472171)]]></content>
<categories>
<category>计算机技术</category>
</categories>
<tags>
<tag>PDF</tag>
</tags>
</entry>
</search>