next_permutation必须先排序才能生成全部排列,因为它只按字典序找下一个排列,若初始非最小序(如{2,1,3})会跳过更小排列;正确做法是先sort再do-while循环。

next_permutation 为什么必须先排序才能生成全部排列
next_permutation 不是“从头生成全排列”,而是“按字典序找下一个排列”。它只修改当前序列,返回 true 表示找到了下一个更大的排列,false 表示已到最大排列(即降序),此时重排完成。
如果初始序列不是最小字典序(比如 {2,1,3}),调用一次 next_permutation 会跳过 {1,2,3}、{1,3,2} 等更小的排列,直接从当前状态往后推——结果漏掉大量排列。
所以正确做法是:先用 sort 排成升序(最小字典序),再循环调用 next_permutation。
- 错误写法:
vector→ 只输出 3 个排列(从v = {3,1,2}; do { ... } while (next_permutation(v.begin(), v.end())); {3,1,2}开始往后找),漏掉前两个 - 正确写法:
sort(v.begin(), v.end()); do { ... } while (next_permutation(v.begin(), v.end())); - 注意:
next_permutation修改原容器,别在循环里反复赋值或误判迭代次数
next_permutation 对重复元素的处理逻辑
当数组含重复元素(如 {1,2,2,3})时,next_permutation 仍能工作,但它的“下一个”定义是基于字典序的唯一排列——也就是说,它自动跳过重复排列,不会输出两遍 {1,2,2,3}。
立即学习“C++免费学习笔记(深入)”;
这其实是优势:你不需要额外去重。但前提是输入本身已按规则排序(比如 sort 后的 {1,2,2,3}),否则行为不可控。
- 输入
{2,1,2,3}→ 先sort得{1,2,2,3},再调用next_permutation,共输出 12 种(4!/2! = 12)不重复排列 - 若跳过
sort直接用{2,1,2,3},第一次调用就变成{2,1,3,2},后续序列混乱,且可能漏排或重复 - 底层比较用
operator,所以自定义类型需提供严格弱序(比如struct Point { int x,y; bool operator)
为什么不能用 while(next_permutation(...)) 包裹初始状态
常见错误是这样写:
vectorv = {1,2,3}; while (next_permutation(v.begin(), v.end())) { // 处理 v }
这段代码**漏掉了第一个排列 {1,2,3}** —— 因为 while 条件在进入循环体前就执行了第一次变换。
正确模式是 do-while,确保初始状态也被处理:
sort(v.begin(), v.end());
do {
// 处理当前 v(包括第一次的 {1,2,3})
} while (next_permutation(v.begin(), v.end()));-
do-while至少执行一次,符合“生成全部排列”的语义 - 如果用
for或while,必须手动先处理一次初始状态,容易出错 - 注意:
next_permutation返回false时,v 已被重排为最小排列(升序),但你通常不需要它——循环已退出
性能和边界要注意什么
next_permutation 时间复杂度是 O(n),单次调用很快;但全排列总数是 O(n!),n ≥ 10 就容易超时或爆内存,这不是算法问题,是组合爆炸本质决定的。
- n = 10 → 3628800 次迭代;n = 12 → 超 4.7 亿,基本不可行
- 不要对
string频繁调用(尤其长字符串),因为每次构造新string有拷贝开销;优先用vector或原地操作 - 空容器或单元素容器调用
next_permutation返回false,但do-while仍会执行一次循环体(这是合理的:1 个元素只有 1 种排列) - 迭代器范围必须合法:
v.begin()和v.end()不能是空范围以外的无效区间,否则未定义行为
真正难的从来不是调用 next_permutation,而是想清楚:你要的真是全排列?有没有剪枝可能?能不能换思路(比如 DFS + visited 标记、或数学计数)?










