题目链接
视频解析
这是一个字典序全排列问题,题眼就是求大于当前序列的最小序列,也就是当前序列的下一个序列是什么
1. 第一种思路
思路
使用c++模板库中的next_permutation();函数直接水过
next_permutation();的作用→输入一个序列,可以求出输入序列的下一个序列
用法→next_permutation(p, p + n);
AC代码
#include <limits.h> //INT_MIN需要的头文件
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
//next_permutation();
//输入一个序列,可以求出输入序列的下一个序列
const int N = 10010;
int n, m;
int p[N];
int main()
{
cin >> n;//输入一个正整数n,表示火星人手指的数目
cin >> m;//输入一个正整数m,表示要加上的小数
//1到N这N个整数的一个排列,用空格隔开,表示火星人手指的排列顺序
for(int i = 0; i < n; i ++) cin >> p[i];
//用next_permutation函数让字典序+1.注意用法是+n(排列的位数)
while(m --) next_permutation(p, p + n);
for(int i = 0; i < n - 1; i++) cout << p[i] << ' ';
cout << p[n - 1] << endl;
return 0;
}
核心代码:
//用next_permutation函数让字典序+1.注意用法,n为序列的长度
while(m --) next_permutation(p, p + n);
2. 第二种思路
康拓展开,但是大佬说用在这个题有点儿“杀鸡用牛刀”
3. 第三种思路
思路
自己实现next_permutation函数
题目条件:输入数据保证这个结果不会超出火星人手指能表示的范围。
表示:输入的n一定不会是n!或者大于n!的数字哦
求大于当前序列的最小序列的方法
一些思路:
- 求的是比当前序列大的最小的那个序列!~不需要考虑边界,题目已经考虑到了
- 改右不改左,改小不改大:如果可以改变右边权值更小的数,就不要先改左边权值更大的数
思路图如下:
实现步骤即为以上的①-④
整理为:
注:由于k+1-n是单减的,所以找大于p[k]的最小数可以转换为从后往前遍历找第一个大于p[k]的数即可!
AC代码
#include <limits.h> //INT_MIN需要的头文件
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
//next_permutation();
//输入一个序列,可以求出输入序列的下一个序列
const int N = 10010;
int n, m, k, mid;
int p[N];
void nextper(int *p, int n){//自己实现next_permutation函数
for(k = n - 2; k >= 0; k --){
if(p[k] < p[k + 1]){//从后往前找到非递减的第一个数p[k]
for(int i = n - 1; i > k; i --)
if(p[i] > p[k]){//在k+1到n找到大于p[k]的最小数
mid = p[i]; p[i] = p[k]; p[k] = mid;
break;
}
break;
}
}
//p[k+1]-p[n-1]翻转(n从0开始,n-1结束)
int j = n - 1;
for(int i = k + 1; i < n; i++){
if(i >= j) break;
mid = p[i];
p[i] = p[j];
p[j] = mid;
j--;
}
}
int main()
{
cin >> n;//输入一个正整数n,表示火星人手指的数目
cin >> m;//输入一个正整数m,表示要加上的小数
//1到N这N个整数的一个排列,用空格隔开,表示火星人手指的排列顺序
for(int i = 0; i < n; i ++) cin >> p[i];
//用next_permutation函数让字典序+1.注意用法是+n(排列的位数)
//while(m --) next_permutation(p, p + n);
while(m --){
nextper(p, n);
}
for(int i = 0; i < n - 1; i++) cout << p[i] << ' ';
cout << p[n - 1] << endl;
return 0;
}
//按照大佬的思路自己敲的,对了hhh
改进
后来发现那个序列反转用reverse可以直接实现
reverse(p + k + 1, p + n);//p[k+1]-p[n-1]翻转,注意这里写n而不是n-1
大佬的代码:
小白一个,如有错误欢迎指正~~!