-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
669 lines (464 loc) · 280 KB
/
atom.xml
File metadata and controls
669 lines (464 loc) · 280 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>mian's blog</title>
<subtitle>这里是mian的博客</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://www.intmian.com/"/>
<updated>2019-11-09T09:06:06.853Z</updated>
<id>https://www.intmian.com/</id>
<author>
<name>mian</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>右值、右值引用、移动语义与完美转发</title>
<link href="https://www.intmian.com/2019/11/08/%E5%8F%B3%E5%80%BC%E5%BC%95%E7%94%A8/"/>
<id>https://www.intmian.com/2019/11/08/右值引用/</id>
<published>2019-11-08T11:00:26.000Z</published>
<updated>2019-11-09T09:06:06.853Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>好久没写c++了,因为最近做的一个工程需要解大规模的有特殊约束条件的线性方程组,库不好使,所以<del>被逼无奈</del>用了c++。又因为对效率要求较高,又想用oo的范式,所以还是免不了要用移动语义这种。而这几个东西我每次用到都要去查一下用法,下次又会忘记,所以我今天彻底理一理。</p><a id="more"></a><h2 id="左值与右值"><a href="#左值与右值" class="headerlink" title="左值与右值"></a>左值与右值</h2><p>设有类<code>A</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">A() {</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"build\n"</span>);</span><br><span class="line">}</span><br><span class="line">~A()</span><br><span class="line">{</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"destroy\n"</span>);</span><br><span class="line">}</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>又有一段代码</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">A a = A{};</span><br></pre></td></tr></table></figure><blockquote><p>这里如果写成<code>A()</code>是有问题的,因为在新标准中这种行为被规范成了构造函数相当于A a()</p></blockquote><p>此处a即为<strong>左值</strong>,<code>A()</code>即为<strong>右值</strong>。</p><p>通俗一点来说左值即在表达式结束后依然存在的值,右值即在表达式结束后自动析构的值。一般情况下,左值在赋值左边,反之反之。或者左值一般有姓名,反之反之。</p><h2 id="左值引用与右值引用"><a href="#左值引用与右值引用" class="headerlink" title="左值引用与右值引用"></a>左值引用与右值引用</h2><h3 id="左值引用"><a href="#左值引用" class="headerlink" title="左值引用"></a>左值引用</h3><p><strong>左值引用</strong>即对于左值的一种引用,是一种变量类型,效果类似于为左值取了一个别名。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">A a;</span><br><span class="line">A& b = a;</span><br></pre></td></tr></table></figure><p>当你修改<code>b</code>时,<code>a</code>也会被修改。</p><p>当左值引用作为参数时,可以避免传参时的参数的拷贝构造与析构,有点类似于指针传参。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">lTest</span><span class="params">(A& a)</span> </span>{</span><br><span class="line"><span class="comment">// do something with a</span></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">pTest</span><span class="params">(A* a)</span> </span>{</span><br><span class="line"><span class="comment">// do something with *a</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="右值引用"><a href="#右值引用" class="headerlink" title="右值引用"></a>右值引用</h3><p><strong>右值引用</strong>即对于右值的一种引用,也是一种变量类型,相当于为右值取一个别名,并将右值的生命周期改为右值引用的作用域,有点类似于将右值转化为左值。例如</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">A&& a = A();</span><br></pre></td></tr></table></figure><p>在下面就可以把<code>a</code>当成普通的`类型值用了。</p><p>右值也可以作为参数传入</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">rTest</span><span class="params">(A&& a)</span> </span>{</span><br><span class="line"><span class="comment">// do something with a</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line">rTest(A())</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>只有当形参为右值时才会触发,一般用于复用<code>a</code>里面的资源(<code>a</code>是右值,会被析构,之后都用不上了,里面的资源<strong>拷贝</strong>一份就浪费了,直接<strong>移动</strong>划算些)。</p><p>有些函数涉及到存储参数里面的资源,就需要区分实参是左值还是右值。</p><p>左值里面的资源因为被用到所以一般函数内拷贝一份。</p><p>右值在作为实参调用完函数后就会被析构,里面的资源也会一起消失。所以就不需要拷贝一份,直接从实参那里移动过来就行。</p><blockquote><p>一般常用于类内有动态分配的资源这种情况。</p></blockquote><p>例如<code>vector</code>的<code>push_back</code>就有两个版本,功能一样,耗时差距很大。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">push_back</span><span class="params">(<span class="keyword">const</span> _Ty& _Val)</span> </span>{ <span class="comment">// insert element at end, provide strong guarantee</span></span><br><span class="line"> emplace_back(_Val);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">push_back</span><span class="params">(_Ty&& _Val)</span> </span>{ <span class="comment">// insert by moving into element at end, provide strong guarantee</span></span><br><span class="line"> emplace_back(_STD move(_Val));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面那个会直接移动走压入的资源,上面那个则是复制一份。当然因为这些函数里面多半涉及移动赋值或者移动构造,所以你的自定义类型应定义这些方法。</p><h2 id="移动构造与移动赋值"><a href="#移动构造与移动赋值" class="headerlink" title="移动构造与移动赋值"></a>移动构造与移动赋值</h2><p>如果你希望你的自定义类型可以在以右值的形式存在时被移动,那么你应该定义<strong>移动构造函数</strong>或<strong>移动赋值函数</strong>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">A(A&& other) {</span><br><span class="line"><span class="comment">// move the resource</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">void</span> <span class="keyword">operator</span>=(A&& other) {</span><br><span class="line"><span class="comment">// move the resource</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>注释中的~基本上等同于浅拷贝,并把被拷贝的指针置空。如果类成员支持移动,那么可以委托构造或直接赋值(需在外面套一个<code>move()</code>)</p></blockquote><p>这样当你的变量以以下形式出现在代码中时,会调用<strong>移动</strong>而非<strong>拷贝</strong>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">A <span class="title">a</span><span class="params">(A{})</span></span>;</span><br><span class="line">A a = A{};</span><br></pre></td></tr></table></figure><h2 id="移动语义"><a href="#移动语义" class="headerlink" title="移动语义"></a>移动语义</h2><p><strong>移动语义</strong>即主动触发移动的一种方法。c++里面的方法是<code>std::move</code>(有些ide会有<code>::move</code>),相当于告诉编辑器虽然我是左值但是请把我当成右值。</p><p>有些时候可以用右值版本的</p><p>例如</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">A a;</span><br><span class="line"><span class="comment">// do something with a</span></span><br><span class="line"><span class="built_in">vector</span><A> as;</span><br><span class="line">a.pushback(a);</span><br><span class="line"><span class="comment">// do other thing without a</span></span><br></pre></td></tr></table></figure><p>这种情况下<code>a</code>在压入<code>as</code>后就不被用到,但是还是调用了左值版的<code>pushback</code>,里面的操作基于拷贝代价高些。</p><blockquote><p>拷贝代价一般高于移动</p></blockquote><p>可以将代码改为</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">A a;</span><br><span class="line"><span class="comment">// do something with a</span></span><br><span class="line"><span class="built_in">vector</span><A> as;</span><br><span class="line">a.pushback(move(a));</span><br><span class="line"><span class="comment">// do other thing without a</span></span><br></pre></td></tr></table></figure><p>这样就好一点。</p><p>还有另外一种用于返回值的情况。</p><blockquote><p>别急着喷我,看完。</p></blockquote><p>例如</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">A <span class="title">f</span><span class="params">()</span> </span>{</span><br><span class="line">A a;</span><br><span class="line"><span class="comment">// do something with a</span></span><br><span class="line"><span class="keyword">return</span> a;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这里面明明<code>a</code>在返回后就会被析构,不存在移动资源而导致不安全的问题,但是还是调用了低效的拷贝,这是不合理的。</p><p>改成</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">A <span class="title">f</span><span class="params">()</span> </span>{</span><br><span class="line">A a;</span><br><span class="line"><span class="comment">// do something with a</span></span><br><span class="line"><span class="keyword">return</span> move(a);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>就会把<code>a</code>当成右值进行处理,那就会调用移动构造函数。</p><blockquote><p>这里没看明白的可以研究下自定义类型的传参与作为返回值的过程</p></blockquote><p>当然,因为这种情况实在是太普遍了,所以在默认情况下编译器会自动进行返回值优化,把上面的代码改成下面的。</p><h2 id="完美转发"><a href="#完美转发" class="headerlink" title="完美转发"></a>完美转发</h2><p>大家应该有留意到右值引用这个类型其实是个左值所以有些时候在函数套函数这种转发的情况下,会丢失右值这一特性,变成左值。</p><p>例如</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span>& i)</span></span>{}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span>&& i)</span></span>{}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">myForward</span><span class="params">(<span class="keyword">int</span>& i)</span></span>{</span><br><span class="line"> f(i);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">myForward</span><span class="params">(<span class="keyword">int</span>&& i)</span></span>{</span><br><span class="line"> f(i);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>你预期的<code>myForward</code>是调用的右值版本的f,但是实际上i作为右值引用,它是左值,调用的是左值版本的<code>f</code>。</p><p>一般的思路也就是</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span>& i)</span></span>{}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span>&& i)</span></span>{}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">myForward</span><span class="params">(<span class="keyword">int</span>& i)</span></span>{</span><br><span class="line"> f(i);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">myForward</span><span class="params">(<span class="keyword">int</span>&& i)</span></span>{</span><br><span class="line"> move(f(i));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="通用引用"><a href="#通用引用" class="headerlink" title="通用引用"></a>通用引用</h3><p>这样确实可以解决问题,可是两个版本的<code>myForward</code>并没有本质性的区别,我们可以通过<strong>通用引用</strong>来实现将两者合一。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span>& i)</span></span>{}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span>&& i)</span></span>{}</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">myForward</span><span class="params">(T&& i)</span></span>{</span><br><span class="line"> f(i);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>当成我们写出这样一个函数时,<code>T&&</code>就是一个通用引用,可以表示<code>int&</code>或<code>int&&</code>。</p><p>但是我们还没有解决问题,<code>i</code>是一个左值,被调用的一定是左值版的f。</p><h3 id="通用引用与完美转发"><a href="#通用引用与完美转发" class="headerlink" title="通用引用与完美转发"></a>通用引用与完美转发</h3><p>这里我们需要将<code>i</code>还原为实参的性质,而<code>move</code>只能把<code>i</code>转换为右值,所以我们需要使用<strong>完美转发</strong>,在c++中的语法是<code>forword<T></code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span>& i)</span></span>{}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span>&& i)</span></span>{}</span><br><span class="line"><span class="keyword">template</span><<span class="keyword">typename</span> T></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">myForward</span><span class="params">(T&& i)</span></span>{</span><br><span class="line"> f(forword<T>(i));</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这样就实现了通用版的<code>myForword</code>了。</p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>虽然我是明白理解概念的,但是想要文辞清楚的将它写出来,还是很困难。</p><p>而且在写完这边文章后,我发现想要搞清楚一个c++的技巧,你就需要搞清楚很多c++隐式的规则,而且组合在一起会形成<code>difficult but simple</code>这样奇怪的东西。c++越来越复杂,特性越来越多,很难说得上是明智,不过历史包袱重也是没办法的事。</p>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>好久没写c++了,因为最近做的一个工程需要解大规模的有特殊约束条件的线性方程组,库不好使,所以<del>被逼无奈</del>用了c++。又因为对效率要求较高,又想用oo的范式,所以还是免不了要用移动语义这种。而这几个东西我每次用到都要去查一下用法,下次又会忘记,所以我今天彻底理一理。</p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="c++" scheme="https://www.intmian.com/tags/c/"/>
</entry>
<entry>
<title>leetcode contest 155 writeup</title>
<link href="https://www.intmian.com/2019/09/23/155/"/>
<id>https://www.intmian.com/2019/09/23/155/</id>
<published>2019-09-23T08:45:50.000Z</published>
<updated>2019-09-23T08:58:46.993Z</updated>
<content type="html"><![CDATA[<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><blockquote><p>比赛链接:<a href="https://leetcode-cn.com/contest/weekly-contest-155" target="_blank" rel="noopener">leetcode第155周周赛</a></p></blockquote><table><thead><tr><th style="text-align:center">题目</th><th style="text-align:center">难度</th><th style="text-align:center">知识点</th></tr></thead><tbody><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-155/problems/minimum-absolute-difference" target="_blank" rel="noopener">最小绝对差</a></td><td style="text-align:center">简单</td><td style="text-align:center">无</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-155/problems/ugly-number-iii" target="_blank" rel="noopener">丑数 III</a></td><td style="text-align:center">中等</td><td style="text-align:center">容斥+二分</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-155/problems/smallest-string-with-swaps" target="_blank" rel="noopener">交换字符串中的元素</a></td><td style="text-align:center">中等</td><td style="text-align:center">并查集</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-155/problems/sort-items-by-groups-respecting-dependencies" target="_blank" rel="noopener">项目管理</a></td><td style="text-align:center">困难</td><td style="text-align:center">拓扑排序</td></tr></tbody></table><a id="more"></a><blockquote><p>注:思路是理想思路,代码有可能是我比赛时写的,就不那么理想.</p><p>所以代码与思路不一定等价</p></blockquote><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><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> typing <span class="keyword">import</span> List</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">minimumAbsDifference</span><span class="params">(self, arr: List[int])</span> -> List[List[int]]:</span></span><br><span class="line"> arr.sort()</span><br><span class="line"> min = arr[<span class="number">1</span>] - arr[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(arr) - <span class="number">1</span>):</span><br><span class="line"> i_ = abs(arr[i + <span class="number">1</span>] - arr[i])</span><br><span class="line"> <span class="keyword">if</span> min > i_:</span><br><span class="line"> min = i_</span><br><span class="line"> re = []</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(len(arr) - <span class="number">1</span>):</span><br><span class="line"> i_ = abs(arr[i + <span class="number">1</span>] - arr[i])</span><br><span class="line"> <span class="keyword">if</span> min == i_:</span><br><span class="line"> re.append([arr[i],arr[i+<span class="number">1</span>]])</span><br><span class="line"> <span class="keyword">return</span> re</span><br><span class="line"></span><br><span class="line">s = Solution()</span><br><span class="line">print(s.minimumAbsDifference([<span class="number">3</span>,<span class="number">8</span>,<span class="number">-10</span>,<span class="number">23</span>,<span class="number">19</span>,<span class="number">-4</span>,<span class="number">-14</span>,<span class="number">27</span>]))</span><br></pre></td></tr></table></figure><h2 id="第二题"><a href="#第二题" class="headerlink" title="第二题"></a>第二题</h2><h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><p>容斥原理加上二分法。容斥法确认范围内有几个丑数。二分法右界设为最大值就行。</p><h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">lcm</span><span class="params">(x, y)</span>:</span></span><br><span class="line"> <span class="comment"># 获取最大的数</span></span><br><span class="line"> <span class="keyword">return</span> x * y / gcd(x, y)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">gcd</span><span class="params">(m, n)</span>:</span></span><br><span class="line"> <span class="keyword">if</span> <span class="keyword">not</span> n:</span><br><span class="line"> <span class="keyword">return</span> m</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> gcd(n, m % n)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">low</span><span class="params">(self, n: int, a: int, b: int, c: int)</span> -> int:</span> <span class="comment"># [1,n]内含有几个丑数</span></span><br><span class="line"> <span class="keyword">return</span> n // a + n // b + n // c - n // lcm(a, b) - n // lcm(a, c) - n // lcm(b, c) + n // lcm(lcm(a, b), c)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">nthUglyNumber</span><span class="params">(self, n: int, a: int, b: int, c: int)</span> -> int:</span></span><br><span class="line"> l = <span class="number">1</span></span><br><span class="line"> r = <span class="number">2</span> * <span class="number">10</span> ** <span class="number">9</span> + <span class="number">1</span></span><br><span class="line"> m = <span class="keyword">None</span></span><br><span class="line"> <span class="keyword">while</span> <span class="keyword">True</span>:</span><br><span class="line"> mid = (l + r) // <span class="number">2</span></span><br><span class="line"> mid_v = self.low(mid, a, b, c)</span><br><span class="line"> <span class="keyword">if</span> mid_v == n:</span><br><span class="line"> m = mid</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> <span class="keyword">if</span> mid_v < n:</span><br><span class="line"> l = mid + <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> r = mid - <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> <span class="keyword">not</span> (self.low(m, a, b, c) == n <span class="keyword">and</span> self.low(m - <span class="number">1</span>, a, b, c) == n - <span class="number">1</span>):</span><br><span class="line"> m -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> m</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">s = Solution()</span><br><span class="line"><span class="comment"># print(s.nthUglyNumber(5, 2, 11, 13))</span></span><br><span class="line">print(s.nthUglyNumber(<span class="number">1000000000</span>,</span><br><span class="line"> <span class="number">2</span>,</span><br><span class="line"> <span class="number">217983653</span>,</span><br><span class="line"> <span class="number">336916467</span>))</span><br></pre></td></tr></table></figure><h2 id="第三题"><a href="#第三题" class="headerlink" title="第三题"></a>第三题</h2><h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><p>首先我们知道如果数组内索引1和2对应的数可以随意调换,索引2和3对应的数可以随意调换的话,那么等价于索引1、2、3对应的数可以任意调换,以此类推。</p><p>也就是我们只需求求出groups最终归并成的集合进行排序即可。</p><p>并查集一把梭(网上的并查集代码没有导出集合,所以我添了这个,竞赛时没写好超时了,下面的这个版本可以过。</p><h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> typing <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">unionfind</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, groups)</span>:</span></span><br><span class="line"> self.groups = groups</span><br><span class="line"> self.items = []</span><br><span class="line"> <span class="keyword">for</span> g <span class="keyword">in</span> groups:</span><br><span class="line"> self.items += list(g)</span><br><span class="line"> self.items = set(self.items)</span><br><span class="line"> self.parent = {}</span><br><span class="line"> self.rootdict = {} <span class="comment"># 记住每个root下节点的数量</span></span><br><span class="line"> <span class="keyword">for</span> item <span class="keyword">in</span> self.items:</span><br><span class="line"> self.rootdict[item] = <span class="number">1</span></span><br><span class="line"> self.parent[item] = item</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">union</span><span class="params">(self, r1, r2)</span>:</span></span><br><span class="line"> rr1 = self.findroot(r1)</span><br><span class="line"> rr2 = self.findroot(r2)</span><br><span class="line"> cr1 = self.rootdict[rr1]</span><br><span class="line"> cr2 = self.rootdict[rr2]</span><br><span class="line"> <span class="keyword">if</span> cr1 >= cr2: <span class="comment"># 将节点数量较小的树归并给节点数更大的树</span></span><br><span class="line"> self.parent[rr2] = rr1</span><br><span class="line"> self.rootdict.pop(rr2)</span><br><span class="line"> self.rootdict[rr1] = cr1 + cr2</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> self.parent[rr1] = rr2</span><br><span class="line"> self.rootdict.pop(rr1)</span><br><span class="line"> self.rootdict[rr2] = cr1 + cr2</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">is_connected</span><span class="params">(self, i, j)</span>:</span></span><br><span class="line"> <span class="keyword">return</span> self.findroot(i) == self.findroot(j)</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">findroot</span><span class="params">(self, r)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> 可以通过压缩路径来优化算法,即遍历路径上的每个节点直接指向根节点</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> <span class="keyword">if</span> r <span class="keyword">in</span> self.rootdict.keys():</span><br><span class="line"> <span class="keyword">return</span> r</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> self.findroot(self.parent[r])</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">createtree</span><span class="params">(self)</span>:</span></span><br><span class="line"> <span class="keyword">for</span> g <span class="keyword">in</span> self.groups:</span><br><span class="line"> <span class="keyword">if</span> len(g) < <span class="number">2</span>:</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">0</span>, len(g) - <span class="number">1</span>):</span><br><span class="line"> <span class="keyword">if</span> self.findroot(g[i]) != self.findroot(g[i + <span class="number">1</span>]): <span class="comment"># 如果处于同一个集合的节点有不同的根节点,归并之</span></span><br><span class="line"> self.union(g[i], g[i + <span class="number">1</span>])</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">to_lists</span><span class="params">(self)</span>:</span></span><br><span class="line"> re: Dict[List] = {}</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> self.rootdict:</span><br><span class="line"> re[k] = []</span><br><span class="line"> <span class="keyword">for</span> n <span class="keyword">in</span> self.parent:</span><br><span class="line"> re[self.findroot(n)].append(n)</span><br><span class="line"> r = []</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> re:</span><br><span class="line"> r.append(re[k])</span><br><span class="line"> <span class="keyword">return</span> r</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">smallestStringWithSwaps</span><span class="params">(self, s: str, pairs: List[List[int]])</span> -> str:</span></span><br><span class="line"> u = unionfind(pairs)</span><br><span class="line"> u.createtree()</span><br><span class="line"> a = u.to_lists()</span><br><span class="line"> li = list(s)</span><br><span class="line"> <span class="keyword">for</span> se <span class="keyword">in</span> a:</span><br><span class="line"> keys = list(se)</span><br><span class="line"> keys.sort()</span><br><span class="line"> values = [li[x] <span class="keyword">for</span> x <span class="keyword">in</span> keys]</span><br><span class="line"> values.sort()</span><br><span class="line"> <span class="keyword">for</span> i, v <span class="keyword">in</span> zip(keys, values):</span><br><span class="line"> li[i] = v</span><br><span class="line"> <span class="keyword">return</span> <span class="string">""</span>.join(li)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">s = Solution()</span><br><span class="line">print(s.smallestStringWithSwaps(<span class="string">"dcab"</span>, [[<span class="number">0</span>, <span class="number">3</span>], [<span class="number">1</span>, <span class="number">2</span>], [<span class="number">0</span>, <span class="number">2</span>]]))</span><br></pre></td></tr></table></figure><h2 id="第四题"><a href="#第四题" class="headerlink" title="第四题"></a>第四题</h2><h3 id="思路-3"><a href="#思路-3" class="headerlink" title="思路"></a>思路</h3><p>不会呀,题都不大看的懂,好像是一个复杂版的拓扑排序,姑且放一个别人的题解吧</p><h3 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Queue</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span><span class="params">(object)</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">sortItems</span><span class="params">(self, n, m, group, beforeItems)</span>:</span></span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> :type n: int</span></span><br><span class="line"><span class="string"> :type m: int</span></span><br><span class="line"><span class="string"> :type group: List[int]</span></span><br><span class="line"><span class="string"> :type beforeItems: List[List[int]]</span></span><br><span class="line"><span class="string"> :rtype: List[int]</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> <span class="comment">#组内拓扑排序</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">get_group_ans</span><span class="params">(group_points,group_edges)</span>:</span></span><br><span class="line"> <span class="comment">#组内级别建图</span></span><br><span class="line"> graph = {group_point:[] <span class="keyword">for</span> group_point <span class="keyword">in</span> group_points}</span><br><span class="line"> degree = {group_point:<span class="number">0</span> <span class="keyword">for</span> group_point <span class="keyword">in</span> group_points}</span><br><span class="line"> <span class="keyword">for</span> x,y <span class="keyword">in</span> group_edges:</span><br><span class="line"> graph[y].append(x)</span><br><span class="line"> degree[x] += <span class="number">1</span></span><br><span class="line"> <span class="comment">#top sort</span></span><br><span class="line"> q = Queue.Queue()</span><br><span class="line"> <span class="keyword">for</span> graph_point <span class="keyword">in</span> group_points:</span><br><span class="line"> <span class="keyword">if</span> degree[graph_point] == <span class="number">0</span>:</span><br><span class="line"> q.put(graph_point)</span><br><span class="line"></span><br><span class="line"> <span class="comment">#组内拓扑排序</span></span><br><span class="line"> task_res = []</span><br><span class="line"> <span class="keyword">while</span> <span class="keyword">not</span> q.empty():</span><br><span class="line"> x = q.get()</span><br><span class="line"> task_res.append(x)</span><br><span class="line"> <span class="keyword">for</span> y <span class="keyword">in</span> graph[x]:</span><br><span class="line"> degree[y] -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> degree[y] == <span class="number">0</span>:</span><br><span class="line"> q.put(y)</span><br><span class="line"> <span class="keyword">if</span> len(task_res) != len(group_points):</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">None</span></span><br><span class="line"> <span class="keyword">return</span> task_res</span><br><span class="line"> group_cnt = max(group)+<span class="number">1</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(n):</span><br><span class="line"> <span class="keyword">if</span> group[i] == <span class="number">-1</span>:</span><br><span class="line"> group[i] = group_cnt</span><br><span class="line"> group_cnt += <span class="number">1</span></span><br><span class="line"> <span class="comment">#组级别建图</span></span><br><span class="line"> group_ids = np.unique(group)</span><br><span class="line"> graph = {group_id:[] <span class="keyword">for</span> group_id <span class="keyword">in</span> group_ids}</span><br><span class="line"> degree = {group_id:<span class="number">0</span> <span class="keyword">for</span> group_id <span class="keyword">in</span> group_ids}</span><br><span class="line"> group_inner_edges = {group_id:[] <span class="keyword">for</span> group_id <span class="keyword">in</span> group_ids}</span><br><span class="line"> group_points = {group_id:[] <span class="keyword">for</span> group_id <span class="keyword">in</span> group_ids}</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(n):</span><br><span class="line"> groupa = group[i]</span><br><span class="line"> group_points[groupa].append(i)</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> beforeItems[i]:</span><br><span class="line"> groupb = group[j]</span><br><span class="line"> <span class="keyword">if</span> groupa == groupb:</span><br><span class="line"> group_inner_edges[groupa].append([i,j])</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> graph[groupb].append(groupa)</span><br><span class="line"> degree[groupa] += <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">#组级别拓扑排序</span></span><br><span class="line"> q = Queue.Queue()</span><br><span class="line"> <span class="keyword">for</span> group_id <span class="keyword">in</span> group_ids:</span><br><span class="line"> <span class="keyword">if</span> degree[group_id] == <span class="number">0</span>:</span><br><span class="line"> q.put(group_id)</span><br><span class="line"> group_res = []</span><br><span class="line"> <span class="keyword">while</span> <span class="keyword">not</span> q.empty():</span><br><span class="line"> x = q.get()</span><br><span class="line"> group_res.append(x)</span><br><span class="line"> <span class="keyword">for</span> y <span class="keyword">in</span> graph[x]:</span><br><span class="line"> degree[y] -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> degree[y] == <span class="number">0</span>:</span><br><span class="line"> q.put(y)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> len(group_res) != len(group_ids):</span><br><span class="line"> <span class="keyword">return</span> []</span><br><span class="line"> <span class="comment">#根据组拓扑序整合结果</span></span><br><span class="line"> task_res = []</span><br><span class="line"> <span class="keyword">for</span> group_id <span class="keyword">in</span> group_res:</span><br><span class="line"> ans = get_group_ans(group_points[group_id],group_inner_edges[group_id])</span><br><span class="line"> <span class="keyword">if</span> ans <span class="keyword">is</span> <span class="keyword">None</span>:</span><br><span class="line"> <span class="keyword">return</span> []</span><br><span class="line"> task_res += ans</span><br><span class="line"> <span class="keyword">return</span> task_res</span><br></pre></td></tr></table></figure><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>这次竞赛意外繁多,最后就一题过了,其它的都是超时。。。结果竞赛后稍微改了改都能过。。。。</p><p>反思一下,其实还是心态崩了,本来都做得出的</p>]]></content>
<summary type="html">
<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><blockquote>
<p>比赛链接:<a href="https://leetcode-cn.com/contest/weekly-contest-155" target="_blank" rel="noopener">leetcode第155周周赛</a></p>
</blockquote>
<table>
<thead>
<tr>
<th style="text-align:center">题目</th>
<th style="text-align:center">难度</th>
<th style="text-align:center">知识点</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-155/problems/minimum-absolute-difference" target="_blank" rel="noopener">最小绝对差</a></td>
<td style="text-align:center">简单</td>
<td style="text-align:center">无</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-155/problems/ugly-number-iii" target="_blank" rel="noopener">丑数 III</a></td>
<td style="text-align:center">中等</td>
<td style="text-align:center">容斥+二分</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-155/problems/smallest-string-with-swaps" target="_blank" rel="noopener">交换字符串中的元素</a></td>
<td style="text-align:center">中等</td>
<td style="text-align:center">并查集</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-155/problems/sort-items-by-groups-respecting-dependencies" target="_blank" rel="noopener">项目管理</a></td>
<td style="text-align:center">困难</td>
<td style="text-align:center">拓扑排序</td>
</tr>
</tbody>
</table>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="算法" scheme="https://www.intmian.com/tags/%E7%AE%97%E6%B3%95/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
</entry>
<entry>
<title>leetcode contest 154 writeup</title>
<link href="https://www.intmian.com/2019/09/20/154/"/>
<id>https://www.intmian.com/2019/09/20/154/</id>
<published>2019-09-20T08:54:51.000Z</published>
<updated>2019-09-20T09:08:05.051Z</updated>
<content type="html"><![CDATA[<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><blockquote><p>比赛链接:<a href="https://leetcode-cn.com/contest/weekly-contest-154" target="_blank" rel="noopener">leetcode第154周周赛</a></p></blockquote><table><thead><tr><th style="text-align:center">题目</th><th style="text-align:center">难度</th><th style="text-align:center">知识点</th></tr></thead><tbody><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-154/problems/maximum-number-of-balloons" target="_blank" rel="noopener">“气球” 的最大数量</a></td><td style="text-align:center">简单</td><td style="text-align:center">无</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-154/problems/reverse-substrings-between-each-pair-of-parentheses" target="_blank" rel="noopener">反转每对括号间的子串</a></td><td style="text-align:center">中等</td><td style="text-align:center">无</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-154/problems/k-concatenation-maximum-sum" target="_blank" rel="noopener">K 次串联后最大子数组之和</a></td><td style="text-align:center">中等</td><td style="text-align:center">lcs/分类讨论</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-154/problems/critical-connections-in-a-network" target="_blank" rel="noopener">查找集群内的「关键连接」</a></td><td style="text-align:center">困难</td><td style="text-align:center">tarjan算法</td></tr></tbody></table><a id="more"></a><blockquote><p>注:思路是理想思路,代码有可能是我比赛时写的,就不那么理想.</p><p>所以代码与思路不一定等价</p></blockquote><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><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">maxNumberOfBalloons</span><span class="params">(self, text: str)</span> -> int:</span></span><br><span class="line"> d = dict()</span><br><span class="line"> d[<span class="string">"b"</span>] = d[<span class="string">"a"</span>] = d[<span class="string">"l"</span>] = d[<span class="string">"o"</span>] = d[<span class="string">"n"</span>] = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> c <span class="keyword">in</span> text:</span><br><span class="line"> <span class="keyword">if</span> c <span class="keyword">not</span> <span class="keyword">in</span> d:</span><br><span class="line"> d[c] = <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> d[c] += <span class="number">1</span></span><br><span class="line"> num_b = d[<span class="string">"b"</span>]</span><br><span class="line"> num_a = d[<span class="string">"a"</span>]</span><br><span class="line"> num_l = d[<span class="string">"l"</span>]</span><br><span class="line"> num_o = d[<span class="string">"o"</span>]</span><br><span class="line"> num_n = d[<span class="string">"n"</span>]</span><br><span class="line"> m_single = min(num_b, num_a, num_n)</span><br><span class="line"> m_double = min(num_l, num_o)</span><br><span class="line"> <span class="keyword">return</span> min(m_single, int(m_double / <span class="number">2</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">s = Solution()</span><br><span class="line">print(s.maxNumberOfBalloons(<span class="string">"leetcode"</span>))</span><br></pre></td></tr></table></figure><h2 id="第二题"><a href="#第二题" class="headerlink" title="第二题"></a>第二题</h2><h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><p>将待翻转的字符串压栈就可以,类似的有用括号表示优先级的,都可以用这个方法。</p><p>因为理论上翻转两次可以抵消,我就写了注释里面的代码,但好像有点问题,我就懒得改进了。</p><h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> typing</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">reverseParentheses</span><span class="params">(self, s: str)</span> -> str:</span></span><br><span class="line"> ans = [<span class="string">''</span>]</span><br><span class="line"> <span class="keyword">for</span> c <span class="keyword">in</span> s:</span><br><span class="line"> <span class="keyword">if</span> c == <span class="string">'('</span>:</span><br><span class="line"> ans += [<span class="string">''</span>]</span><br><span class="line"> <span class="keyword">elif</span> c == <span class="string">')'</span>:</span><br><span class="line"> ans[<span class="number">-2</span>] += ans[<span class="number">-1</span>][:: <span class="number">-1</span>] <span class="comment"># 倒数第二个串压入倒数第一个的翻转</span></span><br><span class="line"> ans.pop()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> ans[<span class="number">-1</span>] += c <span class="comment"># 压入最后一个字符串</span></span><br><span class="line"> <span class="keyword">return</span> ans[<span class="number">0</span>]</span><br><span class="line"> <span class="comment"># ans: typing.List[(str, int)] = []</span></span><br><span class="line"> <span class="comment"># level = 0 # 翻转等级</span></span><br><span class="line"> <span class="comment"># temp = ""</span></span><br><span class="line"> <span class="comment"># for c in s:</span></span><br><span class="line"> <span class="comment"># if c == '(':</span></span><br><span class="line"> <span class="comment"># ans.append((temp, level))</span></span><br><span class="line"> <span class="comment"># level += 1</span></span><br><span class="line"> <span class="comment"># temp = ""</span></span><br><span class="line"> <span class="comment"># elif c == ')':</span></span><br><span class="line"> <span class="comment"># ans.append((temp, level))</span></span><br><span class="line"> <span class="comment"># level -= 1</span></span><br><span class="line"> <span class="comment"># temp = ""</span></span><br><span class="line"> <span class="comment"># else:</span></span><br><span class="line"> <span class="comment"># temp += c</span></span><br><span class="line"> <span class="comment"># result = ""</span></span><br><span class="line"> <span class="comment"># for a, l in ans:</span></span><br><span class="line"> <span class="comment"># if l % 2 == 1:</span></span><br><span class="line"> <span class="comment"># result += a[::-1]</span></span><br><span class="line"> <span class="comment"># else:</span></span><br><span class="line"> <span class="comment"># result += a</span></span><br><span class="line"> <span class="comment"># return result</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">s = Solution()</span><br><span class="line">print(s.reverseParentheses(<span class="string">"a(bcdefghijkl(mno)p)q"</span>))</span><br></pre></td></tr></table></figure><h2 id="第三题"><a href="#第三题" class="headerlink" title="第三题"></a>第三题</h2><h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><p>分成几种情况就可以。</p><ol><li>单周期总和为负数:结果为单周期最大的子序列和,用lcs就行。</li><li>单周期总数为正数:结果为中间的加起来,加上头尾两端为首的最大的连续子序列和,用前/后缀和就可以了。如果这个值比单周期的最大子序列和还大的话,就用上面的。</li></ol><p>小于零去领,大于零记得模。</p><h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env Python</span></span><br><span class="line"><span class="comment"># coding=utf-8</span></span><br><span class="line"><span class="keyword">from</span> typing <span class="keyword">import</span> List</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">find_max_child</span><span class="params">(l: List)</span> -> (int, int, int):</span></span><br><span class="line"> <span class="comment"># return left right sum</span></span><br><span class="line"> dp = [<span class="number">0</span>] * len(l)</span><br><span class="line"> lefts = [<span class="number">0</span>] * len(l) <span class="comment"># 以i结尾的最大的子序列的左界</span></span><br><span class="line"> dp[<span class="number">0</span>] = l[<span class="number">0</span>] <span class="comment"># 以i为结尾的最大子序列</span></span><br><span class="line"> lefts[<span class="number">0</span>] = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>, len(l)):</span><br><span class="line"> <span class="keyword">if</span> l[i] > dp[i - <span class="number">1</span>] + l[i]:</span><br><span class="line"> dp[i] = l[i]</span><br><span class="line"> lefts[i] = i</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> dp[i] = dp[i - <span class="number">1</span>] + l[i]</span><br><span class="line"> lefts[i] = lefts[i - <span class="number">1</span>]</span><br><span class="line"> maxi = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>, len(l)):</span><br><span class="line"> <span class="keyword">if</span> dp[i] > dp[maxi]:</span><br><span class="line"> maxi = i</span><br><span class="line"> <span class="keyword">return</span> lefts[maxi], maxi, dp[maxi]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">kConcatenationMaxSum</span><span class="params">(self, arr: List[int], k: int)</span> -> int:</span></span><br><span class="line"> length = len(arr)</span><br><span class="line"> one_max = find_max_child(arr)[<span class="number">2</span>] <span class="comment"># 一个周期内最大</span></span><br><span class="line"> <span class="keyword">if</span> k == <span class="number">1</span>:</span><br><span class="line"> <span class="keyword">return</span> max(<span class="number">0</span>, one_max)</span><br><span class="line"> s = sum(arr)</span><br><span class="line"> pre_sum = [arr[<span class="number">0</span>]]</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>, length):</span><br><span class="line"> pre_sum.append(pre_sum[i - <span class="number">1</span>] + arr[i])</span><br><span class="line"> after_sum = [arr[<span class="number">-1</span>]]</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>, length):</span><br><span class="line"> after_sum.append(after_sum[i - <span class="number">1</span>] + arr[- i - <span class="number">1</span>])</span><br><span class="line"> <span class="keyword">return</span> (max(pre_sum + [<span class="number">0</span>]) + max(after_sum + [<span class="number">0</span>]) + (k - <span class="number">2</span>) * max(s, <span class="number">0</span>)) % <span class="number">1000000007</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">s = Solution()</span><br><span class="line">s.kConcatenationMaxSum([<span class="number">1</span>, <span class="number">2</span>], <span class="number">3</span>)</span><br></pre></td></tr></table></figure><h2 id="第四题"><a href="#第四题" class="headerlink" title="第四题"></a>第四题</h2><h3 id="思路-3"><a href="#思路-3" class="headerlink" title="思路"></a>思路</h3><p>tarjan算法一把梭,听说中文版比赛少一组测试用例,可以取巧(已经修复。</p><p>这题的时间卡的有问题,不修常数的话,有些语言能过,py过不了。不过我就不修常数了</p><h3 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line"> self.maxV = <span class="number">100001</span></span><br><span class="line"> self.dfn = [<span class="number">0</span> <span class="keyword">for</span> _ <span class="keyword">in</span> range(self.maxV)]</span><br><span class="line"> self.low = [self.maxV <span class="keyword">for</span> _ <span class="keyword">in</span> range(self.maxV)]</span><br><span class="line"> self.vis = [<span class="number">0</span> <span class="keyword">for</span> _ <span class="keyword">in</span> range(self.maxV)]</span><br><span class="line"> self.edgs = [[] <span class="keyword">for</span> _ <span class="keyword">in</span> range(self.maxV)]</span><br><span class="line"> self.ans = []</span><br><span class="line"> self.times = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">tarjan</span><span class="params">(self, curr, parent)</span>:</span></span><br><span class="line"> self.times += <span class="number">1</span></span><br><span class="line"> self.low[curr] = self.times</span><br><span class="line"> self.dfn[curr] = self.times</span><br><span class="line"> self.vis[curr] = <span class="number">1</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> e <span class="keyword">in</span> self.edgs[curr]:</span><br><span class="line"> <span class="keyword">if</span> e == parent:</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> self.vis[e] == <span class="number">0</span>:</span><br><span class="line"> self.tarjan(e, curr)</span><br><span class="line"> self.low[curr] = min(self.low[curr], self.low[e])</span><br><span class="line"> <span class="keyword">if</span> self.low[e] > self.dfn[curr]:</span><br><span class="line"> self.ans.append([curr, e])</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> self.low[curr] = min(self.low[curr], self.dfn[e])</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">criticalConnections</span><span class="params">(self, n: int, connections: List[List[int]])</span> -> List[List[int]]:</span></span><br><span class="line"> <span class="keyword">for</span> conn <span class="keyword">in</span> connections:</span><br><span class="line"> self.edgs[conn[<span class="number">0</span>]].append(conn[<span class="number">1</span>])</span><br><span class="line"> self.edgs[conn[<span class="number">1</span>]].append(conn[<span class="number">0</span>])</span><br><span class="line"></span><br><span class="line"> self.tarjan(<span class="number">0</span>, <span class="number">-1</span>)</span><br><span class="line"> <span class="keyword">return</span> self.ans</span><br></pre></td></tr></table></figure><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>不得不提,自从我花了一点时间写出了根据模板自动生成文档的程序,写周赛题解方便了很多。</p>]]></content>
<summary type="html">
<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><blockquote>
<p>比赛链接:<a href="https://leetcode-cn.com/contest/weekly-contest-154" target="_blank" rel="noopener">leetcode第154周周赛</a></p>
</blockquote>
<table>
<thead>
<tr>
<th style="text-align:center">题目</th>
<th style="text-align:center">难度</th>
<th style="text-align:center">知识点</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-154/problems/maximum-number-of-balloons" target="_blank" rel="noopener">“气球” 的最大数量</a></td>
<td style="text-align:center">简单</td>
<td style="text-align:center">无</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-154/problems/reverse-substrings-between-each-pair-of-parentheses" target="_blank" rel="noopener">反转每对括号间的子串</a></td>
<td style="text-align:center">中等</td>
<td style="text-align:center">无</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-154/problems/k-concatenation-maximum-sum" target="_blank" rel="noopener">K 次串联后最大子数组之和</a></td>
<td style="text-align:center">中等</td>
<td style="text-align:center">lcs/分类讨论</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-154/problems/critical-connections-in-a-network" target="_blank" rel="noopener">查找集群内的「关键连接」</a></td>
<td style="text-align:center">困难</td>
<td style="text-align:center">tarjan算法</td>
</tr>
</tbody>
</table>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="算法" scheme="https://www.intmian.com/tags/%E7%AE%97%E6%B3%95/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
</entry>
<entry>
<title>设计模式读后感</title>
<link href="https://www.intmian.com/2019/09/16/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<id>https://www.intmian.com/2019/09/16/设计模式/</id>
<published>2019-09-16T11:04:15.000Z</published>
<updated>2019-09-16T11:38:43.789Z</updated>
<content type="html"><![CDATA[<p>今天终于读完了设计模式,特书此文以留念</p><a id="more"></a><h2 id="感想"><a href="#感想" class="headerlink" title="感想"></a>感想</h2><p>昔日,郑某老师一直推荐设计模式,但是因为那个时候还没有打算好以后就靠开发吃饭了,因此一直没去看。反而是看了很多c++。最近,在暑假的实习中,我在为公司的祖传代码debug时,发现公司代码规模太大,添加新功能过于麻烦,debug也不容易。加上我之前用go写的主控开始没有设计好,后面吃了很多苦头,web模块与计划模块紧耦合,修bug难度,谁试谁知道。遂读设计模式。</p><p>不过我个人不是很推荐四人帮的这本(<del>虽然我看的是这本</del>),举得例子过于晦涩难懂,而且看到第二章会感觉脑子出问题,不过书是好书啦,也确实是经典。</p><p>我个人感觉像是设计模式这种每一种模式都是从实际例子中提炼出来的,应该吸收其思想,反而是模式本身不必记得太住,知道怎么做就可以了。有一种张三丰教张无忌太极的感觉2333。单看,不吸收思想硬套的话,反而会小工程过度设计,不够自然。</p><h3 id="设计模式的思想"><a href="#设计模式的思想" class="headerlink" title="设计模式的思想"></a>设计模式的思想</h3><ol><li>将变化的与不变的分离</li><li>将类之间的联系泛化从而解耦</li><li>真正的低效是人的低效,所以可以一定程度减少性能来优化维护性</li></ol><hr><ol><li>泛化以实现高拓展</li><li>封装以方便切换</li><li>将类中无关的部分封装</li><li>将独立变化的部分独立封装</li></ol><blockquote><p>自己随便总结的23333</p></blockquote><h3 id="各个模式的总结"><a href="#各个模式的总结" class="headerlink" title="各个模式的总结"></a>各个模式的总结</h3><h4 id="创建型模式"><a href="#创建型模式" class="headerlink" title="创建型模式"></a>创建型模式</h4><h5 id="抽象工厂"><a href="#抽象工厂" class="headerlink" title="抽象工厂"></a>抽象工厂</h5><p>将成系列的类的创建封装并抽象为接口,方便在需要大量创建对象时,方便成系列的调换。或在客户端仅需考虑抽象商品的类型,无需考虑需要具体的哪一个,以实现客户端与具体类型的解耦。</p><h5 id="生成器"><a href="#生成器" class="headerlink" title="生成器"></a>生成器</h5><p>将一个极其复杂类的装配过程封装为生成器,以将变化的装配步骤,与不变的子部件生成相分离,也实现了构建类过程与构建子类过程相解耦。一般用于装配高度内联部件顺序联系可能发生变化,但是子部件在生成时相对不变的大型类。</p><h5 id="工厂模式"><a href="#工厂模式" class="headerlink" title="工厂模式"></a>工厂模式</h5><p>父类仅保留一个创建对象的虚方法(接口),待子类具体实现。可以将具体实例化哪一个推迟到运行时。</p><h5 id="原型"><a href="#原型" class="headerlink" title="原型"></a>原型</h5><p>创建需要被实例化的对象的原型,再拷贝并修改拷贝体,来实现真正创建对象。</p><h5 id="单件(单例"><a href="#单件(单例" class="headerlink" title="单件(单例"></a>单件(单例</h5><p>将对象的新建与计数器相内联,保证只能创建一个类的方法</p><blockquote><p>原文未涉及多线程情况,加锁即可</p></blockquote><h4 id="结构性模式"><a href="#结构性模式" class="headerlink" title="结构性模式"></a>结构性模式</h4><h5 id="适配器"><a href="#适配器" class="headerlink" title="适配器"></a>适配器</h5><p>你有一个接口/类型,和一个功能差不多但是不适合这个接口的类,在此类外套一层来适配接口/类型。</p><h5 id="桥接"><a href="#桥接" class="headerlink" title="桥接"></a>桥接</h5><p>将独立变化的部分相分离并封装,使他们独立变化,避免产生过多的类。如果一个父类的若干子类中,有共通部分,可以将共通部分作为父类的成员,以实现变化的抽象和暂时不变的实现解耦分离。也就是将抽象与实现,通过将抽象部分转换为接口来实现互相分离,使抽象部分调用的实现可以独立变化。通过封装分离抽象可以减少一级继承。</p><h5 id="组合"><a href="#组合" class="headerlink" title="组合"></a>组合</h5><p>通过对对象进行抽象,将对象之间的包含关系泛化为可以包含任意多个从而转换为树形,已提供一致性并将包含者与被包含者相互解耦。</p><h5 id="装饰"><a href="#装饰" class="headerlink" title="装饰"></a>装饰</h5><p>将希望动态地添加的类功能抽象为装饰器类,一层层包裹原对象,以实现在不继承的情况下修改功能。</p><h5 id="外观"><a href="#外观" class="headerlink" title="外观"></a>外观</h5><p>将子系统的对外接口统一归纳到一个总的外观类中,以实现外部与内部解耦。</p><h5 id="享元"><a href="#享元" class="headerlink" title="享元"></a>享元</h5><p>将粒度较小的轻量化类的状态从内部剥离到外部,以实现不包含任何与任何调用者相关联的属性,来将这个对象进行共享,从而减少额外创建过多类。可以减少一切皆对象带来的消耗。此模式将对象中不变的内部状态,与变化的外部状态相分离而减少对象数量。</p><h5 id="代理"><a href="#代理" class="headerlink" title="代理"></a>代理</h5><p>当一个类关联一个大型资源时,可以在需要时才加载资源,但是实现与资源本身无关的操作,以方便用户对资源进行与资源本身无关的操作。</p><h4 id="行为模式"><a href="#行为模式" class="headerlink" title="行为模式"></a>行为模式</h4><h5 id="职责链"><a href="#职责链" class="headerlink" title="职责链"></a>职责链</h5><p>将请求的发送与接收解耦为接收者可以有多个,且形成一条链,实现发送的泛化解耦。</p><h5 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h5><p>将请求封装为一个对象,以实现对于请求的复杂操作或运行时绑定。</p><h5 id="解释器"><a href="#解释器" class="headerlink" title="解释器"></a>解释器</h5><p>若某事物拥有一定的规则性,假定要对某事物进行操作。可以先对去进行分析形成树,将事物分解为部分,在对整棵树使用此操作。拥有较好的拓展性。</p><h5 id="迭代器"><a href="#迭代器" class="headerlink" title="迭代器"></a>迭代器</h5><p>创建一个类,并绑定另一个数据结构,来实现在不暴露其内部结构的情况下对可以对数据结构内部数据进行迭代。</p><h5 id="中介者"><a href="#中介者" class="headerlink" title="中介者"></a>中介者</h5><p>发送方和请求方不直接发送请求,而是先发送给中介对象再由中介对象转发来实现发送方和接收方解耦。</p><h5 id="备忘录"><a href="#备忘录" class="headerlink" title="备忘录"></a>备忘录</h5><p>即对类内所有状态的封装备份。在需要存储内部状态的情况下但是不想暴露内部结构,可以建立一个友元类,通过拷贝内部属性实现备忘。</p><h5 id="状态"><a href="#状态" class="headerlink" title="状态"></a>状态</h5><p>当类的大部分行为与其一个状态相绑定时,可以将类的行为封装为一个接口。这个接口作为内部成员,并根据状态在运行时进行动态绑定具体的行为类。</p><h5 id="策略"><a href="#策略" class="headerlink" title="策略"></a>策略</h5><p>当类内某段代码是一个成系列算法簇的一员,而且你希望可以更好的拓展和动态替换,可以将其封装为对象。这个对象作为类的一个成员。</p><h5 id="模板方法"><a href="#模板方法" class="headerlink" title="模板方法"></a>模板方法</h5><p>当一些类仅有少量不同。可以将类的骨干部分定义为父类,其中不同的部分定义为一个虚函数,通过某个函数调用钩在父类上,使用子类继承父类并覆盖这个虚函数来实现完整的功能。</p><blockquote><p>最常见的继承方式</p></blockquote><h5 id="访问者"><a href="#访问者" class="headerlink" title="访问者"></a>访问者</h5><p>当有一棵树,你希望对所有的节点进行多种操作,而且操作的种类会发生变化而节点的种类不会。与其把这种操作写为节点类的成员函数,不如把它单独抽象为一个类,并在节点类中只有一个接受这种类的访问方法。当你要对某节点进行操作时,仅需把操作对应的访问器作为节点类访问方法的参数即可。这样可以将节点与操作解耦。</p>]]></content>
<summary type="html">
<p>今天终于读完了设计模式,特书此文以留念</p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="架构" scheme="https://www.intmian.com/tags/%E6%9E%B6%E6%9E%84/"/>
</entry>
<entry>
<title>leetcode contest 153 writeup</title>
<link href="https://www.intmian.com/2019/09/10/leetcode%20%E7%AC%AC%20153%20%E5%9C%BA%E5%91%A8%E8%B5%9B%20writeup/"/>
<id>https://www.intmian.com/2019/09/10/leetcode 第 153 场周赛 writeup/</id>
<published>2019-09-10T03:17:05.000Z</published>
<updated>2019-09-16T08:26:27.218Z</updated>
<content type="html"><![CDATA[<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><blockquote><p><a href="https://leetcode-cn.com/contest/weekly-contest-153" target="_blank" rel="noopener">leetcode第153周周赛</a></p></blockquote><table><thead><tr><th style="text-align:center">题目</th><th style="text-align:center">难度</th><th style="text-align:center">知识点</th></tr></thead><tbody><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-153/problems/distance-between-bus-stops" target="_blank" rel="noopener">公交站间的距离</a></td><td style="text-align:center">简单</td><td style="text-align:center">无</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-153/problems/day-of-the-week" target="_blank" rel="noopener">一周中的第几天</a></td><td style="text-align:center">简单</td><td style="text-align:center">无</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-153/problems/maximum-subarray-sum-with-one-deletion" target="_blank" rel="noopener">删除一次得到子数组最大和</a></td><td style="text-align:center">中等</td><td style="text-align:center">dp</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-153/problems/make-array-strictly-increasing" target="_blank" rel="noopener">使数组严格递增</a></td><td style="text-align:center">困难</td><td style="text-align:center">dp</td></tr></tbody></table><a id="more"></a><blockquote><p>注:思路是理想思路,代码有可能是我比赛时写的,就不那么理想.</p><p>所以代码与思路不一定等价</p></blockquote><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><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> typing <span class="keyword">import</span> List</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">distanceBetweenBusStops</span><span class="params">(self, distance: List[int], start: int, destination: int)</span> -> int:</span></span><br><span class="line"> <span class="keyword">if</span> start > destination:</span><br><span class="line"> start, destination = destination, start</span><br><span class="line"> s = sum(distance)</span><br><span class="line"> length = destination - start</span><br><span class="line"> s_shun = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(start, destination):</span><br><span class="line"> s_shun += distance[i]</span><br><span class="line"> s_re = s - s_shun</span><br><span class="line"> <span class="keyword">if</span> s_shun > s_re:</span><br><span class="line"> <span class="keyword">return</span> s_re</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> s_shun</span><br></pre></td></tr></table></figure><h2 id="第二题"><a href="#第二题" class="headerlink" title="第二题"></a>第二题</h2><h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><p>调库就行,吃的空的话可以试试直接推(考虑闰月就行</p><h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">dayOfTheWeek</span><span class="params">(self, day: int, month: int, year: int)</span> -> str:</span></span><br><span class="line"> <span class="keyword">import</span> datetime</span><br><span class="line"> <span class="keyword">return</span> [<span class="string">"Monday"</span>, <span class="string">"Tuesday"</span>,<span class="string">"Wednesday"</span>, <span class="string">"Thursday"</span>, <span class="string">"Friday"</span>, <span class="string">"Saturday"</span>, <span class="string">"Sunday"</span>][datetime.datetime(year, month, day).weekday()]</span><br></pre></td></tr></table></figure><h2 id="第三题"><a href="#第三题" class="headerlink" title="第三题"></a>第三题</h2><h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><ol><li>思路类似于lcs,稍微改一下就可以</li><li>写一个和lcs一样的dp关系式<code>dp_no_delete[i] = max(arr[i], dp_no_delete[i - 1] + arr[i])</code></li><li>在写一个代表了代表以i为结尾的和尽量大且有过删除的dp关系式<code>dp_with_delete[i] = max(dp_no_delete[i - 1], dp_with_delete[i - 1] + arr[i])</code></li></ol><h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> def maximumSum(self, arr: List[int]) -> int:</span><br><span class="line"> l = len(arr)</span><br><span class="line"> dp_with_delete = [<span class="number">0</span>] * l</span><br><span class="line"> dp_no_delete = [arr[<span class="number">0</span>]] * l</span><br><span class="line"> <span class="keyword">for</span> i in range(<span class="number">1</span>, l):</span><br><span class="line"> dp_no_delete[i] = max(arr[i], dp_no_delete[i - <span class="number">1</span>] + arr[i])</span><br><span class="line"> dp_with_delete[i] = max(dp_no_delete[i - <span class="number">1</span>], dp_with_delete[i - <span class="number">1</span>] + arr[i])</span><br><span class="line"> re = dp_no_delete[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">for</span> i in range(<span class="number">1</span>,l):</span><br><span class="line"> m = dp_no_delete[i]</span><br><span class="line"> n = dp_with_delete[i]</span><br><span class="line"> <span class="keyword">if</span> re < max(m, n):</span><br><span class="line"> re = max(m, n)</span><br><span class="line"> <span class="keyword">return</span> re</span><br></pre></td></tr></table></figure><h2 id="第四题"><a href="#第四题" class="headerlink" title="第四题"></a>第四题</h2><h3 id="思路-3"><a href="#思路-3" class="headerlink" title="思路"></a>思路</h3><p>这题没写出来网上看了别人的代码写的。思路正确,但是需要优化下</p><h3 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">makeArrayIncreasing</span><span class="params">(self, arr1: List[int], arr2: List[int])</span> -> int:</span></span><br><span class="line"> n = len(arr1)</span><br><span class="line"> maxV = <span class="number">1000000001</span></span><br><span class="line"> dp = [[maxV <span class="keyword">for</span> i <span class="keyword">in</span> range(n + <span class="number">1</span>)] <span class="keyword">for</span> _ <span class="keyword">in</span> range(n + <span class="number">1</span>)]</span><br><span class="line"></span><br><span class="line"> <span class="comment"># initial</span></span><br><span class="line"> arr2.sort()</span><br><span class="line"> dp[<span class="number">0</span>][<span class="number">0</span>] = <span class="number">-1</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>, n + <span class="number">1</span>):</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> range(<span class="number">0</span>, i + <span class="number">1</span>):</span><br><span class="line"> <span class="keyword">if</span> arr1[i - <span class="number">1</span>] > dp[j][i - <span class="number">1</span>]:</span><br><span class="line"> dp[j][i] = arr1[i - <span class="number">1</span>]</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> j > <span class="number">0</span>:</span><br><span class="line"> loc = bisect.bisect_right(arr2, dp[j - <span class="number">1</span>][i - <span class="number">1</span>])</span><br><span class="line"> <span class="keyword">if</span> loc < len(arr2):</span><br><span class="line"> dp[j][i] = min(dp[j][i], arr2[loc])</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> i == n <span class="keyword">and</span> dp[j][i] != maxV:</span><br><span class="line"> <span class="keyword">return</span> j</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span></span><br></pre></td></tr></table></figure><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>这次睡过头了忘记参见了,以上是后面写的。最后一题偏♂,反正我是做不出2333</p>]]></content>
<summary type="html">
<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><blockquote>
<p><a href="https://leetcode-cn.com/contest/weekly-contest-153" target="_blank" rel="noopener">leetcode第153周周赛</a></p>
</blockquote>
<table>
<thead>
<tr>
<th style="text-align:center">题目</th>
<th style="text-align:center">难度</th>
<th style="text-align:center">知识点</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-153/problems/distance-between-bus-stops" target="_blank" rel="noopener">公交站间的距离</a></td>
<td style="text-align:center">简单</td>
<td style="text-align:center">无</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-153/problems/day-of-the-week" target="_blank" rel="noopener">一周中的第几天</a></td>
<td style="text-align:center">简单</td>
<td style="text-align:center">无</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-153/problems/maximum-subarray-sum-with-one-deletion" target="_blank" rel="noopener">删除一次得到子数组最大和</a></td>
<td style="text-align:center">中等</td>
<td style="text-align:center">dp</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-153/problems/make-array-strictly-increasing" target="_blank" rel="noopener">使数组严格递增</a></td>
<td style="text-align:center">困难</td>
<td style="text-align:center">dp</td>
</tr>
</tbody>
</table>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="算法" scheme="https://www.intmian.com/tags/%E7%AE%97%E6%B3%95/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
</entry>
<entry>
<title>leetcode contest 151 writeup</title>
<link href="https://www.intmian.com/2019/08/26/leetcode%20121%E5%91%A8%E8%B5%9B%20writeup/"/>
<id>https://www.intmian.com/2019/08/26/leetcode 121周赛 writeup/</id>
<published>2019-08-26T09:00:05.000Z</published>
<updated>2019-09-16T08:42:32.010Z</updated>
<content type="html"><![CDATA[<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><blockquote><p><a href="https://leetcode-cn.com/contest/weekly-contest-151" target="_blank" rel="noopener">leetcode第151周周赛</a></p></blockquote><table><thead><tr><th style="text-align:center">题目</th><th style="text-align:center">难度</th><th style="text-align:center">知识点</th></tr></thead><tbody><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-151/problems/invalid-transactions" target="_blank" rel="noopener">查询无效交易</a></td><td style="text-align:center">简单</td><td style="text-align:center">无</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-151/problems/compare-strings-by-frequency-of-the-smallest-character" target="_blank" rel="noopener">比较字符串最小字母出现频次</a></td><td style="text-align:center">简单</td><td style="text-align:center">无</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-151/problems/remove-zero-sum-consecutive-nodes-from-linked-list" target="_blank" rel="noopener">从链表中删去总和值为零的连续节点</a></td><td style="text-align:center">中等</td><td style="text-align:center">链表</td></tr><tr><td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-151/problems/dinner-plate-stacks" target="_blank" rel="noopener">餐盘栈</a></td><td style="text-align:center">困难</td><td style="text-align:center">设计/无</td></tr></tbody></table><a id="more"></a><blockquote><p>注:思路是理想思路,代码有可能是我比赛时写的,就不那么理想.</p><p>所以代码与思路不一定等价</p></blockquote><h2 id="第一题"><a href="#第一题" class="headerlink" title="第一题"></a>第一题</h2><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>将数据处理后,双重map,然后去重。当然直接做也可以,我在比赛时就是直接做的。</p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">invalidTransactions</span><span class="params">(self, transactions: List[str])</span> -> List[str]:</span></span><br><span class="line"> transactions_after: [str, int, int, str] = []</span><br><span class="line"> results: List[str] = []</span><br><span class="line"> <span class="keyword">for</span> t <span class="keyword">in</span> transactions:</span><br><span class="line"> name, time, num, local = str.split(t, <span class="string">","</span>)</span><br><span class="line"> num = int(num)</span><br><span class="line"> time = int(time)</span><br><span class="line"> <span class="keyword">if</span> num > <span class="number">1000</span>:</span><br><span class="line"> results.append(t)</span><br><span class="line"> transactions_after.append((name, time, num, local))</span><br><span class="line"> <span class="keyword">for</span> (n1, t1, num1, l1) <span class="keyword">in</span> transactions_after:</span><br><span class="line"> <span class="keyword">for</span> (n2, t2, num2, l2) <span class="keyword">in</span> transactions_after:</span><br><span class="line"> <span class="keyword">if</span> n1 == n2 <span class="keyword">and</span> abs(t2 - t1) <= <span class="number">60</span> <span class="keyword">and</span> l1 != l2:</span><br><span class="line"> results.append(n1 + <span class="string">","</span> + str(t1) + <span class="string">","</span> + str(num1) + <span class="string">","</span> + l1)</span><br><span class="line"> <span class="keyword">return</span> list(set(results))</span><br></pre></td></tr></table></figure><h2 id="第二题"><a href="#第二题" class="headerlink" title="第二题"></a>第二题</h2><h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><ol><li>将字符串根据f处理成数据</li><li>对word排序(代码中,我没有</li><li>依次迭代处理(对于排序过得数据可以用二分法确认有几个比较大,由于py中的stl很弱,所以代码中我没有</li></ol><h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span>:</span></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">f</span><span class="params">(self, s: str)</span> -> int:</span></span><br><span class="line"> <span class="keyword">if</span> s == <span class="string">""</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"> i = <span class="number">1</span></span><br><span class="line"> min_c = s[<span class="number">0</span>]</span><br><span class="line"> min_n = <span class="number">1</span></span><br><span class="line"> <span class="keyword">while</span> i != len(s):</span><br><span class="line"> c = s[i]</span><br><span class="line"> <span class="keyword">if</span> c < min_c:</span><br><span class="line"> min_c = c</span><br><span class="line"> min_n = <span class="number">1</span></span><br><span class="line"> <span class="keyword">elif</span> c == min_c:</span><br><span class="line"> min_n += <span class="number">1</span></span><br><span class="line"> i += <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> min_n</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">numSmallerByFrequency</span><span class="params">(self, queries: List[str], words: List[str])</span> -> List[int]:</span></span><br><span class="line"> queries_n: List[int] = []</span><br><span class="line"> words_n: List[int] = []</span><br><span class="line"> <span class="keyword">for</span> n <span class="keyword">in</span> queries:</span><br><span class="line"> queries_n.append(self.f(n))</span><br><span class="line"> <span class="keyword">for</span> n <span class="keyword">in</span> words:</span><br><span class="line"> words_n.append(self.f(n))</span><br><span class="line"> result = []</span><br><span class="line"> <span class="keyword">for</span> i, n <span class="keyword">in</span> enumerate(queries_n):</span><br><span class="line"> low = <span class="number">0</span></span><br><span class="line"> <span class="keyword">for</span> n2 <span class="keyword">in</span> words_n:</span><br><span class="line"> <span class="keyword">if</span> n < n2:</span><br><span class="line"> low += <span class="number">1</span></span><br><span class="line"> result.append(low)</span><br><span class="line"> <span class="keyword">return</span> result</span><br></pre></td></tr></table></figure><h2 id="第三题"><a href="#第三题" class="headerlink" title="第三题"></a>第三题</h2><h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><ol><li>求出前缀和。例 12 3 -3 1 求出 0 1 3 6 3 4。</li><li>可以发现前缀和序列中相等的值对,其序号对应的范围在原序列中的子序列恰好值为零。</li><li>不停迭代删除子序列,直到有不存在这样的值对</li></ol><blockquote><p>动归也可</p></blockquote><h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function">ListNode* <span class="title">removeZeroSumSublists</span><span class="params">(ListNode* head)</span> </span>{</span><br><span class="line"> <span class="built_in">unordered_map</span><<span class="keyword">int</span>, ListNode*> prefixSum;</span><br><span class="line"> <span class="comment">// 因为头结点也有可能会被消掉,所以这里加一个虚拟节点作为头结点</span></span><br><span class="line"> ListNode* dummy = <span class="keyword">new</span> ListNode(<span class="number">0</span>), *p = dummy;</span><br><span class="line"> dummy->next = head;</span><br><span class="line"> </span><br><span class="line"> prefixSum[<span class="number">0</span>] = p;</span><br><span class="line"> <span class="keyword">int</span> cur = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (p = p->next) {</span><br><span class="line"> cur += p->val;</span><br><span class="line"> <span class="keyword">if</span> (prefixSum.find(cur) != prefixSum.end()) {</span><br><span class="line"> prefixSum[cur]->next = p->next;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> prefixSum[cur] = p;</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> dummy->next;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h2 id="第四题"><a href="#第四题" class="headerlink" title="第四题"></a>第四题</h2><h3 id="思路-3"><a href="#思路-3" class="headerlink" title="思路"></a>思路</h3><ol><li>使用栈数组</li><li>保存最后一个可以插入的位置一提高push速度</li></ol><h3 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> typing <span class="keyword">import</span> List</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DinnerPlates</span>:</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, capacity: int)</span>:</span></span><br><span class="line"> self.stacks: {int: List[int]} = dict()</span><br><span class="line"> self.size = <span class="number">0</span></span><br><span class="line"> self.capacity = capacity</span><br><span class="line"> self.last_not_full = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">push</span><span class="params">(self, val: int)</span> -> <span class="keyword">None</span>:</span></span><br><span class="line"> <span class="keyword">if</span> self.last_not_full <span class="keyword">not</span> <span class="keyword">in</span> self.stacks:</span><br><span class="line"> self.stacks[self.last_not_full] = [val]</span><br><span class="line"> self.size += <span class="number">1</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> self.stacks[self.last_not_full].append(val)</span><br><span class="line"> i = self.last_not_full</span><br><span class="line"> <span class="keyword">while</span> i < self.size <span class="keyword">and</span> len(self.stacks[i]) == self.capacity:</span><br><span class="line"> i += <span class="number">1</span></span><br><span class="line"> self.last_not_full = i</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">pop</span><span class="params">(self)</span> -> int:</span></span><br><span class="line"> <span class="keyword">if</span> self.size == <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span></span><br><span class="line"> last = self.stacks[self.size - <span class="number">1</span>]</span><br><span class="line"> r = last.pop()</span><br><span class="line"> <span class="keyword">if</span> len(last) == self.capacity - <span class="number">1</span>:</span><br><span class="line"> self.last_not_full = self.size - <span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> len(last) == <span class="number">0</span>:</span><br><span class="line"> self.size -= <span class="number">1</span></span><br><span class="line"> <span class="keyword">return</span> r</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">popAtStack</span><span class="params">(self, index: int)</span> -> int:</span></span><br><span class="line"> <span class="keyword">if</span> index >= self.size <span class="keyword">or</span> len(self.stacks[index]) == <span class="number">0</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span></span><br><span class="line"> self.last_not_full = index</span><br><span class="line"> <span class="keyword">return</span> self.stacks[index].pop()</span><br></pre></td></tr></table></figure><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>这次的题目翻译差一点,竞赛的时候看错了好几次。设计题对于性能的限制比预想的低,不需要hack技巧就可以通过,所以其实比第三题简单。第三题想通了其实也挺简单的。还需努力</p>]]></content>
<summary type="html">
<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><blockquote>
<p><a href="https://leetcode-cn.com/contest/weekly-contest-151" target="_blank" rel="noopener">leetcode第151周周赛</a></p>
</blockquote>
<table>
<thead>
<tr>
<th style="text-align:center">题目</th>
<th style="text-align:center">难度</th>
<th style="text-align:center">知识点</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-151/problems/invalid-transactions" target="_blank" rel="noopener">查询无效交易</a></td>
<td style="text-align:center">简单</td>
<td style="text-align:center">无</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-151/problems/compare-strings-by-frequency-of-the-smallest-character" target="_blank" rel="noopener">比较字符串最小字母出现频次</a></td>
<td style="text-align:center">简单</td>
<td style="text-align:center">无</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-151/problems/remove-zero-sum-consecutive-nodes-from-linked-list" target="_blank" rel="noopener">从链表中删去总和值为零的连续节点</a></td>
<td style="text-align:center">中等</td>
<td style="text-align:center">链表</td>
</tr>
<tr>
<td style="text-align:center"><a href="https://leetcode-cn.com/contest/weekly-contest-151/problems/dinner-plate-stacks" target="_blank" rel="noopener">餐盘栈</a></td>
<td style="text-align:center">困难</td>
<td style="text-align:center">设计/无</td>
</tr>
</tbody>
</table>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="算法" scheme="https://www.intmian.com/tags/%E7%AE%97%E6%B3%95/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
</entry>
<entry>
<title>我踩过的c++的坑 续</title>
<link href="https://www.intmian.com/2019/06/06/%E6%88%91%E8%B8%A9%E8%BF%87%E7%9A%84c++%E7%9A%84%E5%9D%91%202/"/>
<id>https://www.intmian.com/2019/06/06/我踩过的c++的坑 2/</id>
<published>2019-06-06T08:28:15.000Z</published>
<updated>2019-06-08T03:09:50.091Z</updated>
<content type="html"><![CDATA[<p>之前我写过一篇长期更新的《我踩过的c++的坑》,因为时间很长,文章太长了,查看起来太麻烦了,所以以后遇到的坑都记在这篇续里</p><p><a href="https://www.intmian.com/2018/07/21/%E6%88%91%E8%B8%A9%E8%BF%87%E7%9A%84c++%E7%9A%84%E5%9D%91/">旧文链接</a></p><p><strong>持续更新</strong></p><a id="more"></a><h2 id="关于返回右值引用或使用移动语义可能会导致的问题"><a href="#关于返回右值引用或使用移动语义可能会导致的问题" class="headerlink" title="关于返回右值引用或使用移动语义可能会导致的问题"></a>关于返回右值引用或使用移动语义可能会导致的问题</h2><p>今天写了一个这样的函数</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">T&& <span class="title">f</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> T t;</span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line"> <span class="keyword">return</span> move(t);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这样的代码显然是错误的,因为右值引用实际上也是一种引用,而返回一个临时变量的引用是会出问题的。可以通过编译但是退出f时会报错(在vs2019上,理论上也有可能返回不正确的临时堆栈内容)。</p><p>以下的代码才是正确的演示,只要不反回临时变量的都行。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">S</span>></span></span><br><span class="line"><span class="class"><span class="title">S</span>&& <span class="title">forward</span>(<span class="title">typename</span> <span class="title">remove_reference</span><S>:</span>:type& a) <span class="keyword">noexcept</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">static_cast</span><S&&>(a);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>可以看出来我的目的是为了避免一次拷贝。</p><p>但是这样的代码也是错的。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">T <span class="title">f</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> T t;</span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line"> <span class="keyword">return</span> move(t);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>因为</p><p>实际上这种是不需要的。因为编译器会做返回值优化(Return Value Optimization)。在C++11标准中有如下规定:</p><blockquote><p>When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.</p></blockquote><p>直接return x;是NRVO支持的一种用例场景,可以做到多余的拷贝构造。编译器会自己选择使用拷贝构造还是move构造函数。</p><p>但是如果用std::move(x);那么可能会带来额外的影响:可能会阻止NRVO。也就是说可能需要额外的开销来执行move语义。</p><blockquote><p>学艺不精,哎。一直没有研究过右值作为返回值,今天出问题了。以后学东西还是要实践同行。</p></blockquote><h2 id="函数形参中的左值引用不能置入匿名变量(不会自动折叠)"><a href="#函数形参中的左值引用不能置入匿名变量(不会自动折叠)" class="headerlink" title="函数形参中的左值引用不能置入匿名变量(不会自动折叠)"></a>函数形参中的左值引用不能置入匿名变量(不会自动折叠)</h2><p>例</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">fun</span><span class="params">(T& t)</span></span>;</span><br><span class="line">func(T());</span><br></pre></td></tr></table></figure><p>T()不会自动折叠T&</p><p>只能这样写</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> t = T()</span><br><span class="line"><span class="keyword">void</span> fun(T& t);</span><br><span class="line">func(t);</span><br></pre></td></tr></table></figure><h2 id="头文件中不能出现定义"><a href="#头文件中不能出现定义" class="headerlink" title="头文件中不能出现定义"></a>头文件中不能出现定义</h2><p>只能出现声明哦,不然一定会出现链接问题。</p><p>像是全局变量应该在头文件中</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">extern</span> T t;</span><br></pre></td></tr></table></figure><p>.cpp中</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">T t = t0;</span><br></pre></td></tr></table></figure><h2 id="匿名对象就是右值,不能传入左值引用中"><a href="#匿名对象就是右值,不能传入左值引用中" class="headerlink" title="匿名对象就是右值,不能传入左值引用中"></a>匿名对象就是右值,不能传入左值引用中</h2><p>像是<code>T(arg...)</code>这样的匿名对象本质上和<code>1</code> <code>1.0</code>这样的数值常量差不多。如果你的函数参数是 <code>const T&</code> 或 <code>T&</code>,的话是不能正常调用的。事实上不能通过编译。因为在调用函数后匿名对象就析构了,然后函数里传进去的引用就没有意义了。</p><p>正确的函数格式</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">(T t)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">(T&& t)</span></span>;</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>之前我写过一篇长期更新的《我踩过的c++的坑》,因为时间很长,文章太长了,查看起来太麻烦了,所以以后遇到的坑都记在这篇续里</p>
<p><a href="https://www.intmian.com/2018/07/21/%E6%88%91%E8%B8%A9%E8%BF%87%E7%9A%84c++%E7%9A%84%E5%9D%91/">旧文链接</a></p>
<p><strong>持续更新</strong></p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="c++" scheme="https://www.intmian.com/tags/c/"/>
</entry>
<entry>
<title>C++ 中的多返回值的实现</title>
<link href="https://www.intmian.com/2019/05/25/c++%E5%A4%9A%E8%BF%94%E5%9B%9E%E5%80%BC/"/>
<id>https://www.intmian.com/2019/05/25/c++多返回值/</id>
<published>2019-05-25T08:28:15.000Z</published>
<updated>2019-05-25T13:53:16.884Z</updated>
<content type="html"><![CDATA[<p>本文将循序渐进的从最古老的C风格开始,一直讲到C++17中多返回值的实现方法</p><a id="more"></a><h2 id="C风格"><a href="#C风格" class="headerlink" title="C风格"></a>C风格</h2><h3 id="传入指针"><a href="#传入指针" class="headerlink" title="传入指针"></a>传入指针</h3><p>以指针形式传入待返回的值得地址,作为实参,并在类内对其赋值。</p><p>经典实现如下</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">(<span class="keyword">int</span> a, <span class="keyword">int</span> b, <span class="keyword">int</span> *c, <span class="keyword">int</span> *d)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// ... do sth with a,b</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 对*c,*d赋值</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>可以看出我们需要以<code>func(a, b, &c, &d)</code>这样的方式调用func,不仅不方便不直观,而且需要提前定义c, d,代码比较不简洁。而且输入输出不分离,也不大优雅。</p><h3 id="返回结构体"><a href="#返回结构体" class="headerlink" title="返回结构体"></a>返回结构体</h3><p>经典实现如下</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span>{</span></span><br><span class="line"> <span class="keyword">int</span> c;</span><br><span class="line"> <span class="keyword">int</span> d;</span><br><span class="line">} return_v;</span><br><span class="line"><span class="function">retuen_v <span class="keyword">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">// do sth</span></span><br><span class="line"> <span class="keyword">return</span> return_v{c, d};</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>麻烦就不说了,还污染了命名空间。而且再调用时,还要准备一个变量接受返回值,再从这个仅用一次的变量中取出需要的变量,太麻烦了。</p><h2 id="modern-c-风格"><a href="#modern-c-风格" class="headerlink" title="modern c++ 风格"></a>modern c++ 风格</h2><p>现代c++的多返回值得实现基本上用tuple实现,优雅而简洁。当然和python、go这种语言级的语法糖来说显得还是稍微麻烦一点的。不过有的人相较于语法糖形式的,说不定更喜欢这种学院派的泛型风格也说不定2333。</p><h3 id="为什么不用pair"><a href="#为什么不用pair" class="headerlink" title="为什么不用pair"></a>为什么不用pair</h3><ol><li>pair可以完全被tuple取代。</li><li>tuple泛用性更好。</li><li>tuple在之后的c++标准中,有着更为重要的地位。也就是说会有越来越多的语法支持。</li></ol><h3 id="c-11-风格"><a href="#c-11-风格" class="headerlink" title="c++11 风格"></a>c++11 风格</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><tuple></span></span></span><br><span class="line"></span><br><span class="line"><span class="built_in">std</span>::tuple<<span class="keyword">int</span>, <span class="keyword">int</span>> divide(<span class="keyword">int</span> dividend, <span class="keyword">int</span> divisor) {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">std</span>::make_tuple(dividend / divisor, dividend % divisor);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> quotient, remainder;</span><br><span class="line"></span><br><span class="line"> tie(quotient, remainder) = divide(<span class="number">14</span>, <span class="number">3</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">cout</span> << quotient << <span class="string">','</span> << remainder << <span class="built_in">endl</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>用<code>tie</code>来绑定返回值从<code>tuple</code>。虽然比较方便,但是<code>make_tuple</code>这种形式还是稍显扭曲。</p><blockquote><p>自从粗读了c++ stl的代码后,我越发觉得stl的作者太厉害了。就像是上文的这种多返回值语法,实现是非常精妙的。在不添加新的语法糖的情况下,在已有的语法框架下,实现了这么复杂的功能。这非常符合我少即是多的想法,而且统一性好多了2333。</p></blockquote><h3 id="c-17风格"><a href="#c-17风格" class="headerlink" title="c++17风格"></a>c++17风格</h3><blockquote><p><strong>warning</strong> 您的编译器未必支持这么新的语法</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><tuple></span></span></span><br><span class="line"></span><br><span class="line"><span class="built_in">std</span>::tuple<<span class="keyword">int</span>, <span class="keyword">int</span>> divide(<span class="keyword">int</span> dividend, <span class="keyword">int</span> divisor) {</span><br><span class="line"> <span class="keyword">return</span> {dividend / divisor, dividend % divisor};</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">auto</span> [quotient, remainder] = divide(<span class="number">14</span>, <span class="number">3</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">cout</span> << quotient << <span class="string">','</span> << remainder << <span class="built_in">endl</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>用了新的c++特性,绑定结构体,精妙而美丽。</p><h3 id="c-11-c-17混用"><a href="#c-11-c-17混用" class="headerlink" title="c++11/c++17混用"></a>c++11/c++17混用</h3><p>当然我们也没必要全部使用c++11的特性,或者全用c++17的特性。</p><p>他们不互相矛盾,可以这样混用</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><tuple></span></span></span><br><span class="line"></span><br><span class="line"><span class="built_in">std</span>::tuple<<span class="keyword">int</span>, <span class="keyword">int</span>> divide(<span class="keyword">int</span> dividend, <span class="keyword">int</span> divisor) {</span><br><span class="line"> <span class="keyword">return</span> {dividend / divisor, dividend % divisor};</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"> tie(quotient, remainder) = divide(<span class="number">14</span>, <span class="number">3</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">cout</span> << quotient << <span class="string">','</span> << remainder << <span class="built_in">endl</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h3><p>tuple技术没有显示地给出返回值的意义,仅有类型。也就是说你得在注释里给出。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">std</span>::tuple<<span class="keyword">int</span>, <span class="keyword">int</span>> divide(<span class="keyword">int</span> dividend, <span class="keyword">int</span> divisor); <span class="comment">// return {quotient, remainder}</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>warning</strong> 如果你的项目中这一点非常重要还是使用结构体法吧。<del>不过话说真的有人有这个需求吗。。。</del></p></blockquote>]]></content>
<summary type="html">
<p>本文将循序渐进的从最古老的C风格开始,一直讲到C++17中多返回值的实现方法</p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="c++" scheme="https://www.intmian.com/tags/c/"/>
</entry>
<entry>
<title>Effective STL 读后感</title>
<link href="https://www.intmian.com/2019/02/21/%E3%80%8Aeffective%20STL%E3%80%8B%E8%AF%BB%E5%90%8E%E6%84%9F/"/>
<id>https://www.intmian.com/2019/02/21/《effective STL》读后感/</id>
<published>2019-02-20T16:00:00.000Z</published>
<updated>2019-02-21T07:59:51.191Z</updated>
<content type="html"><![CDATA[<p><em>Effective STL</em> 这本书我是在年前从图书馆借的,最近回学校有时间就拜读了一遍。虽然有些地方(函数子,分配子,函数配连,分析机制等等 <del>这么一看,感觉好多啊</del> )还没有完全吃透,但是基本上也看的7788了。</p><a id="more"></a><h2 id="评测"><a href="#评测" class="headerlink" title="评测"></a>评测</h2><p><strong>本人的c++水平实在有限,只能从我的一点点经验里稍微说一点。</strong></p><h3 id="缺点"><a href="#缺点" class="headerlink" title="缺点"></a>缺点</h3><ol><li><p>成书时间过早,后面作者也没有很大的修改,导致了作者所说的<strong>STL</strong>和我们现在使用的<strong>STL</strong>有所区别,诸如<code>unordered_map</code>、<code>unordered_set</code>,这样好用的东西,作者没有着重笔墨,只是作为非标准库提了一嘴。</p></li><li><p>同样的因为成书相对较早,对于<strong>革命性的c++11标准</strong>里的新东西,笔者是基本上没有提到的,<code>智能指针</code>什么的也只是作为<code>boost</code>库里的版本提了一口。像<code>not1</code>、<code>bind2nd</code>,这样的东西在生产实践中事实上用的越来越少了,而<code>lambada</code>作为替代品则用的越来越多。虽然在STL,因为为了需求以及bind等历史因素,可能确定严格弱序,或者有序的一般都是三元以下的谓词,对于书中所采用的函数适配器<code>bind2nd</code>、<code>not1</code>,都是适用的。但是</p><ol><li><code>lambda</code>不需要考虑<strong>可配连</strong>的问题,也就是在在用函数时不用使用<code>fun_ptr</code>,将函数指针特化为可配连的,用函数子对象时,不用考虑继承那些<strong>奇奇怪怪的函数子类</strong>,省了很多力气。(当然虚函数的<strong>剥离</strong>,<strong>拷贝构造</strong>的代价,还是需要考虑的,如果你解决这些问题的方法是<code>bridge pattern</code>的话,<strong>内存管理</strong>也是要注意的,当然喽,<code>智能指针</code>解千愁)</li><li>功能比起<strong>自带</strong>的适配器强多了。</li><li>手写<strong>自定义函数适配器</strong>是高级技巧,而手写<code>lambda</code>不是。</li></ol></li><li><p>有些人可能觉得作者废话太多。</p></li><li><p>翻译有些生硬。例如。</p><ul><li><blockquote><p>你会受伤,如果不那么做的话。</p></blockquote></li></ul></li></ol><h3 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h3><ol><li>作为<strong>c++ 6E</strong>(<em>《Effective C++》《More Effective C++》《Effective Modern C++》《Effective STL》《Exceptional C++》《More Exceptional C++》</em>)系列的一员,Effective 系列的三儿子,成书质量非常的高,对于提高c++水平很有帮助。<strong>作者的c++水平很高</strong>,因此对于c++问题的理解非常透彻,看了本书可以大大提升作为c++程序员的STL水平。</li><li>本书作者对于很难理解的内容,不会堆砌大量的术语,<strong>不让人生厌</strong>。</li><li>此书对于效率的笔墨花了很多,观看本书对于<strong>程序速度</strong>的提升很有帮助。</li><li>有些章节教会了我们如何写出让别人看得懂得代码,对于读者的团队协作和软件工程都有所帮助。</li><li>此书对于<code>STL</code>的原理与构造都有所提及,不仅仅让人明白这样怎么做,还让人明白背后的机制。</li><li>此书作为一本<strong>技术书</strong>,却写的<strong>十分幽默</strong>,不让人感觉无聊。</li></ol><p><strong>总体来说这本书极其值得看值得买</strong></p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>以前听别人说c++太过于复杂,需要彻底的革新。当初我还是嗤之以鼻,认为c++的复杂都是需要的。但是在我的c++水平也有所上升之后,我才渐渐明白了他们。c++的高级技巧里充满了为了和过去不好的设计或者过于复杂的设计,交互而搞出的过于复杂的设计。不仅仅是我们为了使用c++而搞出来的高级技巧,甚至连标准也是这样,标准越出约厚。甚至这种历史的约束都影响了STL的命名空间,标准里先出现的东西占据了后出现的东西的位置,后出现的本该和它平行的东西却只能屈居人后,使得命名空间中的命名很不系统化、体系化(<code>mem_fun</code>、<code>mem_fun_pre</code>)。产生了很多为了复杂而复杂,和不明所以的东西。有人说c++标准需要的不是小修小补,而是壮士断腕。我是赞同的。历史上的很多过时的设计,没必要再去兼容它们了。</p><p>这么说未免过于悲观,最起码c++11以来的c++发展还是给这门老语言灌注了不少新的活力。</p>]]></content>
<summary type="html">
<p><em>Effective STL</em> 这本书我是在年前从图书馆借的,最近回学校有时间就拜读了一遍。虽然有些地方(函数子,分配子,函数配连,分析机制等等 <del>这么一看,感觉好多啊</del> )还没有完全吃透,但是基本上也看的7788了。</p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="c++" scheme="https://www.intmian.com/tags/c/"/>
</entry>
<entry>
<title>leetcode contest 121 writeup</title>
<link href="https://www.intmian.com/2019/01/28/leetcode%20%E7%AC%AC%20151%20%E5%9C%BA%E5%91%A8%E8%B5%9B%20writeup/"/>
<id>https://www.intmian.com/2019/01/28/leetcode 第 151 场周赛 writeup/</id>
<published>2019-01-28T03:17:05.000Z</published>
<updated>2019-01-30T12:29:51.777Z</updated>
<content type="html"><"></p><h3 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h3><p>使用<code>map</code>和<code>unordered_map</code></p><ol><li>用<code>map</code>映射<code>key</code>到\<<code>time</code>,<code>stamp</code>></li><li>用<code>unordered_map</code>映射<code>time</code>到<code>stamp</code></li></ol><p>前面用<code>map</code>的理由是保证常数级的查询时间</p><p>后面用<code>unordered_map</code>是为了尽快查出那个最大的<code>time</code>,如果使用<code>map</code>可能需要<strong>n</strong>级的时间。</p><h3 id="代码-1"><a href="#代码-1" class="headerlink" title="代码"></a>代码</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TimeMap</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="comment">/** Initialize your data structure here. */</span></span><br><span class="line">TimeMap() {</span><br><span class="line">}</span><br><span class="line"><span class="built_in">unordered_map</span><<span class="built_in">string</span>, <span class="built_in">map</span><<span class="keyword">int</span>, <span class="built_in">string</span>>> my_map;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">set</span><span class="params">(<span class="built_in">string</span> key, <span class="built_in">string</span> value, <span class="keyword">int</span> timestamp)</span> </span>{</span><br><span class="line"><span class="keyword">if</span> (my_map.find(key) != my_map.end())</span><br><span class="line">{</span><br><span class="line">my_map[key][timestamp] = value;</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">my_map[key] = <span class="built_in">map</span><<span class="keyword">int</span>, <span class="built_in">string</span>>();</span><br><span class="line">my_map[key][timestamp] = value;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="built_in">string</span> <span class="title">get</span><span class="params">(<span class="built_in">string</span> key, <span class="keyword">int</span> timestamp)</span> </span>{</span><br><span class="line"><span class="keyword">if</span> (my_map.find(key) == my_map.end())</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> <span class="string">""</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">{</span><br><span class="line"><span class="keyword">auto</span> &find_map = my_map[key];</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">auto</span> it = --find_map.end(); it != find_map.begin(); it--)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">if</span> ((*it).first <= timestamp)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> (*it).second;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> ((*find_map.begin()).first <= timestamp)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">return</span> (*find_map.begin()).second;</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="keyword">return</span> <span class="string">""</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><h2 id="最低票价"><a href="#最低票价" class="headerlink" title="最低票价"></a>最低票价</h2><h3 id="题目-2"><a href="#题目-2" class="headerlink" title="题目"></a>题目</h3><p><img src="https://i.loli.net/2019/01/30/5c518ea699197.png" alt="题目"></p><p><a href="https://leetcode-cn.com/contest/weekly-contest-121/problems/minimum-cost-for-tickets/" target="_blank" rel="noopener">最低票价</a></p><h3 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h3><p>因为求得是最优化问题,而且可以分成若干个阶段,因此我们很容易想到dp。因为最低票价显然是个一元谓词,我们就设dp(n)是第n天的最低票价。</p><p>先列出<strong>状态转移</strong>方程</p><p>$$<br>\begin{cases}dp_i = \min(dp_{i+1}+costs_0,dp_{i+7}+costs_1,dp_{i+2}+costs_{30}) & i\in days \<br>dp_i = dp_{i+1}&i \notin days \and i < \max(days) \<br>dp_i = 0 & i > \max(days)<br>\end{cases}<br>$$</p><p>然后注意下<strong>记忆优化</strong>,避免重复的迭代展开。搞个哈希表就行(<code>unordered_map</code>)。</p><blockquote><p>不优化的话复杂度就变成O(3 ^ n)</p></blockquote><h3 id="代码-2"><a href="#代码-2" class="headerlink" title="代码"></a>代码</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="built_in">unordered_map</span><<span class="keyword">int</span>, <span class="keyword">int</span>> dp_pre = <span class="built_in">unordered_map</span><<span class="keyword">int</span>, <span class="keyword">int</span>>();</span><br><span class="line"><span class="built_in">set</span><<span class="keyword">int</span>> days_traval = <span class="built_in">set</span><<span class="keyword">int</span>>();</span><br><span class="line"><span class="keyword">int</span> max_days;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dp</span><span class="params">(<span class="keyword">int</span> day, <span class="built_in">vector</span><<span class="keyword">int</span>>& costs)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">int</span> result;</span><br><span class="line"><span class="keyword">if</span> (dp_pre.find(day) != dp_pre.end())</span><br><span class="line"><span class="keyword">return</span> dp_pre[day];</span><br><span class="line"><span class="keyword">if</span> (day > max_days)</span><br><span class="line">{</span><br><span class="line">dp_pre[day] = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (days_traval.find(day) == days_traval.end())</span><br><span class="line">{</span><br><span class="line">result = dp(day + <span class="number">1</span>, costs);</span><br><span class="line">dp_pre[day] = result;</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">auto</span> && dp_datas = {dp(day+<span class="number">1</span>,costs)+costs[<span class="number">0</span>],dp(day + <span class="number">7</span>,costs) + costs[<span class="number">1</span>],dp(day + <span class="number">30</span>,costs) + costs[<span class="number">2</span>]};</span><br><span class="line">result =*min_element(dp_datas.begin(), dp_datas.end());</span><br><span class="line">dp_pre[day] = result;</span><br><span class="line"><span class="keyword">return</span> result;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">mincostTickets</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>>& days, <span class="built_in">vector</span><<span class="keyword">int</span>>& costs)</span> </span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">auto</span> day : days)</span><br><span class="line">{</span><br><span class="line">days_traval.insert(day);</span><br><span class="line">}</span><br><span class="line">max_days = *max_element(days.begin(),days.end());</span><br><span class="line"><span class="keyword">return</span> dp(<span class="number">1</span>,costs);</span><br><span class="line">}</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h2 id="按位与为零的三元组"><a href="#按位与为零的三元组" class="headerlink" title="按位与为零的三元组"></a>按位与为零的三元组</h2><h3 id="题目-3"><a href="#题目-3" class="headerlink" title="题目"></a>题目</h3><p><a href="https://leetcode-cn.com/contest/weekly-contest-121/problems/triples-with-bitwise-and-equal-to-zero/" target="_blank" rel="noopener">按位与为零的三元组</a></p><p><img src="https://i.loli.net/2019/01/30/5c519291b7c9d.png" alt="按位与为零的三元组"></p><h3 id="思路-3"><a href="#思路-3" class="headerlink" title="思路"></a>思路</h3><p>这个其实是一个<strong>数论题</strong>。。。</p><p>如果<strong>硬要做还挺麻烦的</strong>,但是似乎leetcode官方没有设好时间,所以穷举也可以。。。</p><p>更好的方法就看官方的吧。</p><h3 id="代码-3"><a href="#代码-3" class="headerlink" title="代码"></a>代码</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">countTriplets</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> A)</span> </span>{</span><br><span class="line"><span class="keyword">int</span> sum = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < A.size(); i++)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < A.size(); j++)</span><br><span class="line">{</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">0</span>; k < A.size(); k++)</span><br><span class="line"><span class="keyword">if</span> ((A[i] & A[j] & A[k]) == <span class="number">0</span>)</span><br><span class="line">{</span><br><span class="line">sum++;</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> sum;</span><br><span class="line">}</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>这次因为第一题<strong>看错题</strong>了,第三题<strong>摸鱼</strong>,导致没特别做好,就当长知识了吧-_-</p><p>垃圾hexo,加载latex公式时出错了。。。。。</p>]]></content>
<summary type="html">
<h2 id="概要"><a href="#概要" class="headerlink" title="概要"></a>概要</h2><p>第121周的leetcode周赛共有4题</p>
<blockquote>
<p><a href="https://leetcode-cn.com/contest/weekly-contest-121" target="_blank" rel="noopener">leetcode第121周周赛</a></p>
</blockquote>
<table>
<thead>
<tr>
<th style="text-align:center">题目</th>
<th style="text-align:center">难度</th>
<th style="text-align:center">知识点</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">不含AAA或BBB的字符串</td>
<td style="text-align:center">简单</td>
<td style="text-align:center">没有/<em>贪心</em></td>
</tr>
<tr>
<td style="text-align:center">基于时间的键值存储</td>
<td style="text-align:center">中等</td>
<td style="text-align:center">数据结构</td>
</tr>
<tr>
<td style="text-align:center">最低票价</td>
<td style="text-align:center">中等</td>
<td style="text-align:center">动态规划</td>
</tr>
<tr>
<td style="text-align:center">按位与为零的三元组</td>
<td style="text-align:center">困难</td>
<td style="text-align:center">数学</td>
</tr>
</tbody>
</table>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="算法" scheme="https://www.intmian.com/tags/%E7%AE%97%E6%B3%95/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
</entry>
<entry>
<title>如何重装系统</title>
<link href="https://www.intmian.com/2019/01/27/%E9%87%8D%E8%A3%85%E7%B3%BB%E7%BB%9F/"/>
<id>https://www.intmian.com/2019/01/27/重装系统/</id>
<published>2019-01-27T09:43:11.000Z</published>
<updated>2019-01-27T11:08:30.065Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>本来我是不想写这篇文章的<del>因为懒</del>。</p><p>但是有鉴于最近<strong>找我装系统的人太多</strong>了,再加上看见小白被无良商家骗于心不忍,就写篇教程吧-_-。</p><p>我会把装机的主要几个阶段讲一下,但是任何跟着提示稍微理解下就可以无风险走的小步骤就不讲了。</p><a id="more"></a><h2 id="装系统之前的准备"><a href="#装系统之前的准备" class="headerlink" title="装系统之前的准备"></a>装系统之前的准备</h2><p>首先要有个概念 <code>装系统是一件很简单的事</code>。电脑是一件给人用的 <strong>工具</strong> ,厂商没有理由设置门槛。装机是很简单的,<strong>但是最好不要随意重装系统,文件、软件重新安置太麻烦了</strong>。</p><h2 id="准备阶段"><a href="#准备阶段" class="headerlink" title="准备阶段"></a>准备阶段</h2><ul><li>物理准备<ul><li>一只8G以上U盘</li></ul></li><li>心理准备<ul><li>一小时不到的时间</li><li>一定的理解能力</li></ul></li></ul><h2 id="装机阶段"><a href="#装机阶段" class="headerlink" title="装机阶段"></a>装机阶段</h2><ol><li>找到你所用电脑的<strong>主板</strong>厂商(<em>不需要拆机箱,直接用aida64或者别的软件看</em>)以及<strong>型号</strong>,如果是笔记本就直接使用<strong>电脑型号</strong>。</li><li>搜索 xxxx(<em>你的主板型号</em>) 进入bios的<strong>快捷键</strong>,并记住它。</li><li>在<a href="https://msdn.itellyou.cn/" target="_blank" rel="noopener">msdn 我告诉你</a>,这个网站上找到你要装的系统的 <strong>64位</strong> <strong>最新版本</strong>。</li><li>下载它。</li><li><strong>格式化</strong>U盘。</li><li>把下载的镜像文件用解压软件<strong>解压到U盘</strong>。</li><li><strong>备份c盘里的文件</strong>,其它盘看你想不想顺便格式化。</li><li>重启,并在开机的过程中<strong>狂按</strong>你记住的<strong>快捷键</strong>。</li><li>你将会进入一个蓝蓝白白的界面(bios),请动用你的英语水平进行翻译后使用。</li><li>你有两个选择<ul><li>UEFI路线<ol><li>找到<strong>boot</strong>里面的<strong>UEFI</strong>设置为<strong>ENABLE</strong></li><li><strong>重启</strong>,开机过程中<strong>狂按</strong>快捷键</li><li>会看见弹出一个<strong>对话框</strong>,选择 <strong>WINDOWS</strong> <strong>BOOT</strong> <strong>MANAGER</strong></li></ol></li><li>传统路线<ol><li>找到<strong>boot</strong>里面的<strong>启动顺序</strong></li><li>按照操作指示,把<strong>U盘</strong>放到最上面</li><li>重启</li></ol></li></ul></li><li>在Windows安装指示界面中,按照指示<strong>操作</strong>进行操作<ul><li>分区格式化请<strong>谨慎</strong></li></ul></li><li>开机后联网会<strong>自动</strong>安装驱动</li><li>在你的显卡的对应官网下载安装<strong>显卡驱动</strong></li><li>在设备管理器中查看有无设备上有<strong>感叹号标识</strong>,若有,去官网下载驱动。</li><li>是否安装<em>360</em>、<em>驱动大师</em>等软件自行判断<ul><li>我推荐ccleaner、火绒</li></ul></li><li>重启进入bios,把设置还原为改动之前的</li></ol><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>简单的电脑维护其实很简单(<del>废话</del>),只要不<strong>先入为主</strong>地认为自己不会,<strong>善用搜索引擎</strong>,不懂的东西<strong>稍微研究</strong>一下,一般都没有问题的。</p><blockquote><p>我不对任何本文后果负责,还请读者们自行判断。</p></blockquote>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>本来我是不想写这篇文章的<del>因为懒</del>。</p>
<p>但是有鉴于最近<strong>找我装系统的人太多</strong>了,再加上看见小白被无良商家骗于心不忍,就写篇教程吧-_-。</p>
<p>我会把装机的主要几个阶段讲一下,但是任何跟着提示稍微理解下就可以无风险走的小步骤就不讲了。</p>
</summary>
<category term="一些小教程" scheme="https://www.intmian.com/categories/%E4%B8%80%E4%BA%9B%E5%B0%8F%E6%95%99%E7%A8%8B/"/>
<category term="电脑维护" scheme="https://www.intmian.com/tags/%E7%94%B5%E8%84%91%E7%BB%B4%E6%8A%A4/"/>
</entry>
<entry>
<title>sql中的连接</title>
<link href="https://www.intmian.com/2019/01/23/sql%20%E8%BF%9E%E6%8E%A5/"/>
<id>https://www.intmian.com/2019/01/23/sql 连接/</id>
<published>2019-01-23T06:12:15.000Z</published>
<updated>2019-01-30T11:48:43.770Z</updated>
<content type="html"><![CDATA[<p>一些关于sql语句的连接的小知识</p><a id="more"></a><h1 id="为什么要用连接"><a href="#为什么要用连接" class="headerlink" title="为什么要用连接"></a>为什么要用连接</h1><h2 id="查询例子"><a href="#查询例子" class="headerlink" title="查询例子"></a>查询例子</h2><p>下面我举个例子</p><p>有这样两张表</p><p><strong>student</strong></p><table><thead><tr><th>id</th><th>name</th><th>class_id</th></tr></thead><tbody><tr><td>1</td><td>mian</td><td>1</td></tr><tr><td>2</td><td>mki</td></tr></tbody></table><p><strong>class</strong></p><table><thead><tr><th>id</th><th>name</th></tr></thead><tbody><tr><td>1</td><td>cs</td></tr><tr><td>2</td></tr></tbody></table><p>如果<strong>我们需要查询每个学生选的课</strong>,按照传统的方法我们可以</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> student.name,class.name</span><br><span class="line"><span class="keyword">from</span> student,<span class="keyword">class</span></span><br><span class="line"><span class="keyword">where</span> student.class_id = class.id</span><br></pre></td></tr></table></figure><p>但是如果熟悉sql原理的同学就会知道这样的 <code>from student,class</code> 这样的语句本质上是求<br>$$<br>student \times class<br>$$<br>(笛卡尔积)</p><p>生成了这样一张表</p><table><thead><tr><th>id</th><th>name</th><th>class_id</th><th>id</th><th>name</th></tr></thead><tbody><tr><td>1</td><td>mian</td><td>1</td><td>1</td><td>cs</td></tr><tr><td>1</td><td>mian</td><td>1</td><td>2</td><td></td></tr><tr><td>2</td><td>mki</td><td></td><td>1</td><td>cs</td></tr><tr><td>2</td><td>mki</td><td></td><td>2</td></tr></tbody></table><p>再从中选择<br>$$<br>\sigma _{student.class_id=class.id}<br>$$<br>这样子显然当student和class非常大时,查询效率太低。</p><h1 id="连接"><a href="#连接" class="headerlink" title="连接"></a>连接</h1><h2 id="数学"><a href="#数学" class="headerlink" title="数学"></a>数学</h2><p>既然<strong>笛卡尔迪</strong>行不通,我们就想到了我们的老朋友连接(<em>join</em>)<br>$$<br>student\Join class<br>$$<br>这样子就可以衍生出一张不比代查询的两张表大的表的。</p><h2 id="用法"><a href="#用法" class="headerlink" title="用法"></a>用法</h2><p>此处我们就应该用 <strong>join</strong> 这种sql语法</p><p>join跟据匹配生成元组的方式分为四种</p><ul><li>内连接 <em>inner join</em></li><li>左连接 <em>left join</em></li><li>右连接 <em>right join</em></li><li>全连接 <em>full join</em></li></ul><h3 id="内连接"><a href="#内连接" class="headerlink" title="内连接"></a>内连接</h3><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4><p>生成的行数为左表右表全部匹配的行</p><h4 id="用法-1"><a href="#用法-1" class="headerlink" title="用法"></a>用法</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from sdudent</span><br><span class="line">inner join class</span><br><span class="line">on student.class_id = class.id</span><br></pre></td></tr></table></figure><h4 id="结果"><a href="#结果" class="headerlink" title="结果"></a>结果</h4><table><thead><tr><th>id</th><th>name</th><th>class_id</th><th>id</th><th>name</th></tr></thead><tbody><tr><td>1</td><td>mian</td><td>1</td><td>1</td><td>cs</td></tr></tbody></table><h3 id="左连接"><a href="#左连接" class="headerlink" title="左连接"></a>左连接</h3><h4 id="定义-1"><a href="#定义-1" class="headerlink" title="定义"></a>定义</h4><p>左表的所有元组加上匹配的右表元组</p><h4 id="用法-2"><a href="#用法-2" class="headerlink" title="用法"></a>用法</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from sdudent</span><br><span class="line">left join class</span><br><span class="line">on student.class_id = class.id</span><br></pre></td></tr></table></figure><h4 id="结果-1"><a href="#结果-1" class="headerlink" title="结果"></a>结果</h4><table><thead><tr><th>id</th><th>name</th><th>class_id</th><th>id</th><th>name</th></tr></thead><tbody><tr><td>1</td><td>mian</td><td>1</td><td>1</td><td>cs</td></tr><tr><td>2</td><td>mki</td><td></td><td></td></tr></tbody></table><h3 id="右连接"><a href="#右连接" class="headerlink" title="右连接"></a>右连接</h3><h4 id="定义-2"><a href="#定义-2" class="headerlink" title="定义"></a>定义</h4><p>右表的所有元组加上匹配的左表元组</p><h4 id="用法-3"><a href="#用法-3" class="headerlink" title="用法"></a>用法</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from sdudent</span><br><span class="line">right join class</span><br><span class="line">on student.class_id = class.id</span><br></pre></td></tr></table></figure><h4 id="结果-2"><a href="#结果-2" class="headerlink" title="结果"></a>结果</h4><table><thead><tr><th>id</th><th>name</th><th>class_id</th><th>id</th><th>name</th></tr></thead><tbody><tr><td>1</td><td>mian</td><td>1</td><td>1</td><td>cs</td></tr><tr><td></td><td></td><td></td><td>2</td></tr></tbody></table><h3 id="全连接"><a href="#全连接" class="headerlink" title="全连接"></a>全连接</h3><h4 id="定义-3"><a href="#定义-3" class="headerlink" title="定义"></a>定义</h4><p>所有左右表的元组相互匹配</p><h4 id="用法-4"><a href="#用法-4" class="headerlink" title="用法"></a>用法</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">from sdudent</span><br><span class="line">full join class</span><br><span class="line">on student.class_id = class.id</span><br></pre></td></tr></table></figure><h4 id="结果-3"><a href="#结果-3" class="headerlink" title="结果"></a>结果</h4><table><thead><tr><th>id</th><th>name</th><th>class_id</th><th>id</th><th>name</th></tr></thead><tbody><tr><td>1</td><td>mian</td><td>1</td><td>1</td><td>cs</td></tr><tr><td>2</td><td>mki</td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td>2</td></tr></tbody></table><h1 id="后话"><a href="#后话" class="headerlink" title="后话"></a>后话</h1><p><del>Typora 真香</del></p><p><del>Latex 真香</del></p>]]></content>
<summary type="html">
<p>一些关于sql语句的连接的小知识</p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="sql" scheme="https://www.intmian.com/tags/sql/"/>
</entry>
<entry>
<title>在vs2017进行泛型模板编程的一些笔记</title>
<link href="https://www.intmian.com/2018/12/01/%E6%B3%9B%E5%9E%8B/"/>
<id>https://www.intmian.com/2018/12/01/泛型/</id>
<published>2018-12-01T12:09:00.000Z</published>
<updated>2019-01-24T09:37:59.723Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>我周末用<strong>c++</strong>,写数据结构的作业,出于<del>装逼</del>炫技(<del>这两个词好像没差</del>)的目的,我用<strong>oop</strong>的思想,和<strong>现代c++</strong>的语法来写作业。</p><p>其中我很自然的使用了<strong>泛型</strong>加上一些一些工程技巧。</p><p>而很遗憾的的是,当中出现了非常多的一些问题,一些是由于我对于c++的学习还不是很熟练,另一些则是因为编译器对于modern c++支持得不好,或者vs对它支持的不好。</p><a id="more"></a><h2 id="模板类中的模板类中的子类"><a href="#模板类中的模板类中的子类" class="headerlink" title="模板类中的模板类中的子类"></a>模板类中的模板类中的子类</h2><p>读上去好像有点绕口,我们举个<strong>栗子</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">T</span>></span></span><br><span class="line"><span class="class"><span class="title">class</span> <span class="title">O</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="built_in">vector</span><T> ts;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> O(<span class="built_in">vector</span><T> sourse)</span><br><span class="line"> :ts(sourse)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">vector</span><T>::itereator it = ts.begin();</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>看上去没啥问题,可是一旦我们编译,就会</p><p><img src="https://i.loli.net/2018/12/01/5c0241bb7d2f8.png" alt="错误"></p><p>只是<strong>为什么</strong>呢?</p><p>因为<code>vector<T>::itereator</code>这段语句内,因为<code>vector<T></code>是不确定的,所以我们的编译器无法确认所谓的iteratoe(注:图中的代码,单词打错了,但是不影响结果,望别介意)是<code>vector<T></code>的子类还是静态变量</p><blockquote><p>注:子类这个说法是不准确的,详见stl源码</p></blockquote><p>二义性是计算机系统难以接受的,所以报错。</p><blockquote><p>至于为什么IDE不报错,又是另一个故事了</p></blockquote><p>为了消除二义性</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span><<span class="class"><span class="keyword">class</span> <span class="title">T</span>></span></span><br><span class="line"><span class="class"><span class="title">class</span> <span class="title">O</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="built_in">vector</span><T> ts;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> O(<span class="built_in">vector</span><T> sourse)</span><br><span class="line"> :ts(sourse)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">typename</span> <span class="built_in">vector</span><T>::iterator;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>像我这样加上<code>typename</code>就可以消除二义性,声明后面的<code>iterator</code>是一个类型,而非一个变量。</p><h2 id="没有提示,没有报错"><a href="#没有提示,没有报错" class="headerlink" title="没有提示,没有报错"></a>没有提示,没有报错</h2><p>像是我们上文的代码,如果你的IDE有自动补全的话,你就会发现<code>ts.</code>这样的代码会触发自动补全而<code>vector<T></code>这样的代码就不行。</p><center><img src="https://i.loli.net/2018/12/01/5c024a663c6b6.png" alt="有"></center><br><center><img src="https://i.loli.net/2018/12/01/5c024a4618fb7.png" alt="没有"></center><p>这可能有比较深的原因,但是挺坑的,就记一下吧</p><p>没有动态报错情况详见代码</p><center><img src="1.png" alt="有"></center><p>对于模板函数或者模板类内部的代码,不会进行动态检验,因此使用vs写的时候,我们的体验就回归了vc++(<del>==</del>)。</p><blockquote><p><del>至于原因,我咨询了大佬,大佬也不知道,那就凉凉喽</del></p></blockquote><h2 id="error-type的原因"><a href="#error-type的原因" class="headerlink" title="error type的原因"></a>error type的原因</h2><p>出现这种情况有两种可能</p><ul><li>参数类型写错了,这是绝大多数的情况,因为vs的类型推导十分zz,再加上没有动态检验,就会出现类型推到错误,也就是说函数的第一个参数写错了,后面的参数以及函数体里的变量都会显示error-type</li><li>类的顺序错了,不说了,太zz了</li></ul><h2 id="分离编译"><a href="#分离编译" class="headerlink" title="分离编译"></a>分离编译</h2><p>如果你恰好遇到了编译失败,原因是符号问题,那你可能是吃了分离编译的亏,因为,现在的编译器没有一个支持泛型的分离编译的。因为编译是对单个文件进行的,之后再进行链接。</p><pre><code>error LNK2019: 无法解析的外部符号 "void __cdecl func< int>(int const &)" (??$func@H@@YAXABH@Z)</code></pre><p>我们来复习一下模板的实现</p><ol><li>程序员写出模板(例如模板函数)</li><li>程序员在别的地方确立对于模板的调用</li><li>编译器将模板的实例化调用符号化为符号</li><li>根据符号来生成对应符号化的模板函数</li></ol><p>也就是说当编译过程一过,编译器将不会再去实例化函数</p><p>参考一位大佬的回答</p><blockquote><p>原因出现在分离编译模式上。在分离编译模式下,func.cpp会生成一个目标文件为func.obj,由于在func.cpp文件中,并没有发生函数模板调用,所以不会将函数模板func< T>实例化为模板函数func< int>,也就是说,在func.obj中无法找到关于模板函数func< int>的实现代码。在源文件main.cpp中,虽然函数模板被调用,但由于没有模板代码,也不能将其实例化。也就是说,在main.obj中也找不到模板函数func< int>的实现代码。这样,在连接的时候就会出现func< int>没有定义的错误。</p></blockquote><p>所以要把函数的定义和声明放在同一个文件</p><blockquote><p>在同一个文件里进行类似调用也行,但是不推荐</p></blockquote><p><strong>和普通函数不同的是,这里不会报函数重定义的错,这是对于模板函数的特殊照顾</strong></p><h2 id="泛型的尖括号不补全"><a href="#泛型的尖括号不补全" class="headerlink" title="泛型的尖括号不补全"></a>泛型的尖括号不补全</h2><p>这问题请找罪魁祸首微软</p><h2 id="静态函数成员的一些问题"><a href="#静态函数成员的一些问题" class="headerlink" title="静态函数成员的一些问题"></a>静态函数成员的一些问题</h2><p>当我们定义一些类的静态方法时,我们会很震惊的发现,vs把静态方法的声明和下面的定义视为两个符号,而定义的函数体内,会失去绝大多数高亮补全,或者报错。而且内部的符号在vs中全部是未定义状态。而编译器最后解析的时候都是一视同仁的。</p><h3 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h3><p>可以考虑将定义和声明放在一起<del>,但是并没有解决实际问题23333</del></p><p>至于真正的解决方法,只有等vs更新了。</p><h2 id="模板类内双重模板与auto的推导错误"><a href="#模板类内双重模板与auto的推导错误" class="headerlink" title="模板类内双重模板与auto的推导错误"></a>模板类内双重模板与auto的推导错误</h2><p>假定有</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">ShowProcess</span><span class="params">(<span class="built_in">vector</span><<span class="built_in">vector</span><T>> elements, <span class="built_in">string</span> tip)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">cout</span> << tip << <span class="built_in">endl</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> line : elements)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> element : line)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span> << setw(<span class="number">4</span>) << element;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">cout</span> << <span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">cout</span> << <span class="built_in">endl</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>按照正常情况,这段代码一点问题都没有。</p><p>实际上这里会出现推导错误</p><p>line会被推导为T类型,然后雪崩</p><p>应该改为</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">ShowProcess</span><span class="params">(<span class="built_in">vector</span><<span class="built_in">vector</span><T>> elements, <span class="built_in">string</span> tip)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">cout</span> << tip << <span class="built_in">endl</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="built_in">vector</span><T> line : elements)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> element : line)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span> << setw(<span class="number">4</span>) << element;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">cout</span> << <span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">cout</span> << <span class="built_in">endl</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>我周末用<strong>c++</strong>,写数据结构的作业,出于<del>装逼</del>炫技(<del>这两个词好像没差</del>)的目的,我用<strong>oop</strong>的思想,和<strong>现代c++</strong>的语法来写作业。</p>
<p>其中我很自然的使用了<strong>泛型</strong>加上一些一些工程技巧。</p>
<p>而很遗憾的的是,当中出现了非常多的一些问题,一些是由于我对于c++的学习还不是很熟练,另一些则是因为编译器对于modern c++支持得不好,或者vs对它支持的不好。</p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="c++" scheme="https://www.intmian.com/tags/c/"/>
</entry>
<entry>
<title>耦合与解耦</title>
<link href="https://www.intmian.com/2018/10/23/%E8%A7%A3%E8%80%A6/"/>
<id>https://www.intmian.com/2018/10/23/解耦/</id>
<published>2018-10-23T05:58:27.000Z</published>
<updated>2019-01-25T07:20:28.442Z</updated>
<content type="html"><![CDATA[<p>高内聚,低耦合是<del>你们</del>我一直所追求的目标<br><a id="more"></a></p><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>本人只是个菜鸡,只是写一些自己对于架构的一些小小的理解,可能会出偏差</p><h2 id="何为耦合"><a href="#何为耦合" class="headerlink" title="何为耦合"></a>何为耦合</h2><p><strong>耦合性</strong>(英语:Coupling,dependency。或称耦合力或耦合度)是一种软件工程的度量,是指一程序中,模块及模块之间信息或参数依赖的程度。</p><p>内聚性是一个和耦合性相对的概念,一般而言低耦合性代表高内聚性,反之亦然。耦合性和内聚性都是由提出结构化设计概念的赖瑞·康斯坦丁所提出。低耦合性是结构良好程序的特性,低耦合性程序的可读性及可维护性会比较好。</p><p>看到了上面的那句话,可能会感觉概念还是有所模糊。我们毕竟是写代码的不是写文章的嘛,也就不需要说那么多没什么用的废话了。</p><p>也就是说我们的一个程序中几个<strong>不同</strong>的<strong>基本模块</strong>(可能是函数、类或者更小的基本单位)中存在着互相调用或者互相依赖的行为。</p><p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Coupling_sketches_cropped_1.svg/400px-Coupling_sketches_cropped_1.svg.png" alt="耦合"></p><h2 id="耦合的例子"><a href="#耦合的例子" class="headerlink" title="耦合的例子"></a>耦合的例子</h2><h3 id="例子1"><a href="#例子1" class="headerlink" title="例子1"></a>例子1</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">change</span><span class="params">(<span class="keyword">const</span> <span class="built_in">vector</span><<span class="keyword">int</span>>& source)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> GetTool(<span class="string">"H_1"</span>)->add(source[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">if</span> (source[<span class="number">1</span>] > <span class="number">10</span>)</span><br><span class="line"> GetTool(<span class="string">"A_0"</span>)->change(source[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">if</span> (source[<span class="number">1</span>] < <span class="number">10</span>)</span><br><span class="line"> GetTool(<span class="string">"A_1"</span>)->change(source[<span class="number">1</span>]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>举这一个并不极端的例子,是因为<del>我编不出来了</del>这是我平时碰到的真实的问题。当我写完代码是又回头看了一眼,发现。</p><p><strong>我*</strong>。</p><p><del>他妈的</del>应该是source[2]…于是我一一把他们从1改为2。也许你们觉得这也没什么大不了的,不就是<strong>一一替换</strong>嘛,有什么大不了的。但是如果我给你个500行的复合模块,然后你把source[2]写成了source[1],而且在函数的正确的逻辑中本来就有source[1]。那我们就不能简单的替换,而需要从头审逻辑,再改。甚至可能需要重写,这个代价就太大了。</p><p>这就是耦合的一种,<strong>过度</strong>(自己体会)使用了其他的模块的数据</p><h3 id="例子2"><a href="#例子2" class="headerlink" title="例子2"></a>例子2</h3><p>举个比较zz的例子</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">xxx_0 = xxx_0 * <span class="number">11</span> + <span class="number">1</span>;</span><br><span class="line">xxx = ToList(xxx_0);</span><br><span class="line">GetTool(<span class="string">"IDX"</span>)->add(xxx);</span><br></pre></td></tr></table></figure><p>这样的代码大家一定经常用到。有些人(<del>我</del>),经常性的将这些段落直接复制粘贴来来去去。最后在改动的时候,就需要全篇的瞎瘠薄乱改,最后浪费了巨量的时间。</p><h3 id="例子3"><a href="#例子3" class="headerlink" title="例子3"></a>例子3</h3><p>比方说我们有菜单类和按钮类。而按钮显然是在菜单里的。</p><p>我们现在是把按钮写死在菜单里好呢,还是各自独立好呢。</p><p>显然的,自然是同为独立类,再讲按键映射到菜单里好。因为菜单和按钮显然不是固定的关系,一个菜单拥有不定数量的按钮。如果写在一起的话,其实是很僵化的,换言之,耦合度太高,不利于维护和扩展。我们应该在菜单里以引用表的形式将按钮组合进去</p><h3 id="例子4"><a href="#例子4" class="headerlink" title="例子4"></a>例子4</h3><p>想必大家对于java的set、get这个段子,应该有所耳熟,可是为什么这么写呢。</p><p>主要是为了<strong>解耦</strong>。我呢,架构能力很差,就引用大佬的话来说说吧。</p><blockquote><p>很多人,并不是面向对象学得不好,但总觉得差什么,我也经历过,面向对象,封装,多态,继承,学过的人都知道,都认为自己了解了,其实不然,很多很奇妙的因素,让你误解了,大部分的人认为封装很简单,其实大错特错了,封装是最奇妙的,也是最难用好的。只要你记住以下原则,必然能很好地用好封装,成员尽量使用protected和private,不要去使用public.尽量不要提供给外部对成员属性getter的接口,意思就是不要暴露成员,为什么要这样呢?很简单,暴露成员属性必然会导致自身业务的外泄,业务外泄,会导致,类之间的无谓耦合,如A类有成员a,而程序需要对a数据改变,而你提供一个B类可以访问a成员的getter接口,B类在其自身对a修改,看上去没什么,实际上,就是类耦合,对a的修改是类A的职务,由于习惯的提供getter,导致了,在写类B的时候错误地添加了修改业务,使类A内聚能力降低,程序逐步庞大必然会越发明显,真所谓牵一发动全身,小程序确实是很难看出问题所在。</p></blockquote><h2 id="如何避免耦合"><a href="#如何避免耦合" class="headerlink" title="如何避免耦合"></a>如何避免耦合</h2><blockquote><p>我呢水平一般,只能提出一点点微小的建议</p></blockquote><ul><li>大的函数如果有可能只用到小的功能时,一定要把它分割。</li><li>如果重复的一部分反复用到的话,需要注意把它单独拿出来。</li><li>注意封装与设计模式。</li></ul><h2 id="具体实现方法"><a href="#具体实现方法" class="headerlink" title="具体实现方法"></a>具体实现方法</h2><h3 id="part-1"><a href="#part-1" class="headerlink" title="part 1"></a>part 1</h3><p>先看一段代码</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Set</span><span class="params">(MODE mode)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">switch</span> (mode)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">case</span> A:</span><br><span class="line"> ...</span><br><span class="line"> <span class="keyword">case</span> B:</span><br><span class="line"> ...</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> assert(<span class="literal">false</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这是一个实际程序中的设置方法,其中MODE是一个枚举类。根据解耦的思想应该改为。<br> void SetA(…)<br> …<br> void SetB(…)<br> …<br> …<br> void Set(MODE mode)<br> {<br> switch (mode)<br> {<br> case A:<br> SetA(…);<br> case B:<br> SetB(…);<br> default:<br> assert(false);<br> }<br> }</p><h3 id="part-2"><a href="#part-2" class="headerlink" title="part 2"></a>part 2</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">config_add = None</span><br><span class="line">def SetConfigAdd():</span><br><span class="line"> global config_add</span><br><span class="line"> config_add = xxx</span><br><span class="line">def PushSetToFile():</span><br><span class="line"> # use config_add to <span class="keyword">do</span> sth</span><br></pre></td></tr></table></figure><p>像是这样的代码就不大好,全局的设置变量是一种相当不安全、不专业的行为(<del>但是我很喜欢啊</del>)。</p><p>应该在需要出现<code>config_add</code>的最大作用域(不超过主函数),声明config_add,把它作为<strong>引用</strong>或者<strong>常引用</strong>映射进去。(特指某些语言)</p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>架构设计对于程序员要求非常高。我只学了一些皮毛,甚至有些方法都只是我自己想的。所以只做参考吧。</p><p><strong>学习!学习!</strong></p>]]></content>
<summary type="html">
<p>高内聚,低耦合是<del>你们</del>我一直所追求的目标<br>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="架构" scheme="https://www.intmian.com/tags/%E6%9E%B6%E6%9E%84/"/>
</entry>
<entry>
<title>关于谷歌c++编程规范</title>
<link href="https://www.intmian.com/2018/08/11/%E5%85%B3%E4%BA%8E%E8%B0%B7%E6%AD%8Cc-%E7%BC%96%E7%A8%8B%E8%A7%84%E8%8C%83%E7%9A%84%E4%B8%80%E4%BA%9B%E7%90%86%E8%A7%A3/"/>
<id>https://www.intmian.com/2018/08/11/关于谷歌c-编程规范的一些理解/</id>
<published>2018-08-11T03:17:05.000Z</published>
<updated>2019-01-24T12:17:23.125Z</updated>
<content type="html"><![CDATA[<p>良好的命名真的很重要</p><a id="more"></a><h2 id="谷歌命名规范"><a href="#谷歌命名规范" class="headerlink" title="谷歌命名规范"></a>谷歌命名规范</h2><p><strong>一个图片大纲</strong></p><div align="center"><br><img src="google.png" alt="图片大纲"><br></div><p>附上我看见过的最全面的博客</p><p><a href="http://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/contents/" target="_blank" rel="noopener">谷歌c++规范</a></p><h2 id="为啥不用匈牙利命名法"><a href="#为啥不用匈牙利命名法" class="headerlink" title="为啥不用匈牙利命名法"></a>为啥不用匈牙利命名法</h2><p>早期坚定拥护匈牙利命名法的Microsoft在 .NET Framework后,已经不再建议程序员使用匈牙利命名法了。</p><p>微软新的变量名称建议General Naming Conventions原文如下:</p><blockquote><p>Donot use Hungarian notation. Hungarian notation isthe practice of including a prefix in identifiers to encode some metadata aboutthe parameter, such as the data type of the identifier.</p></blockquote><p>附上一句很经典的原话:</p><blockquote><p>“避免使用匈牙利记法,它会让你的承诺落空。赘物并非信息,而是混淆耳目的伪信息。”</p></blockquote><h2 id="谷歌规范检查工具"><a href="#谷歌规范检查工具" class="headerlink" title="谷歌规范检查工具"></a>谷歌规范检查工具</h2><p>Cpplint是一个python脚本,Google使用它作为自己的C++代码规范检查工具。如果你所在的公司也使用Google C++代码规范,那么你有必要了解下Cpplint。</p><p> 下面说一下Cpplint在windows下的简单使用:</p><ol><li><p>从<a href="http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py" target="_blank" rel="noopener">此处</a>下载cpplint.py源码,并将其存放到D:\soft\Cpplint\cpplint.py中;</p></li><li><p>安装python2,并将D:\ProgramFiles\Python27 添加到系统环境变量Path中;</p></li></ol><p>vs用户可以参考<a href="https://www.jianshu.com/p/64aa95820165" target="_blank" rel="noopener">这个博文</a>来进行配置。</p><hr>]]></content>
<summary type="html">
<p>良好的命名真的很重要</p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="c++" scheme="https://www.intmian.com/tags/c/"/>
</entry>
<entry>
<title>hexo原生无插件快速引入图片</title>
<link href="https://www.intmian.com/2018/07/28/hexo%E5%8E%9F%E7%94%9F%E6%97%A0%E6%8F%92%E4%BB%B6%E5%BF%AB%E9%80%9F%E5%BC%95%E5%85%A5%E5%9B%BE%E7%89%87/"/>
<id>https://www.intmian.com/2018/07/28/hexo原生无插件快速引入图片/</id>
<published>2018-07-28T09:43:11.000Z</published>
<updated>2019-01-25T07:26:25.149Z</updated>
<content type="html"><</span><br></pre></td></tr></table></figure><br><br>我们要不把图片传到<strong>图床</strong>,<del><strong>要不盗链</strong></del>。<br><br>### hexo方法<br><br>#### 文件放在哪<br><br>但是我们今天用的是hexo,可以把本地的一些文件传到hexo博客在你的托管文件夹里面。<br><br>我们有两种方法<br><br><em> 传到source文件夹中然后用相对路径访问它。</em> 传到与你的markdown同名的文件夹里,然后用相对路径访问它。<br><br>毫无疑问,前一种方法存在命名空间混乱而且路径较长的问题,我们选择无视。<br><br>#### 开启自动创建文件夹<br><br>在hexo中,我们在没有hexo_gui的情况下,我们会使用<code>hexo new xxx</code>来创建md文件。<br><br>如果我们把hexo配置文件中的<code>post_asset_folder</code>选项配置为<strong>true</strong>,就可以在使用<code>new</code>命令时自动生成对应的文件夹。我们把图片放在里面就会一起上传。<br><br>#### 在hexo使用文件夹里的图片<br><br>我们依然使用<code>![]()</code>来创建图片链接。此时我们的编辑器会提示补全,以本文为例,会被补全为<br><br><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><br><br>我们试着使用本地测试的方式于是我们会发现图片,在编辑器里被加载出来了,在博客中没有被加载出来,于是我们怀疑hexo在上传时改变了文件夹的结构。于是我传到了github上去试了一试,果不其然,发现图片与博客被解析到了同级文件夹中。于是正确的使用方法是<br><br><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><br><br>虽然很遗憾的是编辑器的预览里面看不见这玩意。<br><br>当然使用hexo独有的插入图片的语法也是一样,需要使用相同的技巧。<br><br>当然在我目前的3.0版本这两种语法的效果是一样的…<br><br>## 居中显示<br><br>如果一个图片比较小的话,在markdown里面直接插入是很难看的。<br><br>但是markdown支持html语法。于是我们可以把<code></code>改为<br><br><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><div align=center></span><br><span class="line"></span><br><span class="line"></div></span><br></pre></td></tr></table></figure><br><br>效果如下<br><img src="1.png" alt="插件错误"><br><br>—<br><br><div align="center"><br> <img src="1.png" alt="插件错误"><br></div><p>当然我现在使用的编辑器并不能预览会把命令解析为文字,但在hexo中亲测可用。</p><hr><p>编辑器中,我看见的预览是↓</p><p><img src="2.png" alt="无法加载"></p><p>那也是没办法的事嘛。md普通话和方言之间确实有所差异。</p>]]></content>
<summary type="html">
<h2 id="前情提要"><a href="#前情提要" class="headerlink" title="前情提要"></a>前情提要</h2><p>说出来你可能不信,笔者常年不知道如何在hexo里面上传图片,导致有些图片都是网上找的,不仅不稳定,时不时还会因为盗链被加入黑名单。现在说起来可真是一段血泪史啊。于是笔者看今天天气不错(<del>大雾</del>),决定搞一波图片。</p>
</summary>
<category term="一些小教程" scheme="https://www.intmian.com/categories/%E4%B8%80%E4%BA%9B%E5%B0%8F%E6%95%99%E7%A8%8B/"/>
<category term="hexo" scheme="https://www.intmian.com/tags/hexo/"/>
</entry>
<entry>
<title>我踩过的c++的坑</title>
<link href="https://www.intmian.com/2018/07/21/%E6%88%91%E8%B8%A9%E8%BF%87%E7%9A%84c++%E7%9A%84%E5%9D%91/"/>
<id>https://www.intmian.com/2018/07/21/我踩过的c++的坑/</id>
<published>2018-07-21T08:28:15.000Z</published>
<updated>2019-06-06T06:07:35.963Z</updated>
<content type="html"><![CDATA[<p>c++坑还挺多的,以后每个坑我都记录下来<br>持续更新</p><a id="more"></a><h2 id="在类的实例化时不能使用其他的类的构造函数"><a href="#在类的实例化时不能使用其他的类的构造函数" class="headerlink" title="在类的实例化时不能使用其他的类的构造函数"></a>在类的实例化时不能使用其他的类的构造函数</h2><p>例如</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">TCHAR current_directiom[<span class="number">100</span>];</span><br><span class="line">GetCurrentDirectoryW(<span class="number">200</span>, current_directiom);</span><br><span class="line">Installer in(wstring(curren));</span><br></pre></td></tr></table></figure><p>理论上没毛病。</p><p>但是在笔者的环境中in被视为一个函数而非一个类。</p><p>必须要写成</p><pre><code>TCHAR current_directiom[100];GetCurrentDirectoryW(200, current_directiom);wstring path(current_directiom);Installer in(path);</code></pre><p>才行</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">char</span> current_directiom[<span class="number">100</span>];</span><br><span class="line">GetCurrentDirectoryA(<span class="number">200</span>, current_directiom);</span><br><span class="line"><span class="built_in">string</span> path = <span class="built_in">string</span>(current_directiom) + <span class="built_in">string</span>(<span class="string">"\\data\\setting.ini"</span>);</span><br></pre></td></tr></table></figure><p>而这样的却又是可以的,迷</p><h2 id="两个指针作为参数不能重载运算符"><a href="#两个指针作为参数不能重载运算符" class="headerlink" title="两个指针作为参数不能重载运算符"></a>两个指针作为参数不能重载运算符</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">QListWidget * <span class="keyword">operator</span><<(QListWidget *output, <span class="keyword">char</span> *your_output);</span><br></pre></td></tr></table></figure><p>这样的语句是错误的,为避免出现内置类型的重载,必须有一个及以上的参数为类或枚举类型</p><h2 id="单例模式请务必加锁"><a href="#单例模式请务必加锁" class="headerlink" title="单例模式请务必加锁"></a>单例模式请务必加锁</h2><p>今天偷懒,写了一个简化版的单例模式,没加异步锁,被别人看出来了。。。</p><h2 id="别再using-namespace-std了"><a href="#别再using-namespace-std了" class="headerlink" title="别再using namespace std了"></a>别再<code>using namespace std</code>了</h2><p>这会极大的污染命名空间。很容易产生<code>c226</code>不明确问题</p><p>替代方法 <code>using xxx::yyy</code></p><blockquote><p>xxx: 命名空间<br>yyy:标识符</p></blockquote><h2 id="关于switch"><a href="#关于switch" class="headerlink" title="关于switch"></a>关于switch</h2><p>switch其实是一个流控制器。如果你用了比较传统的写法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="keyword">case</span> A :</span><br><span class="line">...</span><br><span class="line"><span class="keyword">break</span></span><br></pre></td></tr></table></figure><p>那么你在A中定义的变量会一路传下来,这是不安全的。所以会报错。</p><p>解决方案:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="keyword">case</span> A :</span><br><span class="line">{</span><br><span class="line"> ...</span><br><span class="line">}</span><br><span class="line"><span class="keyword">break</span></span><br></pre></td></tr></table></figure><p>让变量超出范围就消失就行了。</p><p>如果你下文的逻辑还要用到这个变量,就把它定义到swutch块前面去。</p><h2 id="输入输出重定向的问题"><a href="#输入输出重定向的问题" class="headerlink" title="输入输出重定向的问题"></a>输入输出重定向的问题</h2><p><strong>不要在powershell中进行输入输出重定向</strong>,会报很多神奇的错误,改成cmd即可。</p><h2 id="别在迭代器中使用erase"><a href="#别在迭代器中使用erase" class="headerlink" title="别在迭代器中使用erase"></a>别在迭代器中使用erase</h2><p>例如这段代码</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">auto</span> num_ptr = digits.begin(); num_ptr != digits.end(); num_ptr++)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (*num_ptr == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> digits.erase(num_ptr);</span><br><span class="line"> digits.push_back(<span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>会出现错误</p><div align="center"><br><img src="warning.png" alt="警告"><br></div><p>这段错误在<strong>STL</strong>中的源码我也放下</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="keyword">this</span>->_Getcont() == <span class="number">0</span></span><br><span class="line"> || <span class="keyword">this</span>->_Ptr == <span class="number">0</span></span><br><span class="line"> || ((_Myvec *)<span class="keyword">this</span>->_Getcont())->_Mylast <= <span class="keyword">this</span>->_Ptr)</span><br><span class="line">{ <span class="comment">// report error</span></span><br><span class="line"> _DEBUG_ERROR(<span class="string">"vector iterator not incrementable"</span>);</span><br><span class="line"> _SCL_SECURE_OUT_OF_RANGE;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>this->_Getcont()的源码是</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">return</span> (_Myproxy == <span class="number">0</span> ? <span class="number">0</span> : _Myproxy->_Mycont);</span><br></pre></td></tr></table></figure><p>原来的迭代器在erase后已经失效了</p><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><p>把迭代器自增分出来</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">auto</span> num_ptr = digits.begin(); num_ptr != digits.end();)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (*num_ptr == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> num_ptr = digits.erase(num_ptr);</span><br><span class="line"> digits.push_back(<span class="number">0</span>);</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"> num_ptr++;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="stl算法的前后界陷阱"><a href="#stl算法的前后界陷阱" class="headerlink" title="stl算法的前后界陷阱"></a>stl算法的前后界陷阱</h2><p>笔者在今天写代码的时候碰到了一个问题,max_element总是出错,找出来的不包括最后一个,一番研究后啼笑皆非。</p><p>我们使用这个函数对整个容器进行操作时,一定会用<code>max_element(vec.begion(),vec.end())</code>,其中的<code>end()</code>是最后一个迭代器的下一个。<br>但是我们在对容器的一部分进行操作时,却容易忘记掉,第二个参数的意义,最后导致少操作了一个。。。</p><h2 id="关于system"><a href="#关于system" class="headerlink" title="关于system"></a>关于system</h2><p>严格来说,这个不能算是c++的坑,而应该算是c语言和c++一起搞出来的的坑。</p><p><code>system</code>函数,总所周知,是不需要库的(c++),而我又好久没有写过pure c了,于是某日我在用pure c写代码时,突然发现system函数怎么命名空间里没有,而我那时恰好在给学妹演示代码,于是就变成大型翻车现场了…后来我发现,这个函数在c中其实放在<code>stdlib.h</code>里面。</p><blockquote><p>我觉得c++标准库不再需要标明.h是一个重大的创举2333</p></blockquote><h2 id="关于相对路径"><a href="#关于相对路径" class="headerlink" title="关于相对路径"></a>关于相对路径</h2><p>需要注意的是当你使用相对地址,或者使用某些库求地址的库时,其基准地址会存在陷阱。</p><p>对于代码<code>a.txt</code>按照道理你想要达成的是通过相对地址访问与程序同一个层次的<strong>a.txt</strong>。</p><ul><li>对于直接运行程序来说,你得到的就是正确的结果。</li><li>对于命令行运行的程序例如.\xxx\a.exe时,你的基准地址为命令行的工作目录,这就会导致你访问不到,或者访问了错误的a.exe。</li></ul><h2 id="关于类的定义先后"><a href="#关于类的定义先后" class="headerlink" title="关于类的定义先后"></a>关于类的定义先后</h2><p>在vs中偶遇</p><blockquote><p>error C2143: 语法错误: 缺少“;”(在“<”的前面)<br>note: 参见对正在编译的类 模板 实例化“LList”的引用<br>error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int<br>error C2238: 意外的标记位于“;”之前<br>error C2143: 语法错误: 缺少“;”(在“<”的前面)<br>error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int<br>error C2238: 意外的标记位于“;”之前<br>error C2143: 语法错误: 缺少“;”(在“<”的前面)<br>error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int<br>error C2238: 意外的标记位于“;”之前</p></blockquote><p>这样的一大堆错误。</p><p>我当时看了很长时间都没发现错误,而且静态检测中也没报错。就是实例化后会出现类型推倒失败。我开始也以为是类的前后问题。但是因为内含类未报错。所以也就没有接着看了。</p><p>再把组合的成员声明放在总成员上后,问题就解决了。</p><p>总的来说vs,这方面的问题检验还有点问题。所以以后看到这样的错误要自己注意下LOL。</p><h2 id="有关于类多重引用的顺序"><a href="#有关于类多重引用的顺序" class="headerlink" title="有关于类多重引用的顺序"></a>有关于类多重引用的顺序</h2><p>设有A,B两类</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a,b;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> A(B b):</span><br><span class="line"> a(b.a),b(b.b)</span><br><span class="line"> {}</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a,b;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> B(A a):</span><br><span class="line"> a(a.a),b(a.b)</span><br><span class="line"> {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这样子的代码是错误的,因为编译器是<strong>自顶而下</strong>编译的,在编译A类时,不知道B类的情况,甚至不知道B类。</p><p>那我们改一下,提前告诉编译器A类的存在</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a,b;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> A(B b):</span><br><span class="line"> a(b.a),b(b.b)</span><br><span class="line"> {}</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a,b;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> B(A a):</span><br><span class="line"> a(a.a),b(a.b)</span><br><span class="line"> {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这样子可以了吗?答案是这样子也是不行的,因为在A类中用到了<code>b.a</code>这样的东西,而编译器虽然知道B的存在,但是也就仅仅知道它的存在,换言之,这是个不完整类型。而编译器不能访问不完整类型的成员。</p><p>可以改成指针形式</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a,b;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> A(B *b):</span><br><span class="line"> a(b->a),b(b->b)</span><br><span class="line"> {}</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a,b;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> B(A a):</span><br><span class="line"> a(a.a),b(a.b)</span><br><span class="line"> {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这样子就可以解决问题了</p><p>如果你一定不要指针的话,也可以,那你可以把类内方法的实现放到两个类下面</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a,b;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> A(B *b);</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a,b;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> B(A a);</span><br><span class="line">}</span><br><span class="line">A::A(B *b):</span><br><span class="line"> a(b->a),b(b->b)</span><br><span class="line"> {}</span><br><span class="line">B::B(A a):</span><br><span class="line"> a(a.a),b(a.b)</span><br><span class="line"> {}</span><br></pre></td></tr></table></figure><h2 id="stl迭代器陷阱"><a href="#stl迭代器陷阱" class="headerlink" title="stl迭代器陷阱"></a>stl迭代器陷阱</h2><p>今天在用stl迭代经典算法时偶遇问题</p><blockquote><p>果然像是这种问题,还是没有成体系学习stl甚至c++的锅。</p></blockquote><pre><code>iterator not incrementablevector iterators incompatible</code></pre><p>这些问题碰到了很多次,原因这里简单记一下</p><ol><li>迭代器在容器增加,删除时很容易失效,特别是erase函数,此时就会出现不兼容错误,因为此时迭代器的行为是不可预测的。</li><li>在使用memset时很容易弄坏几个指针,就会报错</li></ol><h3 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h3><ol><li>不使用memset简单粗暴操作</li><li>在敏感操作后的迭代器应该重新获得,可以存储偏移,也可以使用敏感操作的返回值重新获得</li></ol><h3 id="反思"><a href="#反思" class="headerlink" title="反思"></a>反思</h3><p>不再土法学习c++,继续系统化</p><h2 id="类的静态变量需要定义"><a href="#类的静态变量需要定义" class="headerlink" title="类的静态变量需要定义"></a>类的静态变量需要定义</h2><blockquote><p>符号未定义…….static…..</p></blockquote><p>如果出现这种问题,说明你没有定义类的静态变量。你至少需要在一个.cpp中定义一次</p><blockquote><p>与普通便量不同,此处不会触发重定义</p></blockquote><h2 id="命令行程序的缓冲区"><a href="#命令行程序的缓冲区" class="headerlink" title="命令行程序的缓冲区"></a>命令行程序的缓冲区</h2><p>有些人(<del>我</del>),为了程序看上去比较骚气</p><p>会使用</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">_wsystem(<span class="string">L"title 停车 -xxxx"</span>); <span class="comment">// 宽字节版</span></span><br><span class="line">system(<span class="string">"color F0"</span>);</span><br><span class="line">system(<span class="string">"mode con cols=36 lines=25"</span>);</span><br></pre></td></tr></table></figure><p>这样的代码。</p><p>然后我们就会发现少了一个很重要的东西,<strong>滚条</strong>。</p><p>如果一屏幕放不下就看不见上面的数据了</p><h3 id="解决方法-1"><a href="#解决方法-1" class="headerlink" title="解决方法"></a>解决方法</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span></span></span><br><span class="line">......</span><br><span class="line">HANDLE con = GetStdHandle(STD_OUTPUT_HANDLE);</span><br><span class="line">COORD buf = { <span class="number">36</span>,<span class="number">200</span> };</span><br><span class="line">SetConsoleScreenBufferSize(con, buf);</span><br></pre></td></tr></table></figure><p>使缓冲区变大</p><blockquote><p>缓冲区长度高于窗口时会有竖直的滚动条,反之反之,缓冲区应大于窗体</p></blockquote><h2 id="关于类的函数友元"><a href="#关于类的函数友元" class="headerlink" title="关于类的函数友元"></a>关于类的函数友元</h2><p>类的友元函数被类声明后。事实上就已经将此函数声明了。也就是这个函数是一个特殊的<strong>类方法</strong>。期望将独立于类的方法作为友元(即将别人的友元同时作为自己的友元声明)会在编译期报错。事实上</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a;</span><br><span class="line"> <span class="function"><span class="keyword">friend</span> <span class="keyword">void</span> <span class="title">test</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a;</span><br><span class="line"> <span class="function"><span class="keyword">friend</span> <span class="keyword">void</span> <span class="title">test</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">test</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure><p>这里的三个test是不同的test。位于不同的作用域 <code>::</code> <code>A::</code> <code>B::</code>,那么显然<code>::A</code>不能调用<code>B::a</code>。</p><p>这都是简单的东西,因为搞错了我们的ide都会报错。</p><p>但是如果test是A B中某类的操作符重载的话就会混淆ide,从而不报错</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a;</span><br><span class="line"> <span class="keyword">friend</span> A&& <span class="keyword">operator</span> +(<span class="keyword">const</span> A& a, <span class="keyword">const</span> A& b); <span class="comment">// 无用 没有A::A&& operator (const A& a, const A& b) +的定义</span></span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="keyword">int</span> a;</span><br><span class="line"> <span class="keyword">friend</span> A&& <span class="keyword">operator</span> +(<span class="keyword">const</span> A& a, <span class="keyword">const</span> A& b); <span class="comment">// 无用 没有B::A&& operator (const A& a, const A& b) +的定义</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">A&& <span class="keyword">operator</span> +(<span class="keyword">const</span> A& a, <span class="keyword">const</span> A& b); <span class="comment">// 有用 有::A&& operator (const A& a, const A& b) +的定义</span></span><br><span class="line"></span><br><span class="line">A&& <span class="keyword">operator</span> +(<span class="keyword">const</span> A& a, <span class="keyword">const</span> A& b) <span class="comment">// ::A&& operator (const A& a, const A& b) +的定义</span></span><br><span class="line">{</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>没错,这里的<code>operator +</code>会被我们的vs识别为一个东西,甚至ctrl 点进去都是同一个,也就是下面的实现。然后你就会发现你可以使用<code>A::a</code>却不可以使用<code>B::a</code>,如果你水平和我一样菜的话,就会觉得很晕。</p><p>实际上,编译器只认最后面那个。上面的两个其实是被无视掉的,也就是被认为是只有声明没有定义的玩意。而函数可以使用A的私有变量其实是因为它是A的重载函数,c++给的语法糖罢了。</p><p>这里的原因是vs的bug,把三个<code>A&& operator (const A& a, const A& b) +</code>的声明都当成了<code>::A&& operator (const A& a, const A& b) +</code>。。。</p><p><del>其实和我菜也有一定关系。</del></p>]]></content>
<summary type="html">
<p>c++坑还挺多的,以后每个坑我都记录下来<br>持续更新</p>
</summary>
<category term="从零开始的编程之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E8%B7%AF/"/>
<category term="编程" scheme="https://www.intmian.com/tags/%E7%BC%96%E7%A8%8B/"/>
<category term="c++" scheme="https://www.intmian.com/tags/c/"/>
</entry>
<entry>
<title>ROP与ROP的实践</title>
<link href="https://www.intmian.com/2018/07/15/ROP/"/>
<id>https://www.intmian.com/2018/07/15/ROP/</id>
<published>2018-07-15T02:46:27.000Z</published>
<updated>2018-07-30T08:13:48.518Z</updated>
<content type="html"><![CDATA[<p>Return-oriented programming(<strong>ROP</strong>)是一种很常见的攻击技术,是一种具有图灵完备性的超级攻击方式。</p><a id="more"></a><h2 id="何为ROP"><a href="#何为ROP" class="headerlink" title="何为ROP"></a>何为ROP</h2><p><strong>rop</strong> 即 <strong>面向返回的编程</strong>。上文我们讲到了ret2plt,rop就是ret2plt在64位的升级版本。rop也可以用来做32位的题,是一种相当上位的攻击技术。可以替代我们之前讲的几乎所有溢出利用。可以绕过aslr与dep(NX)。</p><p>我所理解的的ROP就是有去有回,需要多次劫持程序流的攻击。</p><blockquote><p>广义的ROP包括了上文所讲到的任何返回式的攻击方式,不过我们今天要讲的是狭义的ROP</p></blockquote><hr><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><h3 id="传参方式的改变"><a href="#传参方式的改变" class="headerlink" title="传参方式的改变"></a>传参方式的改变</h3><p>在64位程序中,<a href="https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI" target="_blank" rel="noopener">calling conventions</a>规定参数依靠寄存器传递,前面6个参数依次以rdi, rsi, rdx, rcx, r8和r9寄存来传递,后面的参数则用栈来传递。这样子我们之前的那些依靠栈来传递参数的方法似乎就难以使用。</p><h3 id="天然零化"><a href="#天然零化" class="headerlink" title="天然零化"></a>天然零化</h3><p>64位相较32位对于32位可以掌控更多(<strong>40亿</strong>倍,大约16<strong>EB</strong>)的内存。而我们显然用不到这么多内存(<del>笔者连加一条8g内存都心痛</del>),在linux中规定只使用后48位的内存,而前面的那些就全部置零,这些零字节会截断字符串,形成了天然的防护。</p><hr><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>linux x64采用了<strong>寄存器传参</strong>,因此难以使用我们平时使用的栈传参。</p><table><thead><tr><th style="text-align:center">参数</th><th style="text-align:center">寄存器</th></tr></thead><tbody><tr><td style="text-align:center">1</td><td style="text-align:center">RDI</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center">RSI</td></tr><tr><td style="text-align:center">3</td><td style="text-align:center">RDX</td></tr><tr><td style="text-align:center">4</td><td style="text-align:center">RCX</td></tr><tr><td style="text-align:center">5</td><td style="text-align:center">R8</td></tr><tr><td style="text-align:center">6</td><td style="text-align:center">R9</td></tr></tbody></table><p>由于我们不能直接<strong>控制</strong>寄存器。</p><p>我们上文讲到的<strong>ret2plt</strong>利用所谓的PPR结构来在libc或者其他的可执行块里找到一些片段来调用。</p><p>现在我们也用这种方法来进行攻击。将我们需要执行的指令连成<strong>ROP链</strong>来进行ROP攻击。</p><hr><h2 id="攻击步骤"><a href="#攻击步骤" class="headerlink" title="攻击步骤"></a>攻击步骤</h2><h3 id="如何构建ROP链"><a href="#如何构建ROP链" class="headerlink" title="如何构建ROP链"></a>如何构建ROP链</h3><p>因为我们的攻击的最终目的一定是获得shell,所以我们最终需要让程序执行<code>system("\bin\sh")</code>这条指令。那就需要覆盖程序返回地址到我们想要执行的地方。</p><blockquote><p>buffer|canary|saved fame pointer|saved returned address</p></blockquote><p>那么我们需要在栈里面写入”/bin/sh\0”。因为栈的内容是我们可以控制的,所以可以写入。那么我们需要找到例如<code>pop rdi</code>这样的语句。我们可以使用诸如<strong>ROPgadget</strong>这样的工具,具体用法请看官方文档。</p><p>但是有一点需要注意,我们找到的语句必须包含一个返回<code>ret(retq)</code>,不然会顺着语句一路执行下去。</p><p>当然,我们有些时候会碰到程序过于小,导致根本没有rop片段可以利用,例如上次笔者碰见的一个500b的题,那我们需要利用libc的gadget,但是我们一般情况下不知道题目的libc,所以需要不断leak出服务器端的libc。</p><blockquote><p>如果对于libc的地址,aslr等不是很清楚的话,建议再读一读<strong>elf</strong>的内容。</p></blockquote><h2 id="ROP的功能"><a href="#ROP的功能" class="headerlink" title="ROP的功能"></a>ROP的功能</h2><p>rop看似复杂,限制很多。但是总可以从程序中找到一枝半叶,而组成极其强大的功能。<del>rop真的可以为所欲为。</del></p><p>甚至,高手的rop可以实现循环、分支、条件等等逻辑。有人指出rop具有图灵完备性。</p><hr><h2 id="局限"><a href="#局限" class="headerlink" title="局限"></a>局限</h2><ul><li>技巧性有点强。</li><li>需要其他的栈溢出或者注入来做铺垫。</li></ul>]]></content>
<summary type="html">
<p>Return-oriented programming(<strong>ROP</strong>)是一种很常见的攻击技术,是一种具有图灵完备性的超级攻击方式。</p>
</summary>
<category term="从零开始的ctf之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84ctf%E4%B9%8B%E8%B7%AF/"/>
<category term="pwn" scheme="https://www.intmian.com/tags/pwn/"/>
<category term="栈" scheme="https://www.intmian.com/tags/%E6%A0%88/"/>
</entry>
<entry>
<title>巧绕NX与ascii armoring-ret2plt</title>
<link href="https://www.intmian.com/2018/06/15/%E5%B7%A7%E7%BB%95NX%E4%B8%8Eascii-armoring-ret2plt/"/>
<id>https://www.intmian.com/2018/06/15/巧绕NX与ascii-armoring-ret2plt/</id>
<published>2018-06-15T13:01:55.000Z</published>
<updated>2019-01-24T05:07:05.999Z</updated>
<content type="html"><![CDATA[<p>前面讲完了plt、got,我们来个相关的。</p><a id="more"></a><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><del>前排广告位招租</del><br>最近忙于乱七八糟的事,导致没时间更博客。除了开发方面,bin方面也需要多多努力,避免被别人远远甩在后面</p><hr><h2 id="ret2plt"><a href="#ret2plt" class="headerlink" title="ret2plt"></a>ret2plt</h2><h3 id="ascii-armoring"><a href="#ascii-armoring" class="headerlink" title="ascii armoring"></a>ascii armoring</h3><p>为了针对1997年的黑客提出的 <strong>return-to-libc</strong> 技术,ascii morning被提出,以将libc的函数地址的第一个字节进行零化的方式阻止了system地址被写入栈中导致程序流被劫持到了libc中奇怪的地方,从而拿到shell。</p><blockquote><p>零字节可以截断字符串使黑客无法将system地址写入栈。</p></blockquote><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>还记得我们是怎么写shellcode的嘛,就是千方百计地通过各种方式搞出零字节。这次我们也要使用这种精神。</p><p>为了对抗ascii armoring我们不再使用libc中的函数,我们使用<strong>plt</strong>中的<strong>strcpy</strong>一点点的把system的地址拼接出来,写入plt表中的某个函数的空间中。最后再劫持程序流到这个空间中去,从而拿到shell。</p><p>这就有一个问题,我们都知道开了NX之后程序不再可以在栈中执行shellcode,这让需要执行这么多strcpy的我们感觉很麻烦。因此我们通过一种被称为 <strong>PPR</strong> 的技术,这样子我们就可以连续地执行多个函数。</p><p>PPR由两个pop、和一个ret组成,专门负责清空两个已经用过的参数(plt表中需要写入的东西与需要被写入地system地址的一部分)并且用ret返回到下一个参数中去。</p><p>假定有</p><pre><code>(堆栈中的内容)strcpy@pltsystem[0]xxx@plt[0]PPR的地址strcpy@plt <--------EIP指向这里(某处)pop eax <--------PPR的地址pop eaxret</code></pre><p>我用文字来描述一般</p><ol><li>程序流走向了strcpy@plt这里后把PPR的地址当成函数的返回地址并把system[0]和xxx@plt[0]当成了函数的两个两个参数运行</li><li>执行完了strcpy后<code>ret</code>返回了某处的PPR源码中,然后通过两个<code>pop eax</code>将两个参数从栈中清除出去(通过增加了esp的值到了两个参数下面),然后通过<code>ret</code>,取出下一个strcpy的地址,并控制程序流到了那里。</li><li>返回第一过程。</li></ol><p>这样子我们就通过预先的栈溢出来控制程序的连续走向不同的plt表中的函数,来达成一个非常复杂的功能,而不是像ret-libc那样只能达成一个单独的函数的功能</p><blockquote><p>PPR技术主要是为了清除参数,在其他情况中如果没有参数则不需要PPR技术只需把下一个函数的地址填入返回地址中</p></blockquote><h3 id="过程"><a href="#过程" class="headerlink" title="过程"></a>过程</h3><p><img src="https://img-blog.csdn.net/20150801224756198" alt="payload"></p><p>我们需要从栈中注入如上图大小的块</p><p>但是我们还有几个技术问题没有解决</p><blockquote><ol><li>PPR的代码放在哪里?</li><li>strcpy在plt表中的位置</li><li>system的地址在哪里?</li><li>放在plt表的哪里</li><li>/bin/bash放在那里</li></ol></blockquote><p>我们按照一步步流程来</p><h4 id="对准EIP"><a href="#对准EIP" class="headerlink" title="对准EIP"></a>对准EIP</h4><p>这个打开ida可以解决问题或者用我们的gdb调一调也可以解决。</p><h4 id="找到strcpy的位置"><a href="#找到strcpy的位置" class="headerlink" title="找到strcpy的位置"></a>找到strcpy的位置</h4><p>可以通过ida来反编译函数来获得地址(没开aslr的情况)。</p><h4 id="找到PPR的地址"><a href="#找到PPR的地址" class="headerlink" title="找到PPR的地址"></a>找到PPR的地址</h4><p>我们唯一可以控制的空间只有栈和plt表,而对后者的控制是建立在PPR的地址已经找到了上。那我们就不能自由的注入PPR了。索性这种平衡栈帧的代码非常(<del>并不</del>)常见。我们去可执行段里随便找一个,然后拿来用。</p><h4 id="system的拷贝"><a href="#system的拷贝" class="headerlink" title="system的拷贝"></a>system的拷贝</h4><p>由于<strong>ASCII armoring</strong>机制,system的地址含有零字节,造成strcpy拷贝结束,达不到预期的攻击效果。攻击者找到4个地址空间,它的首字节分别是system地址的第一个byte, 第二个byte,第三个byte和第四个byte,然后一个个byte拷贝,将这4个byte拼凑到GOT里面。从而绕过直接拷贝system地址造成失败。</p><blockquote><p>时下最流行的<strong>ubantu</strong>没有这个特性哦。</p></blockquote><p>我们强行逆一波,然后在内存里找到,然后在记在小本本上。</p><blockquote><p>需要注意,虽然说我们都是经验<del>并不</del>丰富的攻击者,但是还需要特别注意一下,需要找的是内存中存放的字节,而不是字节的ascii码。</p></blockquote><p>也可以使用<code>find</code>命令在内存中找。为了精确定位,我们应当在内存镜像中寻找以避免地址在加载中偏移,形如<code>find /b 0xaaaaaaaa, 0xbbbbbbbb, 0xcc</code>的<strong>gdb</strong>命令可以在a…到b…的空间内写入cc。</p><blockquote><p>内存镜像的工作原理与硬盘的热备份类似,内存镜像是将内存数据做两个拷贝,分别放在主内存和镜像内存中。</p></blockquote><h4 id="写入哪个plt表空间为好呢?"><a href="#写入哪个plt表空间为好呢?" class="headerlink" title="写入哪个plt表空间为好呢?"></a>写入哪个plt表空间为好呢?</h4><p>看了我前文的内容你是否有疑惑,我用的<code>strcpy</code>并不是一个字符拷贝函数,而是字符串拷贝函数,也就是说这四个字符的位置可能会溢出,盖掉其他的plt表项,其中可能就包括strcpy。这就让我们需要选一个trycpy前面的,我就随便选个puts吧。</p><p>逆一波程序就可以拿到puts的地址了。</p><blockquote><p>本文使用了puts作为目标地址,你当然可以选择其他的。</p></blockquote><h4 id="“-bin-bash”的地址"><a href="#“-bin-bash”的地址" class="headerlink" title="“\bin\bash”的地址"></a>“\bin\bash”的地址</h4><p>同样的,为了精确攻击,我们最好找一个现成的。</p><p>Linux里面有个shell环境变量,表示前使用哪个shell,它的值通常是”/bin/bash”,如下:</p><blockquote><p>$ env | grep -i shell<br>SHELL=/bin/bash</p></blockquote><p>每个进程的环境变量都保存在主线程的栈上,因此可以在主线程栈空间上找到该字符串。由于本文的代码为单线程 ,因此可以沿着esp地址往上找即可:</p><pre><code>(gdb) x/1000s $esp…0xffffd8b4: "/home/ivan/exploit/stack4"0xffffd8ce: "SHELL=/bin/bash"0xffffd8de: "TERM=xterm"</code></pre><p>…</p><blockquote><p>环境变量也是作为参数传进主程序的。</p></blockquote><h4 id="攻击向量"><a href="#攻击向量" class="headerlink" title="攻击向量"></a>攻击向量</h4><p>根据上面的方法我们可以得出我们需要注入的内容。</p><p>A*x<br>strcpy@plt + PPR + puts@got[0] + addr of system[0]<br>strcpy@plt + PPR + puts@got[1] + addr of system[1]<br>strcpy@plt + PPR + puts@got[2] + addr of system[2]<br>strcpy@plt + PPR + puts@got[3] + addr of system[3]<br>puts@plt + exit + addr of “/bin/bash”</p><h3 id="局限"><a href="#局限" class="headerlink" title="局限"></a>局限</h3><ol><li>需要确切的地址难以对抗<strong>aslr</strong>防护。</li><li>需要<strong>过于多的条件</strong>,难以满足多变的情况。</li><li>在内存中需要寻找<strong>过于多</strong>的地址。</li><li>需要注入plt表的值,在64位天然零化的情况下难以为继</li><li>与ROP技术相比,不具备完备性,局限性太强</li></ol><p>正因为许许多多的漏洞导致了ret2plt并没有流行起来。</p>]]></content>
<summary type="html">
<p>前面讲完了plt、got,我们来个相关的。</p>
</summary>
<category term="从零开始的ctf之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84ctf%E4%B9%8B%E8%B7%AF/"/>
<category term="pwn" scheme="https://www.intmian.com/tags/pwn/"/>
<category term="栈" scheme="https://www.intmian.com/tags/%E6%A0%88/"/>
<category term="plt&got" scheme="https://www.intmian.com/tags/plt-got/"/>
</entry>
<entry>
<title>bin实用小工具</title>
<link href="https://www.intmian.com/2018/06/14/%E5%AE%9E%E7%94%A8%E5%B0%8F%E5%B7%A5%E5%85%B7/"/>
<id>https://www.intmian.com/2018/06/14/实用小工具/</id>
<published>2018-06-14T11:04:15.000Z</published>
<updated>2018-07-01T07:59:13.708Z</updated>
<content type="html"><![CDATA[<p>一些bin学习过程中常用的工具</p><a id="more"></a><h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><p>glibc版本<= 2.23</p><h2 id="bin必要工具:"><a href="#bin必要工具:" class="headerlink" title="bin必要工具:"></a>bin必要工具:</h2><p>Ubuntu:<br><a href="https://mirrors.aliyun.com/ubuntu-releases/16.04/" target="_blank" rel="noopener">https://mirrors.aliyun.com/ubuntu-releases/16.04/</a><br>你大可换其他的,例如kali</p><p>windows:<br>不解释</p><p>IDA7.0:<br>链接:<a href="https://pan.baidu.com/s/1s9K1TurV_bvlnWAAGJ4z-g" target="_blank" rel="noopener">https://pan.baidu.com/s/1s9K1TurV_bvlnWAAGJ4z-g</a> 密码:1e9i</p><p>没有IDA不知道怎么做bin题。。。</p><h2 id="pwn必要工具:"><a href="#pwn必要工具:" class="headerlink" title="pwn必要工具:"></a>pwn必要工具:</h2><p>pwntools:<br>apt-get update<br>apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev build-essential<br>pip install –upgrade pip<br>pip install –upgrade pwntools</p><p>pwn题必备,使用方法可以百度下,很容易找到的</p><p>Pwngdb:<br>链接:<a href="https://pan.baidu.com/s/1XtbuCfh_09ahlNAdly-KcA" target="_blank" rel="noopener">https://pan.baidu.com/s/1XtbuCfh_09ahlNAdly-KcA</a> 密码:mfz0</p><p>gdb的插件,简直是太好用了</p><p>msfvenom:<br><a href="https://github.com/rapid7/metasploit-framework/wiki/Nightly-Installers" target="_blank" rel="noopener">https://github.com/rapid7/metasploit-framework/wiki/Nightly-Installers</a></p><p>shellcode生成工具,可以生成各种要求的shellcode,蛮好用的</p><p>roputils:<br><a href="https://github.com/inaz2/roputils" target="_blank" rel="noopener">https://github.com/inaz2/roputils</a></p><p>和pwntools一起导入可能有点问题,一开始可能用不到,我用这个做过dl-resolve的题</p><p>ROPgadget:<br><a href="https://github.com/JonathanSalwan/ROPgadget" target="_blank" rel="noopener">https://github.com/JonathanSalwan/ROPgadget</a></p><p>ROP基本也是做pwn必备的东西,用法看自行看readme</p><h2 id="Re必要工具:"><a href="#Re必要工具:" class="headerlink" title="Re必要工具:"></a>Re必要工具:</h2><p>听逆向大神说好像一个IDA可以走天下了……<br>此外还需要用到OD。偶发性地,还需要一些小工具。</p><blockquote><p>建议安装吾爱破解工具包,再把里面的IDA等更新到最新版本。</p></blockquote><h2 id="小建议:"><a href="#小建议:" class="headerlink" title="小建议:"></a>小建议:</h2><blockquote><p>有余力的朋友建议购买正版。</p></blockquote><blockquote><p>要下载github上的东西,可以在虚拟机里输入 git clone +项目地址</p></blockquote>]]></content>
<summary type="html">
<p>一些bin学习过程中常用的工具</p>
</summary>
<category term="从零开始的ctf之路" scheme="https://www.intmian.com/categories/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84ctf%E4%B9%8B%E8%B7%AF/"/>
<category term="pwn" scheme="https://www.intmian.com/tags/pwn/"/>
<category term="re" scheme="https://www.intmian.com/tags/re/"/>
</entry>
</feed>