-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest.cc
3836 lines (3533 loc) · 140 KB
/
test.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <unordered_set>
#include <set>
#include <stack>
#include <queue>
#include <cstdlib> // rand, qsort
#include <functional>
#include <fstream>
#include "data_structs/base_struct.h"
#include "algorithm.h"
#include "sorts.h"
#include "utils.h"
#include "search_algs.h"
#include "dp_algs.h"
#include "greedy_algs.h"
#include "graph_algs.h"
#include "trace_back_algs.h"
#include "dfs_algs.h"
#include "bfs_algs.h"
#include "stack_algs.h"
#include "heap_algs.h"
#include "binary_search.h"
#include "merge_set.h"
#include "listnode_algs.h"
#include "binary_pointer.h"
#include "str_algs.h"
#include "topoloical_sort.h"
#include "memory_algs.h"
#include "hash_algs.h"
#include "bits_algs.h"
#include "design_algs.h"
#include "dict_tree.h"
#include "line_tree_algs.h"
#include "minimization_algs.h"
#include "random_sample_algs.h"
#include "geometric_algs.h"
#include "swordfingeroffer.h"
#include "queue_algs.h"
#include "hot_100.h"
#include "thot_50.h"
using namespace std;
/*
1.求树的最小深度:
递归: 若左右子树均不为null,则等于min(left_depth, right_depth) + 1;
queue: for (q.size()) q.pop(), 逐层遍历直到某个node的左右子树均为null,每遍历一遍则depth+1。
*/
void test_minmum_depth_binary_tree() {
TreeNode* root = new TreeNode(0);
TreeNode* left1 = new TreeNode(1);
// TreeNode* right1 = new TreeNode(2);
// TreeNode* right2 = new TreeNode(3);
root->left = left1;
// root->right = right1;
// right1->right = right2;
// int result = binary_tree::minimum_depth_binary_tree(root);
int result = binary_tree::minimum_depth_binary_tree_by_queue(root);
std::printf("result:%d\n", result);
}
/*
2. 后序遍历:
递归,
stack: 遍历root->val, root->right, root->left, 最后reverse 整个result数组。
*/
void test_postorderTraversal() {
TreeNode* root = new TreeNode(1);
// TreeNode* l = new TreeNode(2);
TreeNode* r = new TreeNode(3);
TreeNode* rr = new TreeNode(4);
// root->left = l;
root->right = r;
r->right = rr;
vector<int> result;
// binary_tree::postorderTraversal(root, result);
binary_tree::postorderTraversalWithStack(root, result);
for (int i=0; i<result.size(); i++) {
std::printf("%d ,", result[i]);
}
std::printf("\n");
}
/*
3. 使用stack求逆波兰式
*/
void test_reverse_polish_notation(){
vector<string> tokens;
// string inputs[5] = {"2", "1", "+", "3", "*"};
string inputs[5] = {"4", "13", "5", "/", "+"};
for (int i=0; i<5; i++) tokens.push_back(inputs[i]);
int result = reverse_polish_notation(tokens);
std::printf("%d \n", result);
}
/*
4. 求最大共线点数:两层循环,分别求以点i为起点的最大共线点数。因为浮点数存在误差,斜率需要用向量表示,向量可由x,y除以最大公约数得到。并额外处理斜率为0,无穷大,及重合的点。
最大公约数:max_common_divisor(a,b) if (a%b==0) return b; else return max_common_divisor(b, a%b);
*/
void test_max_point_on_a_line(){
vector<Point> inputs;
inputs.push_back(Point(0, 0));
int result = max_point_on_a_line(inputs);
std::printf("%d \n", result);
}
/*
5. 对链表进行排序,使用二分法 + merge two listnode
6. 检测链表中是否存在环,并找出环的起点。(1)通过step=1,2两个指针遍历链表,若两者相等,则存在环,返回该重合的点;(2)分别从起点,重合的点以step=1走,当起点走到重合点时,
则重合点的指针刚好走到环的起始位置。画可知,step=2的指针比step=1的指针多走的具体就是起点到重合点的距离== 重合点到环起点的距离。
*/
void test_sortListNode(){
ListNode* root = new ListNode(1);
ListNode* tmp = root;
tmp->next = new ListNode(2);
tmp = tmp->next;
tmp->next = new ListNode(3);
tmp = tmp->next;
tmp->next = new ListNode(4);
tmp = tmp->next;
tmp->next = new ListNode(5);
tmp->next = root->next;
ListNode* src = root;
// while(src != NULL) {
// std::printf("%d ,", src->val);
// src = src->next;
// }
// std::printf("\n");
// ListNode* result = list_node::sortList(root);
// ListNode* result = list_node::insertSortList(root);
// ListNode* result = list_node::reorderList(root);
// ListNode* result = list_node::reorderList_V2(root);
ListNode* result = list_node::detectCycle_V2(root);
std::printf("%d ,", result->val);
// while(result != NULL) {
// std::printf("%d ,", result->val);
// result = result->next;
// }
std::printf("\n");
}
/*
7. 求得字符串由dicts中子串拆分的所有可能。
(1) dp[n]数组保存0到i的子串是否可由dicts中的构成。两重for循环(i=1->n-1, j=0->i) if (dp[j] && s.substr(j, i-j+1) in dict) dp[i]=true
(2) 根据dp由n反推到0,得到所有的子串。dfs(idx, dp[], result): for (i=idx-1->0) {if dp[i] && s.substr(i, idx-i+1) in dict} result[i]=result[idx] + substr, dfs(i-1, dp, result);
再刷感想:1. 使用dp求得0->i是否可由dicts中的字符串组成,并记录其前一个节点下标,如dp[6]从dp[3]得到,则traces[6].push_back(3);
2. 根据dp flags 和traces, 可以构建整个字符串的结果.注意区分0,和第0个元素.为直观起见,在0的时候单独判断,而不是new len+1个空间区分
*/
void test_wordBreak(){
string s = "catsanddog";
std::unordered_set<string> dicts;
// dicts.insert("leet");
// dicts.insert("code");
dicts = {"cat", "cats", "and", "sand", "dog"};
// bool result = wordBreak(s, dicts);
// printf("result:%d\n", result);
// vector<string> result = wordBreak_v2(s, dicts);
// vector<string> result = wordBreak_v3(s, dicts);
vector<string> result = dp::wordBreak(s, dicts);
for(int i=0; i<result.size(); i++) {
printf("%s\n", result[i].c_str());
}
}
int tmp_fetch(RandomListNode* head) {
if (head != NULL) return head->label;
return -1;
}
void print_random_list_node(RandomListNode* head) {
RandomListNode* p = head;
while(p != NULL) {
printf("label:%d, next:%d, random:%d\n", p->label,
tmp_fetch(p->next), tmp_fetch(p->random));
p = p->next;
}
}
/*
8. 复制待随机指针的链表:这类指针复制分三步:
(1) 克隆节点,并插入原始节点中。即 src->next = src_copy; scr_copy->next = src->next;
(2) 设置指针连接关系。即src_copy->random = src->random->next;
(3) 分离src/copy
*/
void test_randomListNode() {
RandomListNode arr[5];
for (int i=1; i<4; i++) {
arr[i].label = i;
arr[i].next = &arr[i+1];
arr[i].random = &arr[i-1];
}
arr[0].next = &arr[1];
arr[0].label = 0;
arr[3].next = NULL;
RandomListNode* head = &arr[0];
print_random_list_node(head);
RandomListNode* copy_head = list_node::copyRandomList(head);
print_random_list_node(copy_head);
}
/*
9. 从重复2次,3次的数组中找出唯一出现一次的数。
(1)重复两次,则相同的数按位异或会变0,所以异或所有的数,最终结果就为只出现一次的数。for(num=A[0]-->A[n]) result ^= num;
(2) 重复三次,则使用one, two, three三个变量分别记录出现1,2,3次的每一比特,最终返回one即可。
one=two=three=0;
for(num=A[0]-->A[n]) {
two |= (one & num); // 一个数出现两次
one ^= num; // 某一比特位位1的条件
three = one & two; // 出现三次的情况
one &= ~three; // 如果出现三次,则将one对应位置0
two &= ~three; // 如果出现三次,则将two对应位置0
}
*/
void test_singleNumber() {
int a[7] = {1,2,3,2,3,2,3};
// int result = singleNumber(a, 7);
int result = singleNumber_v2(a, 7);
printf("%d\n", result);
return;
}
/*
10. n个小朋友分糖,rating高的人必须比旁边低的人分的多,每人最少一个。
从1遍历到最后
如果当前rating大于前一个,则当前分糖数为前一个+1;
否则:从前一个节点一直往前遍历:直到不满足: ranting[j]>ranting[j+1] && result[j]<=result[j+1]: result[j]=result[j+1]+1;
*/
void test_candy() {
int a[3]={2, 1, 3};
vector<int> ratings(a, a+3);
for(int i=0;i<ratings.size(); i++){
printf("%d ", a[i]);
}
printf("\n");
int result = candy(ratings);
printf("%d\n", result);
}
/*
11. 汽车是否能走完全程,并找到起点位置。
(1)start为n,end为0,如果res + cost[start]-gas[start]<0,则说明该点不能作为起点,start--;否则end++;直到start==end结束,即为该点。
*/
void test_complete_circuit() {
// vector<int> gas(2);
// vector<int> costs(2);
// gas[0]=1;
// gas[1]=2;
// costs[0]=2;
// costs[1]=1;
int gas_arr[] = {1, 2};
int costs_arr[] = {2, 1};
vector<int> gas(gas_arr, gas_arr + 2);
vector<int> costs(costs_arr, costs_arr + 2);
int result = canCompleteCircuit_v2(gas, costs);
printf("result:%d\n", result);
}
/*
12. 同8
*/
void test_clone_graph() {
UndirectedGraphNode* zero = new UndirectedGraphNode(0);
UndirectedGraphNode* one = new UndirectedGraphNode(1);
UndirectedGraphNode* two = new UndirectedGraphNode(2);
zero->neighbors.push_back(one);
zero->neighbors.push_back(two);
one->neighbors.push_back(two);
two->neighbors.push_back(two);
print_graph(zero);
UndirectedGraphNode* copy_node = cloneGraph(zero);
printf("clone graph\n");
print_graph(copy_node);
delete zero;
delete one;
delete two;
}
/*
13. 将字符串分割成回文子串的所有可能,每次回溯需要pop_back curr_vector。dfs(curr_str, curr_vector, result): for (i=0->curr_str.length())
if (curr_str(0,i+1) is palindrome) curr_vector.push_back(curr_str(0,i+1)); dfs(curr_str(i,len-1), curr_vector, result);
*/
void test_palidrome() {
string str = "aab";
// vector<vector<string> > result = palindrome_partition(str);
vector<vector<string> > result = dfs::palindrome_partition(str);
printf("result size:%lu\n", result.size());
for (vector<string> v_iter: result) {
for (string iter: v_iter) {
printf("%s,", iter.c_str());
}
printf("\n");
}
}
/*
14. 最小回文子串的数量:两重循环,i=0->n;j=i->n; if (s.sub(i, j-i+1) is palindrome) dp[j]=min(dp[j],dp[i]+1)
再刷感想:1. 使用dp求解.如果str[i]!=str[j], dp[i,j] = min(dp[i,j], dp[i][k]+dp[k+1][j]), 如果str[i]==str[j] dp[i,j]=dp[i+1,j-1], 注意j-1>2
*/
void test_palidrome_min_cut() {
string str = "leet";
// int result = palindrome_minCut(str);
// int result = palindrome_minCut_v2(str);
int result = dp::palindrome_minCut(str);
printf("result %s: %d\n", str.c_str(), result);
str = "leaet";
result = dp::palindrome_minCut(str);
printf("result %s: %d\n", str.c_str(), result);
}
void print_surroundReigon(vector<vector<char> >& board) {
int width = board.size();
int length = board[0].size();
for (int i=0; i<width; i++) {
for(int j=0; j<length; j++) {
printf("%c ", board[i][j]);
}
printf("\n");
}
}
/*
15. 保留边界‘0’的连通部分。使用queue/stack遍历边界‘0’部分,置为‘A’
*/
void test_surroundRegion() {
char board_arr[4][4] = {{'X','X','X','X'},
{'X','O','O','X'},
{'X','X','O','X'},
{'X','O','X','X'}};
vector<vector<char> > board(4);
for(int i=0; i<4; i++) {
vector<char> tmp(board_arr[i], board_arr[i]+4);
board[i] = tmp;
}
print_surroundReigon(board);
SurroundingReigon(board);
printf("\n");
print_surroundReigon(board);
return;
}
void test_sum_number_binary_tree() {
TreeNode* root = new TreeNode(1);
TreeNode* left = new TreeNode(2);
TreeNode* right = new TreeNode(3);
root->left = left;
root->right = right;
int sum = binary_tree::sumNumbers(root);
printf("sum:%d\n", sum);
}
/*
16. 找出最长连续数的个数。使用set/map存所有的数,遍历arr,得到第i个val, 依次val--, val++ 从set/map中找
*/
void test_longest_consecutive() {
int arr[] = {100, 4, 200, 1, 3, 2};
vector<int> vec(arr, arr+6);
// int result = longestConsecutive(vec);
int result = longestConsecutive_V2(vec);
printf("result:%d\n", result);
}
/*
17. 去掉空格,标点符号,屏蔽大小写差异,判断是否为回文串。
(1)遍历字符串去掉空格,标点符号;interview 48 最长不重复的子字符串
(2)转成小写字符,std::transform(begin(), end(), ::tolower);
(3)判断是否为回文串,即str==std::string(str.rbegin(), str.rend())
*/
void test_is_palindrome() {
std::string s = "A man, a plan, a canal: Panama";
bool result = search::isPalindrome(s);
printf("result:%d\n", result);
}
/*
18. 求二叉树最大的路径之和。dfs
当前节点的最大路径之和=val + left_node_result + right_node_result;
return val + max(left_node_result, right_node_result);
再刷感想:1.dfs过程中要计算两个值:1.包含当前节点的单边path的最大值,2.包含当前节点的最大路径之和.
2.因为是可以选择任意节点,所以只有在路径大于零时才将该路径并入,单边path,最大路径和都需要比较左右子树的路径大小是否>0
*/
void test_maxPathSum() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
// int result = search::binary_tree::maxPathSum(root);
int result = search::binary_tree::maxPathSum_V2(root);
printf("result:%d\n", result);
}
/*
19. 买卖两次股票,收益最大能到多少。
使用buy1, sell1,buy2,sell2模拟两次交易的内容。
buy1=max(buy1, -prices[i]); 买入股票需要掏出的钱,越少越好
sell1=max(sell1, buy1+prices[i]); 卖出股票,剩余的钱越多越好;
buy2=max(buy2, sell1-prices[i]); 第二次买入股票
sell2=max(sell2, buy2+prices[i])
*/
void test_maxprofix() {
int arr[] = {3,2,1,3,4,5,4,6,1,7};
std::vector<int> vec(arr, arr+10);
// int result = search::maxProfit_v3(vec);
int result = search::max_profit_2(vec);
printf("result:%d\n", result);
}
/*
20. 求三角形从上到下最小的路径之和。其中只能和其相邻的数相加。
动态规划 dp[2][line]
*/
void test_minimumTotal() {
std::vector<std::vector<int> > triangle;
int line1[]={2};
int line2[]={3,4};
int line3[]={6,5,7};
int line4[]={4,1,8,3};
std::vector<int> line1_v(line1, line1+1);
std::vector<int> line2_v(line2, line2+2);
std::vector<int> line3_v(line3, line3+3);
std::vector<int> line4_v(line4, line4+4);
triangle.push_back(line1_v);
triangle.push_back(line2_v);
triangle.push_back(line3_v);
triangle.push_back(line4_v);
int result = dp::minimumTotal(triangle);
printf("result:%d\n", result);
}
/*
21. 生成杨辉三角
*/
void test_pascal_row() {
// std::vector<int> result = dp::getRow(3);
// for (int i=0; i<result.size(); i++) {
// printf("%d, ", result[i]);
// }
// printf("\n");
std::vector<std::vector<int> > result = dp::generate(3);
for (int i=0; i<result.size(); i++) {
for(int j=0; j<=i; j++) {
printf("%d ",result[i][j]);
}
printf("\n");
}
}
/*
22. 给二叉树兄弟节点加上next指针。
通过queue依次得到每一层的所有节点,然后将依次设置节点的next指针。
*/
void test_populating_next_right_pointer() {
TreeLinkNode* root = new TreeLinkNode(1);
root->left = new TreeLinkNode(2);
root->right = new TreeLinkNode(3);
// root->left->left = new TreeLinkNode(4);
root->left->right = new TreeLinkNode(5);
// root->right->left = new TreeLinkNode(6);
// root->right->right = new TreeLinkNode(7);
search::populating_next_right_pointers_in_each_node(root);
TreeLinkNode* curr_left=root;
while(curr_left != nullptr) {
TreeLinkNode* curr = curr_left;
while(curr != nullptr) {
printf("%d ", curr->val);
curr = curr->next;
}
printf("\n");
curr_left = curr_left->left;
}
// delete root->right->right;
// delete root->right->left;
// delete root->left->right;
// delete root->left->left;
// delete root->left;
// delete root->right;
// delete root;
}
/*
23. 求两个字符串的最短距离,dp求解,根据代码没看懂问题的定义
*/
void test_min_distance_of_string() {
std::string S = "rabbbit"; // ""rabbbit";
std::string T = "rabbit"; // "rabbit";
int result = dp::min_distance_of_str(S, T);
printf("result:%d\n", result);
}
/*
24. 遍历二叉树的路径,判断是否存在和为sum的路径,并返回所有可能的路径结果
回溯法。bfs(combinations, curr, res, root)
将val push curr
如果res==root->val && root->left==null && root->right==null 则将curr push到结果中;
bfs(combinations, curr, res, root->left)
bfs(combinations, curr, res, root->right)
*/
void test_haspathsum() {
TreeNode* root = new TreeNode(-2);
root->left = new TreeNode(-3);
// root->right = new TreeNode(1);
// root->left->right = new TreeNode(11);
// root->right->left = new TreeNode(13);
// root->right->right = new TreeNode(4);
int sum = -5;
bool result = search::hasPathSum(root, sum);
printf("result:%d\n", result);
std::vector<std::vector<int>> results = search::pathSum(root, sum);
// std::vector<std::vector<int>> results = search::pathSum_bfs(root, sum);
for (int i=0; i< results.size(); i++) {
for(int j=0; j<results[i].size(); j++) {
printf("%d ", results[i][j]);
}
printf("\n");
}
}
/*
25. 快速排序,堆排序
快排: 先从j开始,while(arr[j]<=ref&& i<j)j--; arr[j]=arr[i];
堆排序: 先构建最大堆。从k=length/2-1-->0调整堆的顺序;
然后依次从length-1->1, 交换arr[0],arr[i]的值,调整堆的顺序;
heap_modify: 注意dad=start,son=2*dad+1; while(son<=end) {
找到左右子节点最大的一个,如果son的值大于dad的交换两者,dad=son;son=2*dad+1;
否则直接返回。
}
*/
void test_qsort() {
// int a[] = {6, 2, 1, 3, 5, 4};
int len = 20;
int a[len];
int b[len];
// int a[] = {3, 6, 7, 5, 3, 5, 6, 2, 9, 1};
for (int i=0; i<len; i++) {
a[i] = std::rand() % len;
b[i] = a[i];
}
for (int i=0; i<len; i++) {
printf("%d ", a[i]);
}
printf("\n");
std::qsort(b, len, sizeof(int), utils::compare);
for(int i=0; i<len; i++) {
printf("%d ", b[i]);
}
printf("\n");
// sort::qsort(a, 0, len -1);
// sort::heap_sort(a, 0, len-1);
// sort::qsort_v2(a, 0, len-1);
std::vector<int> a_vec = std::vector<int>(a, a+len);
sort::qsort_v3(a_vec);
for (int i=0; i<len; i++) {
printf("%d ", a_vec[i]);
}
printf("\n");
}
/*
26. 两个链表数字相加。
1.将两个链表对应位分别相加,合成一个链表后再转成正常数字。注意最后一位是否进位的问题。
2.将两个链表对应位相加,使用carry位保留前一位的进位,在相加过程中完成进位。
*/
void test_add_two_numbers() {
ListNode* l1 = new ListNode(9);
l1->next = new ListNode(8);
// l1->next->next = new ListNode(3);
ListNode *l2 = new ListNode(1);
// l2->next = new ListNode(6);
// l2->next->next = new ListNode(4);
ListNode *result = search::addTwoNumbers_v2(l1, l2);
while(result != nullptr) {
printf("%d ", result->val);
result = result->next;
}
}
/*
27. 从两个有序数组中找出中位数。
1. 先对两个数组merge,然后直接找出中位数。
2. 二分查找。每次查找两个数组中的k/2个,直接舍弃较小的那一部分。
dfs(nums1, low1, nums2, low2, k);
注意k==1,low1,low2是否在nums1,nums2之内。
if (low1+k/2-1<nums1.size())mid1=nums1[low1+k/2-1];
if (low2+k/2-1<nums2.size()) mid2 = nums2[low2+k/2-1];
if (mid1<mid2) dfs(nums1, low1+k/2, nums2, low2, k-k/2);
else dfs(nums1, low1, nums2, low2+k/2, k-k/2);
*/
void test_find_mid_num() {
std::vector<int> a={1, 3};
std::vector<int> b={2};
// double result = search::findMedianSortedArrays(a, b);
double result = search::findMedianSortedArrays_v2(a, b);
printf("result:%f \n", result);
}
/*
28. 求字符串中最长的回文子串。
dp[][] 记录i->j是否为回文串
dp[i][j]与 dp[i+1][j-1]的关系,注意考虑a|a,aba两者情况
*/
void test_length_palindrome() {
std::string str = "abaabca"; //"abcdasdfghjkldcba";
// std::string result = search::longestPalindrome(str);
// std::string result = dp::longestPalindrome_v2(str);
// std::string result = dp::longestPalindrome_v3(str);
// std::string result = dp::longestPalindrome_v4(str);
std::string result = dp::longestPalindrome_v5(str);
printf("result: %s\n", result.c_str());
}
/*
29. 字符按照N字形排列,按行输出最后的顺序。
推导出N字排列的规律。一个周期为2*rows-2,
钱rows个为列,后面row-2个斜向上递增。
*/
void test_z_convert() {
std::string str = "LEETCODEISHIRING";
int rows = 4;
std::string result = search::z_convert(str, rows);
printf("result:%s\n", result.c_str());
}
/*
30. 数字转换
1. 特殊处理第一个字符,判断是否存在正负号
2. 使用double保存中间结果避免int溢出,然后对int32_max,int32_min进行判断
*/
void test_my_atoi() {
std::string str= "-2147483647";
int result = search::myAtoi(str);
printf("result:%d\n", result);
}
/*
31. 正则表达式匹配
dp求解:dp[i][j]表示s的前i个字符与p的前j个字符是否匹配。
注意*匹配0个字符的情况。初始化i=0的情况,if p[j]='*' p[j]=p[j-2]
注意: 1. *号匹配要满足s[idx]==p[j],
2. 字符下标和dp下标
3. 初始化dp[0][i]的时候,考虑*匹配0个字符的情况,
如果p[i-1]=='*', dp[0][i]应该等于dp[0][i-2], 而不是直接等于true
再刷感想:1. 必须有dp[n+1,m+1]即匹配0个元素的状态,否则无法处理s="",p=".*"这种
2.匹配0个字符情况下特殊处理,且返回值为dp[n][m]
3. 在匹配>=1个字符时,s[idx]与p[j]要match
再刷感想:1. p[j]!='*'时,s[i-1]与p[j-1]匹配时,dp[i][j]=dp[i-1][j-1],而不是直接为true
*/
void test_regular_match() {
std::string s= "aa"; //"aab"; //"acbbcbcbcbaaacaac"; //"aab"; //"issi"; //"mississippi";
std::string p = "a"; //"c*a*b"; //"ac*.a*ac*.*ab*b*ac"; //"c*a*b"; //"is*"; // "mis*is*p*.";
// bool result = dp::regular_match(s, p);
// bool result = dp::regular_match_v2(s, p);
// bool result = dp::regular_match_v3(s, p);
bool result = dp::regular_match_v4(s, p);
printf("result:%d\n", result);
}
/*
32. 最大的矩形面积
1.维护一个升序的栈,纪录对于数字的index,当当前数值>stack.top()时,直接push
2.当小于时,记录以当前栈顶元素为高,i-当前栈顶元素前一个元素的idx
3.最后依次pop stack中的元素,(len-i)* high
再刷心得:维护一个升序栈,当前元素小于栈顶元素时,一直pop,并计算area,而不是只pop 一次栈顶元素.
*/
void test_largest_rectangle_area() {
std::vector<int> arr = {2,1,5,6,2,3}; //{4, 1000, 1000, 1000, 1000}; // {7, 2, 1, 4, 5, 1, 3, 3}; // {3, 1, 6, 5, 2, 3}; // {2,1,5,6,2,3};
// int result = search::largestRectangleArea(arr);
int result = stack_algs::largestRectangleArea(arr);
printf("result:%d\n", result);
}
/*
33. 求最大方阵长度
dp求解dp[i][j]表示0,0-->i,j部分最大方阵的长度。
dp[i][j]=min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
*/
void test_maximal_square() {
std::vector<std::vector<char>> matrix = {{'1', '0', '1', '0', '0'},
{'1', '0', '1', '1', '1'},
{'1', '1', '1', '1', '1'},
{'1', '0', '0', '1', '0'}};
int result = dp::maximalSquare(matrix);
printf("result:%d\n", result);
}
/*
34. 求水箱的最大容量
从两边往中间依次遍历即可。
*/
void test_max_area_in_water_tank() {
std::vector<int> arr= {1,8,6,2,5,4,8,3,7}; //{1,2,4,3}; // {1,2}; // {1,8,6,2,5,4,8,3,7};
// int result = search::maxArea(arr);
// int result = search::maxArea_v2(arr);
int result = search::maxArea_v3(arr);
printf("result:%d\n", result);
}
/*
35. 转换成罗马数字
建立一个<int, string>的map,
列举所有可能的值:1,4,5,9.... 对应的string "I", "IV"
降序排列。
*/
void test_int_to_map() {
// std::string result = search::intToRoman_v2(1994);
std::string result = search::intToRoman_v3(1994);
printf("result:%s\n", result.c_str());
}
/*
36. 判断一棵数是不是另一棵树的子树
需要额外判断子树是否相等。因为是否是子树必须是两者相等。
if (root->val!=sub->val)
(issame(root->left, sub->left)&& issame(root->right, sub->right)||
isSub(root->left, sub)||isSub(root->right, sub)
else:
isSub(root->left, sub)||isSub(root->right, sub)
)
*/
void test_is_subtree() {
TreeNode* root = new TreeNode(3);
root->left = new TreeNode(4);
root->right = new TreeNode(5);
root->left->left = new TreeNode(1);
root->right->left = new TreeNode(2);
// root->left->left = new TreeNode(0);
TreeNode* sub = new TreeNode(3);
sub->left = new TreeNode(1);
sub->right = new TreeNode(2);
bool result = search::isSubtree(root, sub);
printf("result:%d\n", result);
}
/*
37. 找到两个节点最近的公共祖先
递归判断一棵树中是否存在p或q节点
left = dfs(root->left, p,q)
right = dfs(root->right, p,q);
if (left==null&& right==null) return null
if(left!=null && right!=null) return root //左右节点均存在p或q
if (left!=null && right==null) return left // 只有left存在p或q
if (left==null && right!=null) return right
*/
void test_is_lowest_ancestor() {
TreeNode* root = new TreeNode(3);
root->left = new TreeNode(5);
root->right = new TreeNode(1);
root->left->left = new TreeNode(6);
root->left->right = new TreeNode(2);
root->left->right->left = new TreeNode(7);
root->left->right->right = new TreeNode(4);
root->right->left = new TreeNode(0);
root->right->right = new TreeNode(8);
TreeNode* p = root->left;
TreeNode* q = root->left->right->right;
TreeNode* result = search::lowestCommonAncestor2(root, p, q);
printf("result:%lf\n", result->val);
}
/*
38. 找到树中所有可能到sum,并返回出现次数最多的元素
*/
void test_requent_tree_sum() {
TreeNode* root = new TreeNode(5);
root->left = new TreeNode(2);
root->right = new TreeNode(-5);
// root->left->left = new TreeNode(6);
// root->left->right = new TreeNode(2);
// root->left->right->left = new TreeNode(7);
// root->left->right->right = new TreeNode(4);
// root->right->left = new TreeNode(0);
// root->right->right = new TreeNode(8);
std::vector<int> result = search::findFrequentTreeSum(root);
for (int i=0; i<result.size(); i++) {
printf("%d ", result[i]);
}
printf("\n");
}
/*
39. 简化路径
1. 以‘/’划分字符子串得到items。
2. 遍历items,依次将item压入栈中,当出现'..'时pop;
3. 依次弹出item,result = '/' + item + result;
再刷感想:注意分词时别漏了最后一个词.
*/
void test_simple_path() {
std::string path = "/a//b////c/d//././/.."; //"/a/../../b/../c//.//"; // "/a/./b/../../c/"; // "/home//foo/"; // "/../"; // "/home/";
// std::string result = search::simplifyPath(path);
std::string result = search::simplifyPath_V2(path);
printf("result:%s\n", result.c_str());
}
/*
40. 反转链表m,n之间的元素
1. 记录m的前一个元素和m元素的指针。然后从m+1个元素开始,
node(m+1)->next=node(m-1)->next;
node(m-1)->next = node(m+1);
2. 在n的时候,node(m)->next=node(n)->next;
*/
void test_reverse_between() {
ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
head->next->next->next = new ListNode(4);
head->next->next->next->next = new ListNode(5);
ListNode* result = search::reverseBetween(head, 2, 2);
while(result!=nullptr) {
printf("%d ", result->val);
result = result->next;
}
printf("\n");
}
/*
41. 判断4个数是否可以求得24点
1. 递归求解,先从4个数中选取两个数进行一直运算得到结果,
然后从3个数中选两个得到结果,最终只剩一个数时,判断是否等于24
*/
void test_juge_point24() {
// std::vector<int> nums = {1, 2, 1, 2}; // {4, 1, 8, 7};
// bool result = search::judgePoint24(nums);
std::vector<double> nums = {4, 1, 8, 7};
char op_types[5] = {'*', '+', '/', '-'};
bool result = search::judgePoint24_v2(nums, op_types);
printf("result:%d\n", result);
}
/*
42. 矩阵旋转遍历
模拟旋转遍历,注意i,j是否越界
*/
void test_spiral_order() {
std::vector<std::vector<int>> matrix = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16}}; // {{1,2,3}, {4,5,6}, {7,8,9}};
std::vector<int> result = search::spiralOrder(matrix);
for (int i=0; i<result.size(); i++) {
printf("%d ", result[i]);
}
printf("\n");
}
/*
43. 生成旋转矩阵
与42类似
*/
void test_generate_matrix(){
std::vector<std::vector<int>> result = search::generateMatrix(3);
for (int i=0; i< result.size(); i++) {
for (int j=0; j<result[0].size(); j++) {
printf("%d ", result[i][j]);
}
printf("\n");
}
}
/*
43. 找出递增数组中val与idx一致的数。
递增数组中val与idx一致的数只可能出现连续的一次。不可能出现多次。
mid = (left+right)/2
// 左边不可能存在符合条件的数
if num[mid]<mid: dfs(mid+1, right)
else dfs(left, mid-1)
*/
void test_match_idx_val() {
std::vector<int> data = {-5,1,2,3,6};
std::vector<int> result;
search::match_idx_val(data, result, 0, 4);
for (int i=0; i<result.size(); i++) {
printf("%d ", result[i]);
}
printf("\n");
result.clear();
search::match_idx_val_v2(data, result, 0, 4);
for (int i=0; i<result.size(); i++) {
printf("%d ", result[i]);
}
printf("\n");
}
/*
44. 求所有二叉树非叶子节点总和的最小值。
dp求解。定义辅助数组aux[i][j]表示i->j元素中最大的值
dp[i][j]表示i->j中总和最小值,则dp[i][j]=min(dp[i][k]+dp[k][j])+ aux[i][k]*aux[k][j];
*/
void test_mct_from_leaf() {
std::vector<int> data= {6,2,4};
int result = dp::mctFromLeafValues(data);
printf("result:%d\n", result);
}
/*
45. 三数之和
先对数组排序,设置first,second,thrid指针,不能指向重复的元素
for (int i=0; i<n-2; i++) {
secod=i+1;
third = n-1;
if (nums[first]+nums[secod]==target-nums[third])....
}
注意:1. 不指向重复元素时, 要判断second 始终小于third. 同时该操作只需要在
nums[first]+nums[second] == target - nums[third]时做,而不需要在外面也判断,
因为second+, third--即可达到同样目的.
*/
void test_three_sum() {
std::vector<int> data = {-1, 0, 1, 2, -1, -4}; //{-2,0,0,2,2}; //{-1, 0, 1, 2, -1, -4};
// std::vector<std::vector<int>> result = search::threeSum(data);
// std::vector<std::vector<int>> result = search::threeSum_v2(data);
std::vector<std::vector<int>> result = search::threeSum_v3(data);
for (int i=0; i<result.size(); i++) {
for (int j=0; j<result[i].size(); j++) {
printf("%d ", result[i][j]);
}
printf("\n");
}
}
/*
46. 田忌赛马 参考:https://leetcode.cn/problems/advantage-shuffle/solution/you-shi-xi-pai-by-leetcode-solution-sqsf/
1.对A,B进行排序。2.注意B中可能存在重复的元素。
if A[j]> B[i]:match_map[B[i]].push(A[j]);
else: unmatch.push(A[j]);
*/
void test_advantage_count() {
std::vector<int> A = {2,0,4,1,2}; // {12,24,8,32}; //{2,7,11,15};
std::vector<int> B = {1,3,0,0,2}; // {13,25,32,11}; // {1,10,4,11};
std::vector<int> result = greedy::advantageCount(A, B);
for (int i=0;i<result.size(); i++) {
printf("%d ", result[i]);
}
printf("\n");
}
/*
47. 判断是否可以跳到终点
记录当前可到达的最远点k=max(k, nums[i]+i)
*/
void test_can_jump() {
std::vector<int> data = {3,2,1,0,4}; //{2,3,1,1,4};
// bool result = greedy::canJump(data);
// printf("result:%d\n", result);
int result = greedy::jump(data);
printf("result:%d\n", result);
}
/*
48. 判断能否环绕一圈
同11
*/
void test_can_complete_circuit() {
std::vector<int> gas = {1,2,3,4,5}; // {2,3,4}; //{1,2,3,4,5};
std::vector<int> costs = {3,4,5,1,2}; // {3,4,3}; // {3,4,5,1,2};
// int result = greedy::canCompleteCircuit(gas, costs);
int result = greedy::canCompleteCircuit_v2(gas, costs);
printf("results:%d\n", result);
}
/*
49. 正则表达式,类似31
注意初始化匹配0个元素的情况
*/
void test_match_str() {
std::string s = "aa"; // "adceb";
std::string p = "*ab"; // "*a*b";
bool result = greedy::isMatch(s, p);
printf("result:%d\n", result);
}
/*
50. 删除冗余字符,并使得保留的字符字典序最小
遍历字符串,查询i以后的字符中是否存在该字符
while (result.back()>s[i] && s.find(result.back(), i)!=string::npos) result.pop_back()
*/
void test_remove_duplicate_letters() {
std::string s = "cbacdcbc"; // "bcabc";
std:string result = greedy::removeDuplicateLetters(s);
printf("result:%s\n", result.c_str());
}
/*
51. 求数组中连续子串总和最大的值。
记录curr_sum,如果curr_sum>0 则curr_sum+=nums[i];
else curr_sum=nums[i];
*/