forked from soulmachine/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 97
/
chapLinearList.tex
2244 lines (1675 loc) · 59.5 KB
/
chapLinearList.tex
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
\chapter{线性表}
这类题目考察线性表的操作,例如,数组,单链表,双向链表等。
\section{数组} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Remove Duplicates from Sorted Array}
\label{sec:remove-duplicates-from-sorted-array}
\subsubsection{描述}
Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this in place with constant memory.
For example, Given input array \code{A = [1,1,2]},
Your function should return length = 2, and A is now \code{[1,2]}.
\subsubsection{分析}
\subsubsection{代码}
\begin{Code}
// LeetCode, Remove Duplicates from Sorted Array
class Solution {
public:
int removeDuplicates(int A[], int n) {
if (n == 0) return 0;
int index = 0;
for (int i = 1; i < n; i++) {
if (A[index] != A[i])
A[++index] = A[i];
}
return index + 1;
}
};
\end{Code}
\begin{Code}
// LeetCode, Remove Duplicates from Sorted Array,使用STL
class Solution {
public:
int removeDuplicates(int A[], int n) {
return removeDuplicates(A, A + n, A) - A;
}
template<typename InIt, typename OutIt>
OutIt removeDuplicates(InIt first, InIt last, OutIt output) {
while (first != last) {
*output++ = *first;
first = find_if(first, last,
bind1st(not_equal_to<int>(), *first));
}
return output;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item Remove Duplicates from Sorted Array II,见 \S \ref{sec:remove-duplicates-from-sorted-array-ii}
\myenddot
\subsection{Remove Duplicates from Sorted Array II}
\label{sec:remove-duplicates-from-sorted-array-ii}
\subsubsection{描述}
Follow up for "Remove Duplicates":
What if duplicates are allowed at most twice?
For example,
Given sorted array \code{A = [1,1,1,2,2,3]},
Your function should return length = 5, and A is now \code{[1,1,2,2,3]}
\subsubsection{分析}
加一个变量记录一下元素出现的次数即可。这题因为是已经排序的数组,所以一个变量即可解决。如果是没有排序的数组,则需要引入一个hashmap来记录出现次数。
\subsubsection{代码}
\begin{Code}
// LeetCode, Remove Duplicates from Sorted Array II
class Solution {
public:
int removeDuplicates(int A[], int n) {
if (n == 0) return 0;
int occur = 1;
int index = 0;
for (int i = 1; i < n; i++) {
if (A[index] == A[i]) {
if (occur < 2) {
A[++index] = A[i];
occur++;
}
} else {
A[++index] = A[i];
occur = 1;
}
}
return index + 1;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item Remove Duplicates from Sorted Array,见 \S \ref{sec:remove-duplicates-from-sorted-array}
\myenddot
\subsection{Search in Rotated Sorted Array}
\label{sec:search-in-rotated-sorted-array}
\subsubsection{描述}
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., \code{0 1 2 4 5 6 7} might become \code{4 5 6 7 0 1 2}).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.
\subsubsection{分析}
二分查找,难度主要在于左右边界的确定。
\subsubsection{代码}
\begin{Code}
// LeetCode, Search in Rotated Sorted Array
class Solution {
public:
int search(int A[], int n, int target) {
int first = 0, last = n;
while (first != last) {
const int mid = (first + last) / 2;
if (A[mid] == target)
return mid;
if (A[first] <= A[mid]) {
if (A[first] <= target && target < A[mid])
last = mid;
else
first = mid + 1;
} else {
if (A[mid] < target && target <= A[last-1])
first = mid + 1;
else
last = mid;
}
}
return -1;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item Search in Rotated Sorted Array II,见 \S \ref{sec:search-in-rotated-sorted-array-ii}
\myenddot
\subsection{Search in Rotated Sorted Array II}
\label{sec:search-in-rotated-sorted-array-ii}
\subsubsection{描述}
Follow up for "Search in Rotated Sorted Array": What if \emph{duplicates} are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given target is in the array.
\subsubsection{分析}
允许重复元素,则上一题中如果\fn{A[m]>=A[l]},那么\fn{[l,m]}为递增序列的假设就不能成立了,比如\code{[1,3,1,1,1]}。
如果\fn{A[m]>=A[l]}不能确定递增,那就把它拆分成两个条件:
\begindot
\item 若\fn{A[m]>A[l]},则区间\fn{[l,m]}一定递增
\item 若\fn{A[m]==A[l]} 确定不了,那就\fn{l++},往下看一步即可。
\myenddot
\subsubsection{代码}
\begin{Code}
// LeetCode, Search in Rotated Sorted Array II
class Solution {
public:
bool search(int A[], int n, int target) {
int first = 0, last = n;
while (first != last) {
const int mid = (first + last) / 2;
if (A[mid] == target)
return true;
if (A[first] < A[mid]) {
if (A[first] <= target && target < A[mid])
last = mid;
else
first = mid + 1;
} else if (A[first] > A[mid]) {
if (A[mid] <= target && target <= A[last-1])
first = mid + 1;
else
last = mid;
} else
//skip duplicate one, A[start] == A[mid]
first++;
}
return false;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item Search in Rotated Sorted Array,见 \S \ref{sec:search-in-rotated-sorted-array}
\myenddot
\subsection{Median of Two Sorted Arrays}
\label{sec:median-of-two-sorted-arrays}
\subsubsection{描述}
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be $O(\log (m+n))$.
\subsubsection{分析}
这是一道非常经典的题。这题更通用的形式是,给定两个已经排序好的数组,找到两者所有元素中第$k$大的元素。
$O(m+n)$的解法比较直观,直接merge两个数组,然后求第$k$大的元素。
不过我们仅仅需要第$k$大的元素,是不需要“排序”这么复杂的操作的。可以用一个计数器,记录当前已经找到第$m$大的元素了。同时我们使用两个指针\fn{pA}和\fn{pB},分别指向A和B数组的第一个元素,使用类似于merge sort的原理,如果数组A当前元素小,那么\fn{pA++},同时\fn{m++};如果数组B当前元素小,那么\fn{pB++},同时\fn{m++}。最终当$m$等于$k$的时候,就得到了我们的答案,$O(k)$时间,$O(1)$空间。但是,当$k$很接近$m+n$的时候,这个方法还是$O(m+n)$的。
有没有更好的方案呢?我们可以考虑从$k$入手。如果我们每次都能够删除一个一定在第$k$大元素之前的元素,那么我们需要进行$k$次。但是如果每次我们都删除一半呢?由于A和B都是有序的,我们应该充分利用这里面的信息,类似于二分查找,也是充分利用了“有序”。
假设A和B的元素个数都大于$k/2$,我们将A的第$k/2$个元素(即\fn{A[k/2-1]})和B的第$k/2$个元素(即\fn{B[k/2-1]})进行比较,有以下三种情况(为了简化这里先假设$k$为偶数,所得到的结论对于$k$是奇数也是成立的):
\begindot
\item \fn{A[k/2-1] == B[k/2-1]}
\item \fn{A[k/2-1] > B[k/2-1]}
\item \fn{A[k/2-1] < B[k/2-1]}
\myenddot
如果\fn{A[k/2-1] < B[k/2-1]},意味着\fn{A[0]}到\fn{A[k/2-1}的肯定在$A \cup B$的top k元素的范围内,换句话说,\fn{A[k/2-1}不可能大于$A \cup B$的第$k$大元素。留给读者证明。
因此,我们可以放心的删除A数组的这$k/2$个元素。同理,当\fn{A[k/2-1] > B[k/2-1]}时,可以删除B数组的$k/2$个元素。
当\fn{A[k/2-1] == B[k/2-1]}时,说明找到了第$k$大的元素,直接返回\fn{A[k/2-1]}或\fn{B[k/2-1]}即可。
因此,我们可以写一个递归函数。那么函数什么时候应该终止呢?
\begindot
\item 当A或B是空时,直接返回\fn{B[k-1]}或\fn{A[k-1]};
\item 当\fn{k=1}是,返回\fn{min(A[0], B[0])};
\item 当\fn{A[k/2-1] == B[k/2-1]}时,返回\fn{A[k/2-1]}或\fn{B[k/2-1]}
\myenddot
\subsubsection{代码}
\begin{Code}
// LeetCode, Median of Two Sorted Arrays
class Solution {
public:
double findMedianSortedArrays(int A[], int m, int B[], int n) {
int total = m + n;
if (total & 0x1)
return find_kth(A, m, B, n, total / 2 + 1);
else
return (find_kth(A, m, B, n, total / 2)
+ find_kth(A, m, B, n, total / 2 + 1)) / 2;
}
private:
static double find_kth(int A[], int m, int B[], int n, int k) {
//always assume that m is equal or smaller than n
if (m > n) return find_kth(B, n, A, m, k);
if (m == 0) return B[k - 1];
if (k == 1) return min(A[0], B[0]);
//divide k into two parts
int pa = min(k / 2, m), pb = k - pa;
if (A[pa - 1] < B[pb - 1])
return find_kth(A + pa, m - pa, B, n, k - pa);
else if (A[pa - 1] > B[pb - 1])
return find_kth(A, m, B + pb, n - pb, k - pb);
else
return A[pa - 1];
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item 无
\myenddot
\subsection{Longest Consecutive Sequence} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:longest-consecutive-sequence}
\subsubsection{描述}
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
For example,
Given \code{[100, 4, 200, 1, 3, 2]},
The longest consecutive elements sequence is \code{[1, 2, 3, 4]}. Return its length: 4.
Your algorithm should run in $O(n)$ complexity.
\subsubsection{分析}
如果允许$O(n \log n)$的复杂度,那么可以先排序,可是本题要求$O(n)$。
由于序列里的元素是无序的,又要求$O(n)$,首先要想到用哈希表。
用一个哈希表 \fn{unordered_map<int, bool> used}记录每个元素是否使用,对每个元素,以该元素为中心,往左右扩张,直到不连续为止,记录下最长的长度。
\subsubsection{代码}
\begin{Code}
// Leet Code, Longest Consecutive Sequence
class Solution {
public:
int longestConsecutive(vector<int> const& num) {
unordered_map<int, bool> used;
for (auto i : num) used[i] = false;
int longest = 0;
for (auto i : num) {
if (used[i]) continue;
int length = 1;
used[i] = true;
for (int j = i + 1; used.find(j) != used.end(); ++j) {
used[j] = true;
++length;
}
for (int j = i - 1; used.find(j) != used.end(); --j) {
used[j] = true;
++length;
}
longest = max(longest, length);
}
return longest;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item 无
\myenddot
\subsection{3Sum} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:3sum}
\subsubsection{描述}
Given an array $S$ of $n$ integers, are there elements $a, b, c$ in $S$ such that $a + b + c = 0$? Find all unique triplets in the array which gives the sum of zero.
Note:
\begindot
\item Elements in a triplet $(a,b,c)$ must be in non-descending order. (ie, $a \leq b \leq c$)
\item The solution set must not contain duplicate triplets.
\myenddot
For example, given array \code{S = \{-1 0 1 2 -1 -4\}}.
A solution set is:
\begin{Code}
(-1, 0, 1)
(-1, -1, 2)
\end{Code}
\subsubsection{分析}
先排序,然后二分查找,复杂度 $O(n^2 \log n)$。
\subsubsection{代码}
\begin{Code}
// LeetCode, 3Sum
// 先排序,然后二分查找
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& num) {
vector<vector<int>> result;
if (num.size() < 3) return result;
sort(num.begin(), num.end());
const int target = 0;
auto last = num.end();
for (auto a = num.begin(); a < prev(last, 2);
a = upper_bound(a, prev(last, 2), *a)) {
for (auto b = next(a); b < prev(last);
b = upper_bound(b, prev(last), *b)) {
const int c = target - *a - *b;
if (binary_search(next(b), last, c))
result.push_back(vector<int> { *a, *b, c });
}
}
return result;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item 3Sum Closest, 见 \S \ref{sec:3sum-closest}
\item 4Sum, 见 \S \ref{sec:4sum}
\myenddot
\subsection{3Sum Closest} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:3sum-closest}
\subsubsection{描述}
Given an array $S$ of $n$ integers, find three integers in $S$ such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
For example, given array \code{S = \{-1 2 1 -4\}}, and \code{target = 1}.
The sum that is closest to the target is 2. (\code{-1 + 2 + 1 = 2}).
\subsubsection{分析}
先排序,然后左右夹逼,复杂度 $O(n^3)$。
\subsubsection{代码}
\begin{Code}
// LeetCode, 3Sum Closest
// 先排序,然后左右夹逼
class Solution {
public:
int threeSumClosest(vector<int>& num, int target) {
int result = 0;
int min_gap = INT_MAX;
sort(num.begin(), num.end());
for (auto a = num.begin(); a != prev(num.end(), 2);
a = upper_bound(a, prev(num.end(), 2), *a)) {
auto b = next(a);
auto c = prev(num.end());
while (b < c) {
const int sum = *a + *b + *c;
const int gap = abs(sum - target);
if (gap < min_gap) {
result = sum;
min_gap = gap;
}
if (sum < target)
b = upper_bound(b, c, *b);
else
c = prev(lower_bound(b, c, *c));
}
}
return result;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item 3Sum, 见 \S \ref{sec:3sum}
\item 4Sum, 见 \S \ref{sec:4sum}
\myenddot
\subsection{4Sum} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:4sum}
\subsubsection{描述}
Given an array $S$ of $n$ integers, are there elements $a, b, c$, and $d$ in $S$ such that $a + b + c + d = target$? Find all unique quadruplets in the array which gives the sum of target.
Note:
\begindot
\item Elements in a quadruplet $(a,b,c,d)$ must be in non-descending order. (ie, $a \leq b \leq c \leq d$)
\item The solution set must not contain duplicate quadruplets.
\myenddot
For example, given array \code{S = \{1 0 -1 0 -2 2\}}, and \code{target = 0}.
A solution set is:
\begin{Code}
(-1, 0, 0, 1)
(-2, -1, 1, 2)
(-2, 0, 0, 2)
\end{Code}
\subsubsection{分析}
跟 3Sum 很类似,先排序,然后二分查找,复杂度 $O(n^3 \log n)$,会超时。
然后想到,可以先缓存两个数的和,最终复杂度$O(n^3)$。这个策略也适用于 3Sum 。
\subsubsection{代码}
\begin{Code}
// LeetCode, 4Sum
// 先排序,然后二分查找,复杂度n^3*logn,会超时
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& num, int target) {
vector<vector<int>> result;
if (num.size() < 4) return result;
sort(num.begin(), num.end());
auto last = num.end();
for (auto a = num.begin(); a < prev(last, 3);
a = upper_bound(a, prev(last, 3), *a)) {
for (auto b = next(a); b < prev(last, 2);
b = upper_bound(b, prev(last, 2), *b)) {
for (auto c = next(b); c < prev(last);
c = upper_bound(c, prev(last), *c)) {
const int d = target - *a - *b - *c;
if (binary_search(next(c), last, d))
result.push_back(vector<int> { *a, *b, *c, d });
}
}
}
return result;
}
};
\end{Code}
\begin{Code}
// LeetCode, 4Sum
// 先缓存两个数的和,复杂度O(n^3)
class Solution {
public:
vector<vector<int> > fourSum(vector<int> &num, int target) {
if (num.size() < 4) return vector<vector<int> >();
sort(num.begin(), num.end());
map<int, vector<pair<int, int> > > cache;
for (size_t a = 0; a < num.size(); ++a) {
for (size_t b = a + 1; b < num.size(); ++b) {
cache[num[a] + num[b]].push_back(pair<int, int>(a, b));
}
}
set<vector<int>> result; // 去重,因为 num 里有重复元素
for (size_t c = 2; c < num.size(); ++c) {
for (size_t d = c + 1; d < num.size(); ++d) {
const int key = target - num[c] - num[d];
if (cache.find(key) != cache.end()) {
for (size_t k = 0; k < cache[key].size(); ++k) {
if (c <= cache[key][k].second) continue; // 有重叠
result.insert(vector<int> { num[cache[key][k].first],
num[cache[key][k].second], num[c], num[d] });
}
}
}
}
return vector<vector<int> >(result.begin(), result.end());
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item 3Sum, 见 \S \ref{sec:3sum}
\item 3Sum Closest, 见 \S \ref{sec:3sum-closest}
\myenddot
\subsection{Remove Element} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:remove-element }
\subsubsection{描述}
Given an array and a value, remove all instances of that value in place and return the new length.
The order of elements can be changed. It doesn't matter what you leave beyond the new length.
\subsubsection{分析}
无
\subsubsection{代码}
\begin{Code}
// LeetCode, Remove Element
class Solution {
public:
int removeElement(int A[], int n, int elem) {
int index = 0;
for (int i = 0; i < n; ++i) {
if (A[i] != elem) {
A[index++] = A[i];
}
}
return index;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item 无
\myenddot
\subsection{Next Permutation} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:next-permutation}
\subsubsection{描述}
Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
\begin{Code}
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
\end{Code}
\subsubsection{分析}
算法过程如图~\ref{fig:permutation}所示(来自\myurl{http://fisherlei.blogspot.com/2012/12/leetcode-next-permutation.html})。
\begin{center}
\includegraphics[width=360pt]{next-permutation.png}\\
\figcaption{下一个排列算法流程}\label{fig:permutation}
\end{center}
\subsubsection{代码}
\begin{Code}
// LeetCode, Next Permutation
class Solution {
public:
void nextPermutation(vector<int> &num) {
next_permutation(num.begin(), num.end());
}
template<typename BidiIt>
bool next_permutation(BidiIt first, BidiIt last) {
// Get a reversed range to simplify reversed traversal.
const auto rfirst = reverse_iterator<BidiIt>(last);
const auto rlast = reverse_iterator<BidiIt>(first);
// Begin from the second last element to the first element.
auto pivot = next(rfirst);
// Find `pivot`, which is the first element that is no less than its
// successor. `Prev` is used since `pivort` is a `reversed_iterator`.
while (pivot != rlast and !(*pivot < *prev(pivot)))
++pivot;
// No such elemenet found, current sequence is already the largest
// permutation, then rearrange to the first permutation and return false.
if (pivot == rlast) {
reverse(rfirst, rlast);
return false;
}
// Scan from right to left, find the first element that is greater than
// `pivot`.
auto change = find_if(rfirst, pivot, bind1st(less<int>(), *pivot));
swap(*change, *pivot);
reverse(rfirst, pivot);
return true;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item Permutation Sequence, 见 \S \ref{sec:permutation-sequence}
\item Permutations, 见 \S \ref{sec:permutations}
\item Permutations II, 见 \S \ref{sec:permutations-ii}
\item Combinations, 见 \S \ref{sec:combinations}
\myenddot
\subsection{Permutation Sequence} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:permutation-sequence}
\subsubsection{描述}
The set \fn{[1,2,3,…,n]} contains a total of $n!$ unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for $n = 3$):
\begin{Code}
"123"
"132"
"213"
"231"
"312"
"321"
\end{Code}
Given $n$ and $k$, return the kth permutation sequence.
Note: Given $n$ will be between 1 and 9 inclusive.
\subsubsection{分析}
简单的,可以用暴力枚举法,调用 $k-1$ 次 \fn{next_permutation()}。
暴力枚举法把前 $k$个排列都求出来了,比较浪费,而我们只需要第$k$个排列。
利用康托编码的思路,假设有$n$个不重复的元素,第$k$个排列是$a_1, a_2, a_3, ..., a_n$,那么$a_1$是哪一个位置呢?
我们把$a_1$去掉,那么剩下的排列为
$a_2, a_3, ..., a_n$, 共计$n-1$个元素,$n-1$个元素共有$(n-1)!$个排列,于是就可以知道 $a_1 = k / (n-1)!$。
同理,$a_2, a_3, ..., a_n$的值推导如下:
\begin{eqnarray}
k_2 &=& k\%(n-1)! \nonumber \\
a_2 &=& k_2/(n-2)! \nonumber \\
... &=& ... \nonumber \\
k_{n-1} &=& k_{n-2}\%2! \nonumber \\
a_{n-1} &=& k_{n-1}/1! \nonumber \\
a_n &=& 0 \nonumber
\end{eqnarray}
\subsubsection{代码}
\begin{Code}
// LeetCode, Permutation Sequence
// 思路一:next_permutation(),TLE
class Solution {
public:
string getPermutation(int n, int k) {
string s(n, '0');
for (int i = 0; i < n; ++i)
s[i] += i+1;
for (int i = 0; i < k-1; ++i)
next_permutation(s.begin(), s.end());
return s;
}
template<typename BidiIt>
bool next_permutation(BidiIt first, BidiIt last) {
// 代码见上一题 Next Permutation
}
};
\end{Code}
\begin{Code}
// LeetCode, Permutation Sequence
// 康托编码
class Solution {
public:
string getPermutation(int n, int k) {
string s(n, '0');
string result;
for (int i = 0; i < n; ++i)
s[i] += i + 1;
return kth_permutation(s, k);
}
private:
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; ++i)
result *= i;
return result;
}
// seq 已排好序,是第一个排列
template<typename Sequence>
Sequence kth_permutation(const Sequence &seq, int k) {
const int n = seq.size();
Sequence S(seq);
Sequence result;
int base = factorial(n - 1);
--k; // 康托编码从0开始
for (int i = n - 1; i > 0; k %= base, base /= i, --i) {
auto pos = next(S.begin(), k / base);
result.push_back(*pos);
S.erase(pos);
}
result.push_back(S[0]); // 最后一个
return result;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item Next Permutation, 见 \S \ref{sec:next-permutation}
\item Permutations, 见 \S \ref{sec:permutations}
\item Permutations II, 见 \S \ref{sec:permutations-ii}
\item Combinations, 见 \S \ref{sec:combinations}
\myenddot
\subsection{Valid Sudoku} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:valid-sudoku}
\subsubsection{描述}
Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules \myurl{http://sudoku.com.au/TheRules.aspx} .
The Sudoku board could be partially filled, where empty cells are filled with the character \fn{'.'}.
\begin{center}
\includegraphics[width=200pt]{sudoku.png}\\
\figcaption{A partially filled sudoku which is valid}\label{fig:sudoku}
\end{center}
\subsubsection{分析}
细节实现题。
\subsubsection{代码}
\begin{Code}
// LeetCode, Valid Sudoku
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
bool used[9];
for (int i = 0; i < 9; ++i) {
fill(used, used + 9, false);
for (int j = 0; j < 9; ++j) // 检查行
if (!check(board[i][j], used))
return false;
fill(used, used + 9, false);
for (int j = 0; j < 9; ++j) // 检查列
if (!check(board[j][i], used))
return false;
}
for (int r = 0; r < 3; ++r) // 检查 9 个子格子
for (int c = 0; c < 3; ++c) {
fill(used, used + 9, false);
for (int i = r * 3; i < r * 3 + 3; ++i)
for (int j = c * 3; j < c * 3 + 3; ++j)
if (!check(board[i][j], used))
return false;
}
return true;
}
bool check(char ch, bool used[9]) {
if (ch == '.') return true;
if (used[ch - '1']) return false;
used[ch - '1'] = true;
return true;
}
};
\end{Code}
\subsubsection{相关题目}
\begindot
\item Sudoku Solver, 见 \S \ref{sec:sudoku-solver}
\myenddot
\subsection{Trapping Rain Water} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{sec:trapping-rain-water}
\subsubsection{描述}
Given $n$ non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
For example,
Given \code{[0,1,0,2,1,0,1,3,2,1,2,1]}, return 6.
\begin{center}
\includegraphics{trapping-rain-water.png}\\
\figcaption{Trapping Rain Water}\label{fig:trapping-rain-water}
\end{center}
\subsubsection{分析}
对于每个柱子,找到其左右两边最高的柱子,该柱子能容纳的面积就是\code{min(max_left, max_right) - height}。所以,
\begin{enumerate}
\item 从左往右扫描一遍,对于每个柱子,求取左边最大值;
\item 从右往左扫描一遍,对于每个柱子,求最大右值;
\item 再扫描一遍,把每个柱子的面积并累加。
\end{enumerate}
也可以,
\begin{enumerate}
\item 扫描一遍,找到最高的柱子,这个柱子将数组分为两半;
\item 处理左边一半;
\item 处理右边一半。
\end{enumerate}
\subsubsection{代码}
\begin{Code}
// LeetCode, Trapping Rain Water
// 思路1
class Solution {
public:
int trap(int A[], int n) {
int *max_left = new int[n]();
int *max_right = new int[n]();
for (int i = 1; i < n; i++) {
max_left[i] = max(max_left[i - 1], A[i - 1]);
max_right[n - 1 - i] = max(max_right[n - i], A[n - i]);
}
int sum = 0;
for (int i = 0; i < n; i++) {
int height = min(max_left[i], max_right[i]);
if (height > A[i]) {
sum += height - A[i];
}
}
delete[] max_left;
delete[] max_right;
return sum;
}
};
\end{Code}
\begin{Code}
// LeetCode, Trapping Rain Water
// 思路2
class Solution {
public:
int trap(int A[], int n) {
int max = 0; // 最高的柱子,将数组分为两半
for (int i = 0; i < n; i++)
if (A[i] > A[max]) max = i;
int water = 0;
for (int i = 0, peak = 0; i < max; i++)
if (A[i] > peak) peak = A[i];
else water += peak - A[i];
for (int i = n - 1, top = 0; i > max; i--)
if (A[i] > top) top = A[i];
else water += top - A[i];
return water;