必须先sort再do-while调用next_permutation,且path要传引用;否则会漏排列、栈溢出或性能爆炸。

std::next_permutation 怎么用才不踩坑
直接用标准库比手写递归快得多,也少出错。但它要求输入序列初始时是升序(或至少能生成全排列的合法起始状态),否则会漏掉部分排列。
-
std::next_permutation只生成“字典序下一个”排列,必须从最小字典序开始循环调用 - 如果输入是
{3, 1, 2},第一次调用返回true并改成{3, 2, 1},再调用就返回false—— 它不会自动回退到{1, 2, 3} - 正确做法:先
std::sort(v.begin(), v.end()),再进 do-while 循环
std::vector<int> v = {2, 1, 3};
std::sort(v.begin(), v.end());
do {
// 处理 v
} while (std::next_permutation(v.begin(), v.end()));
手写递归回溯时 vector<int>& path 参数为什么不能省
因为每层递归都在往里加、弹出元素,不传引用就会复制整份路径,时间爆炸,而且最终收集到的全是空或重复内容。
- 传值(
vector<int> path</int>):每次递归都拷贝一次,n! 个排列 × 平均长度 n/2 → O(n! × n) 空间和时间开销 - 传引用(
vector<int>& path</int>)+ 回溯 pop_back(),空间只占 O(n) - 别忘了在递归前
path.push_back(nums[i]),递归后path.pop_back(),否则状态污染
去重:nums 有重复元素时 std::next_permutation 还管用吗
管用,但默认行为是按值去重——它把相等元素视为不同个体,只要位置不同就算不同排列,所以 {1,1,2} 会输出 6 个结果,实际只有 3 个本质不同的排列。
- 想真正去重,得先排序,再用
std::next_permutation,它内部会跳过相同前缀的重复调用 - 或者手写回溯时加判断:
if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue;(需配合used数组) - 注意:这个条件里
!used[i-1]是关键,它保证相同数只允许“从左到右依次选”,避免1a,1b和1b,1a被算两次
递归深度大了栈溢出怎么办
全排列递归深度就是数组长度 n,一般 n > 1000 就危险。不是算法问题,是系统栈限制。
立即学习“C++免费学习笔记(深入)”;
- C++ 默认栈空间小(Linux 通常 8MB,Windows 更小),递归 n=5000 就可能崩
- 改非递归?可以,但
std::next_permutation本身就是迭代实现,天然无栈溢出风险 - 真要手写迭代回溯,得自己用
stack模拟调用栈,维护当前路径、已选索引、下一层候选范围——复杂度陡增,没必要 - 结论:n > 1000 别用递归;n ≤ 20 用递归更直观;中间段优先
std::next_permutation











