@@ -77,16 +77,15 @@ \subsubsection{代码}
77
77
public:
78
78
vector<vector<int> > subsets(vector<int> &S) {
79
79
vector<vector<int> > result;
80
- bool * selected = new bool[ S.size()] ;
80
+ vector< bool> selected( S.size(), false) ;
81
81
std::sort(S.begin(), S.end()); // 本题对顺序有要求,需要排序
82
82
83
83
subsets(S, selected, 0, result);
84
- delete[] selected;
85
84
return result;
86
85
}
87
86
88
87
private:
89
- static void subsets(const vector<int> &S, bool selected[] , int step,
88
+ static void subsets(const vector<int> &S, vector< bool> & selected, int step,
90
89
vector<vector<int> > &result) {
91
90
if (step == S.size()) {
92
91
vector<int> subset;
@@ -112,11 +111,12 @@ \subsection{二进制法}
112
111
113
112
这种方法最巧妙。因为它不仅能生成子集,还能方便的表示集合的并、交、差等集合运算。设两个集合的位向量分别为$ B_1 $ 和$ B_2 $ ,则$ B_1 |B_2 , B_1 \& B_2 , B_1 \^ B_2 $ 分别对应集合的并、交、对称差。
114
113
114
+ 二进制法,也可以看做是位向量法,只不过更加优化。
115
115
116
116
\subsubsection {代码 }
117
117
\begin {Code }
118
118
// LeetCode, Subsets
119
- // 二进制法
119
+ // 二进制法,也可以看做是位向量法,只不过更加优化
120
120
class Solution {
121
121
public:
122
122
vector<vector<int> > subsets(vector<int> &S) {
@@ -221,3 +221,233 @@ \subsubsection{相关题目}
221
221
\begindot
222
222
\item Subsets,见 \S \ref {sec:subsets }
223
223
\myenddot
224
+
225
+
226
+ \section {Permutations } % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227
+ \label {sec:permutations }
228
+
229
+
230
+ \subsection {next_permutation() }
231
+ \label {sec:next-permutation }
232
+ 偷懒的做法,可以直接使用\fn {std::next_permutation}。如果是在OJ网站上,可以用这个API偷个懒;如果是在面试中,面试官肯定会让你重新实现。
233
+
234
+ \subsubsection {代码 }
235
+ \begin {Code }
236
+ // LeetCode, Permutations
237
+ class Solution {
238
+ public:
239
+ vector<vector<int> > permute(vector<int> &num) {
240
+ vector<vector<int> > result;
241
+ std::sort(num.begin(), num.end());
242
+
243
+ do {
244
+ result.push_back(num);
245
+ } while(std::next_permutation(num.begin(), num.end()));
246
+ return result;
247
+ }
248
+ };
249
+ \end {Code }
250
+
251
+
252
+ \subsection {重新实现next_permutation() }
253
+ \label {sec:next-permutation-implement }
254
+ 算法过程如图~\ref {fig:permutation }所示(来自\myurl {http://fisherlei.blogspot.com/2012/12/leetcode-next-permutation.html})。
255
+
256
+ \begin {center }
257
+ \includegraphics [width=360pt]{next-permutation.png}\\
258
+ \figcaption {下一个排列算法流程}\label {fig:permutation }
259
+ \end {center }
260
+
261
+
262
+ \subsubsection {代码 }
263
+ \begin {Code }
264
+ // LeetCode, Permutations
265
+ // 重新实现 next_permutation()
266
+ class Solution {
267
+ public:
268
+ vector<vector<int>> permute(vector<int>& num) {
269
+ sort(num.begin(), num.end());
270
+
271
+ vector<vector<int>> permutations;
272
+
273
+ do {
274
+ permutations.push_back(num);
275
+ } while (next_permutation(num.begin(), num.end()));
276
+
277
+ return permutations;
278
+ }
279
+
280
+ template<typename BidiIt>
281
+ bool next_permutation(BidiIt first, BidiIt last) {
282
+ // Get a reversed range to simplify reversed traversal.
283
+ const auto rfirst = reverse_iterator<BidiIt>(last);
284
+ const auto rlast = reverse_iterator<BidiIt>(first);
285
+
286
+ // Begin from the second last element to the first element.
287
+ auto pivot = next(rfirst);
288
+
289
+ // Find `pivot`, which is the first element that is no less than its
290
+ // successor. `Prev` is used since `pivort` is a `reversed_iterator`.
291
+ while (pivot != rlast and !(*pivot < *prev(pivot)))
292
+ ++pivot;
293
+
294
+ // No such elemenet found, current sequence is already the largest
295
+ // permutation, then rearrange to the first permutation and return false.
296
+ if (pivot == rlast) {
297
+ reverse(rfirst, rlast);
298
+ return false;
299
+ }
300
+
301
+ // Scan from right to left, find the first element that is greater than
302
+ // `pivot`.
303
+ auto pos = find_if(rfirst, pivot, bind1st(less<int>(), *pivot));
304
+
305
+ swap(*pos, *pivot);
306
+ reverse(rfirst, pivot);
307
+
308
+ return true;
309
+ }
310
+ };
311
+ \end {Code }
312
+
313
+
314
+ \subsection {深搜 }
315
+ 本题是求路径本身,求所有解,函数参数需要标记当前走到了哪步,还需要中间结果的引用,最终结果的引用。
316
+
317
+ 扩展节点,每次从左到右,选一个没有出现过的元素。
318
+
319
+ 本题不需要判重,因为状态装换图是一颗有层次的树。收敛条件是当前走到了最后一个元素。
320
+
321
+ \subsubsection {代码 }
322
+ \begin {Code }
323
+ // LeetCode, Permutations
324
+ // 深搜
325
+ class Solution {
326
+ public:
327
+ vector<vector<int> > permute(vector<int>& num) {
328
+ std::sort(num.begin(), num.end());
329
+
330
+ vector<vector<int>> result;
331
+ vector<int> p(num.size(), 0); // 中间结果
332
+
333
+ permute(num.begin(), num.end(), 0, p, result);
334
+ return result;
335
+ }
336
+ private:
337
+ typedef vector<int>::const_iterator Iter;
338
+ void permute(Iter first, Iter last, int cur, vector<int> &p,
339
+ vector<vector<int> > &result) {
340
+ if ((first + cur) == last) { // 收敛条件
341
+ result.push_back(p);
342
+ }
343
+
344
+ // 扩展状态
345
+ for (auto i = first; i != last; i++) {
346
+ bool used = false;
347
+ // 查找 *i 是否在p[0, cur) 中出现过
348
+ for (auto j = p.begin(); j != p.begin() + cur; j++) {
349
+ if (*i == *j) {
350
+ used = true;
351
+ break;
352
+ }
353
+ }
354
+ if (!used) {
355
+ p[cur] = *i;
356
+ permute(first, last, cur + 1, p, result);
357
+ // 不需要恢复P[cur],返回上层cur会自动减1,P[cur]会被覆盖
358
+ }
359
+ }
360
+ }
361
+ };
362
+ \end {Code }
363
+
364
+
365
+ \subsubsection {相关题目 }
366
+ \begindot
367
+ \item Permutations II ,见 \S \ref {sec:permutations-ii }
368
+ \myenddot
369
+
370
+
371
+ \section {Permutations II } % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372
+ \label {sec:permutations-ii }
373
+
374
+
375
+ \subsection {next_permutation() }
376
+ 上一题中的代码,见\S \ref {sec:next-permutation } 节,也适用于本题。
377
+
378
+
379
+ \subsection {重新实现next_permutation() }
380
+ 上一题中的代码,见\S \ref {sec:next-permutation-implement } 节,也适用于本题。
381
+
382
+
383
+ \subsection {深搜 }
384
+ 递归函数\fn {permute()}的参数\fn {p},是中间结果,它的长度又能标记当前走到了哪一步,用于判断收敛条件。
385
+
386
+ 扩展节点,每次从小到大,选一个没有被用光的元素,直到所有元素被用光。
387
+
388
+ 本题不需要判重,因为状态装换图是一颗有层次的树。
389
+
390
+
391
+ \subsubsection {代码 }
392
+ \begin {Code }
393
+ // LeetCode, Permutations II
394
+ // 深搜
395
+ class Solution {
396
+ public:
397
+ vector<vector<int> > permuteUnique(vector<int>& num) {
398
+ std::sort(num.begin(), num.end());
399
+
400
+ unordered_map<int, int> count_map; // 记录每个元素的出现次数
401
+ std::for_each(num.begin(), num.end(), [&count_map](int e) {
402
+ if (count_map.find(e) != count_map.end())
403
+ count_map[e]++;
404
+ else
405
+ count_map[e] = 1;
406
+ });
407
+
408
+ // 将map里的pair拷贝到一个vector里
409
+ std::vector<pair<int, int> > elems;
410
+ std::for_each(count_map.begin(), count_map.end(),
411
+ [&elems](const pair<int, int> &e) {
412
+ elems.push_back(e);
413
+ });
414
+
415
+ vector<vector<int>> result; // 最终结果
416
+ vector<int> p; // 中间结果
417
+
418
+ permute(num.size(), elems.begin(), elems.end(), 0, p, result);
419
+ return result;
420
+ }
421
+
422
+ private:
423
+ typedef std::vector<pair<int, int> >::const_iterator Iter;
424
+
425
+ void permute(const size_t n, Iter first, Iter last,
426
+ vector<int> &p, vector<vector<int> > &result) {
427
+ if (n == p.size()) { // 收敛条件
428
+ result.push_back(p);
429
+ }
430
+
431
+ // 扩展状态
432
+ for (auto i = first; i != last; i++) {
433
+ int count = 0; // 统计 *i 在p中出现过多少次
434
+ for (auto j = p.begin(); j != p.end(); j++) {
435
+ if (i->first == *j) {
436
+ count ++;
437
+ }
438
+ }
439
+ if (count < i->second) {
440
+ p.push_back(i->first);
441
+ permute(n, first, last, p, result);
442
+ p.pop_back(); // 撤销动作,返回上一层
443
+ }
444
+ }
445
+ }
446
+ };
447
+ \end {Code }
448
+
449
+
450
+ \subsubsection {相关题目 }
451
+ \begindot
452
+ \item Permutations ,见 \S \ref {sec:permutations }
453
+ \myenddot
0 commit comments