欢迎光临散文网 会员登陆 & 注册

输出1-n的全排列(按字典序)

2022-10-19 13:43 作者:-王-小-明-  | 我要投稿

先上题

一道题

再上代码

这个问题的棘手之处就在于n是不确定的。

如果n确定,为了按照字典序输出,我们可以通过循环的嵌套以及几个条件判断直接输出,比如这样:

但n是不确定的,我们并不知道要套几层循环,这就需要递归的使用。

递归的核心有三点:起始点、递推关系和边界条件。

在这个问题里,起始点可以从第一位开始。

而递推关系体现为:我们如果有了这n个数选取x个数后在前x位上所有的排列,我们可以在它的基础上给出这n个数在前x%2B1位上所有选取后的排列。

对于每一种已知的排列,我们只需要从1n遍历一遍,分别找到所有在这一个排列中没有出现过的数字,放在第x%2B1位上,便可以得到需要的结果。

而边界条件就是x%3En,也即当我们把前n位都填充完之后,我们已经得到了一种排列,只需要输出即可。

到这里这个递归的思路已经了然了,剩下的是一个小的优化,也就是sgn数组的加入。

在我们从1n遍历的时候,需要与前面的数比对以确定是否重复,这是一笔不小的开销。为了减少这个开销,我们选择开一个sgn数组,用于标志该数是否已在前x位中被选取。

当我们在第x位上放置一个数i时,我们将sgn%5Bi%5D置为1,表示该数已被选取,而当后面的函数,即arrange(x%2B1)调用结束时,我们将sgn%5Bi%5D置为0,因为无论之后是还在该层继续循环,还是跳出循环,该位都不再选取i

把两个代码作比较可能会好理解一些:

code2中的for循环就对应code1中的for循环,只不过code2中循环的嵌套是直接写出来的,code1中的循环嵌套则通过递归实现。code2中取不同变量名是为了区分,而code1中不同层的循环在不同的函数中,不需要在名字上做区分。

code2中的条件判断就对应code1中对sgn%5Bi%5D的判断以及反复的置01

code2中最后一次循环正常结束便可输出一个结果,而code1中则是到第x%3Dn%2B1时,递归到最底层,输出结果。不同点则在于code2的循环中完整保留了各位的信息,而code1需要一个数组来存放这些信息。


以上。

递归还是要多写,刚接触的时候确实会比较懵,但把三个核心点写好,递归还是可以以简单的思路实现的。

输出1-n的全排列(按字典序)的评论 (共 条)

分享到微博请遵守国家法律