PTA 输出全排列

题目描述

请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。

输入格式

输入给出正整数n(<10)。

输出格式

输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a​1​​,a​2​​,⋯,a​n​​排在序列b​1​​,b​2​​,⋯,b​n​​之前,如果存在k使得a​1​​=b​1​​,⋯,a​k​​=b​k​​ 并且 a​k+1​​<b​k+1​​。

输入样例

3

输出样例

123

132

213

231

312

321

我们尝试用递归的思想解决:先输出所有以1开头的排列(这一步是递归调用),然后输出以2开头的排列(又是递归调用),接着是以3开头的排列……最后才是以n开头的排列。
以1开头的排列的特点是:第一位是1,后面是2~9的排列。根据字典序的定义,这些2~9的排列也必须按照字典序排列。换句话说,需要“按照字典序输出2~9的排列”,不过需注意的是,在输出时,每个排列的最前面要加上“1”。这样一来,所设计的递归函数需要以下参数:

  1. 已经确定的“前缀”序列,以便输出。
  2. 需要进行全排列的元素集合,以便依次选做第一个元素。
void print_permutation(序列A, 集合S)
{
    if(S为空) 输出序列A;
    else 按照从小到大的顺序依次考虑S的每个元素v
    {
        print_permutation(在A的末尾填加v后得到的新序列, S-{v});
    }
}

暂时不用考虑序列A和集合S如何表示,首先理解一下上面的伪代码。递归边界是S为空的情形,这很好理解:现在序列A就是一个完整的排列,直接输出即可。接下来按照从小到大的顺序考虑S中的每个元素,每次递归调用以A开头。下面考虑程序实现。不难想到用数组表示序列A,而集合S根本不用保存,因为它可以由序列A完全确定——A中没有出现的元素都可以选。C语言中的函数在接受数组参数时无法得知数组的元素个数,所以需要传一个已经填好的位置个数,或者当前需要确定的元素位置cur,代码如下://不要关心那么多头文件啥意思,我用的基本上都是c风格的(对我们新生说的)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#include<list>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
void print_permutation(int n, int* A, int cur) {
	if(cur == n) { //递归边界
		for(int i = 0; i < n; i++) printf("%d", A[i]);
		printf("\n");
	}
	else for(int i = 1; i <= n; i++) { //尝试在A[cur]中填各种整数i
		int ok = 1;
		for(int j = 0; j < cur; j++)
		    if(A[j] == i) ok = 0; //如果i已经在A[0]~A[cur-1]出现过,则不能再选
		if(ok) {
			A[cur] = i;
			print_permutation(n, A, cur+1); //递归调用
		}
	}
}
int main()
{
	int n,a[20];
	scanf("%d",&n);
	memset(a,0,sizeof(a));
	print_permutation(n,a,0);
    return 0;
}

当然如果你会c++的话可以用c++的库函数next_permutation。但对于初学者我建议最好理解上面的,不要一开始就对库函数有依赖,对于我们新生我希望你们可以先打好c的基础,觉得自己还不错了,可以尝试的开始学习c++,但值得一说的是,学习不要图快,学好才是关键,基础要劳,这次小测试的题目我没有出好,太过简单了,我的错。这些都是题外话,关于库函数的使用,看下面代码,相信你就会了。

#include<cstdio>
#include<algorithm> //包含next_permutation
using namespace std;
int main( ) {
    int n, p[10];
    scanf("%d", &n);
    for(int i = 0; i < n; i++) scanf("%d", &p[i]);
    sort(p, p+n); //排序,得到p的最小排列
    do {
        for(int i = 0; i < n; i++) printf("%d ", p[i]); //输出排列p
        printf("\n");
    } while(next_permutation(p, p+n)); //求下一个排列
    return 0;
}

 

全部评论

相关推荐

感觉这一周太梦幻了,就像一个梦,很不真实~~~感觉这个暑期,我的运气占了99成,实力只有百分之一4.15上午&nbsp;腾讯csig&nbsp;腾讯云部门,面完秒进入复试状态4.16下午&nbsp;美团优选供应链部门,4.18上午发二面4.17晚上&nbsp;阿里国际一面,纯拷打,面完我都玉玉了4.18下午&nbsp;阿里国际二面,是我们leader面的我,很轻松~~4.18晚上&nbsp;约了hr面4.19上午&nbsp;hr面,下午两点口头oc4.19晚上&nbsp;意向书说起来我的暑期好像一次都没挂过~~~~~难道我是天生面试圣体?----------------------------------------------------------------------六个月前,我还是0项目0刷题,当时想的是先把论文发出来再去找实习。结果一次组会,老师打破了我的幻想(不让投B会,只让投刊或者A)我拿头投啊!!!然后就开始物色着找实习,顺便做完了mit的6.s081,但是基本上还是没刷过题目-----------------------------------------------------------------------11月&nbsp;&nbsp;一次偶然的机会,面进了某个耳机厂的手环部门,大概是做嵌入式的,用的是CPP。12月&nbsp;莫名其妙拿到了国创的面试机会,0基础四天速成java基础!居然也给我面过了hhhhh,可能是面试没写题吧入职国创后的几个月,一直没活,天天搁那看剧,都快忘了还有暑期实习这回事了~~~~命运的齿轮在2.26开始转动,因为这一天美团开了,我开始慌了,因为那时的我什么都不会。lc,八股,sql全部是0进度。然后就开始了女娲补天,上班刷题,下班继续做之前的开源,顺便学一学八股。3月到现在,lc也刷到快200了,一天最多提交了47次~~~~~~~~~~八股根据别人的面经总结和博客,写了快十万字的笔记~~~~~~~~~~简历上的实习经历和开源,也努力去深挖了,写了几万字的记录~~~~~~所以面试的时候,基本上都能cover了,面试官问到的基础基本都会,不基础的我就把他往我会的地方引。结果好像还不错,基本上每个面试官评价都挺好的emmmmmmmm
投递阿里巴巴等公司10个岗位
点赞 评论 收藏
转发
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务