示例1
求任意不同的n个数的全排列
先假设4个序列的全排列
递归过程其实就是忽略开头元素,去求解一个比自己当前阶数少一阶的序列的全排列,而这个子问题的全排列的解决也是一个同样的过程,这样就完全符合递归思想了。我们只要在每一个进程中,让当前规模下序列的每一个元素做一遍开头,然后进入递归调用即可解决问题
代码如下
public class Main
{
int[] data = {1,2,3,4,5,6,8,9,10,32,15,18,33};/*本例设n为10*/
int num = 0;/*统计全排列的个数*/
void Perm(int begin, int end){
int i;
if(begin == end){/*当开始位置下标和结束位置下标相等时,意味着当前的数组中只有一个元素了,即递归结束,产生一个全排列*/
//如有必要,可在此打印出这个全排列或作其它处理
num++;/*统计全排列的个数*/
}
else for(i = begin; i <= end; i++){
swap(data[begin], data[i]);//移动位置,做出移动操作
Perm(begin+1, end);//进行递归调用,将开头加一,代表不去考虑第一个元素,进一步去考虑剩下的元素。其实就是去解决剩余元素的全排列
swap(data[begin], data[i]);//问题解决完之后,恢复,用于下一次交换
}
}
static void swap(int a, int b) {//交换两个变量值
int t = a;
a = b;
b = t;
}
public static void main(String args[]){
Main m = new Main();
m.Perm(0,9);//求十个数的全排列
System.out.println(m.num);//输出总数num= 3628800
}
}
示例2
求 1~n 的全排列
其基本思想如以下的解答树
即先输出所有以1开头的就排列,然后输出以2开头的排列…最后是n
以1开头的排列的特点是:第一位是1,后面是2-9的排列(n=9)。根据字典序的定义,这些2~9的就排列也必须是字典序的排列。
代码如下
class Solution {//此代码中数组nums的元素是任意且不重复的,不只是解决1~n的排序
List<List<Integer>> list = new ArrayList<>();//用来存储所有的排列情况
public List<List<Integer>> permute(int[] nums) {//nums是需排列的数组
int n = nums.length;
Qpl(n, nums, new ArrayList(), 0);
return this.list;
}
private void Qpl(int n, int[] nums, List A, int cur) {//n是数组的大小,集合A用来存储排列好的序列,cur是当前元素的位置
if (cur == n) {//递归结束条件
list.add(new ArrayList(A));
return;
} else for (int i = 0; i < nums.length; i++) {//尝试在A[cur]中填入各种整数i
int ok = 1;//标志变量,若集合A中包含某个i,则为0,反之为1
for (int j = 0; j < cur; j++) {
if ((int)A.get(j) == nums[i]) ok = 0;//如果i已在A[0]~A[cur-1]出现过,则不选
}
if (ok != 0) {
A.add(nums[i]);
Qpl(n, nums, A, cur + 1);
A.remove(A.size()-1);//递归结束后,恢复
}
}
}
}
示例3
生成可重集的排列
其基本思想大致如示例2
只不过需要统计 A[0]~A[cur-1] 中 P[i] 的出现次数c1,以及P数组中 P[i] 的出现次数c2,只要 c1<c2 ,就可以递归调用
但是,枚举的下标 i 应不重复、不遗漏地取遍所有 P[i] 的值,所以我们可以先对数组P进行排序, 然后检查P的第一个元素和所有“与前一个元素不相同”的元素
代码如下
class Solution2 {
List<List<Integer>> list = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
int n = nums.length;
Arrays.sort(nums);//在此排序以便检查是否重复取P[i]
Qpl(n, nums, new ArrayList(), 0);
return this.list;
}
private void Qpl(int n, int[] nums, List A, int cur) {
if (cur == n) {
list.add(new ArrayList(A));
return;
} else for (int i = 0; i < nums.length; i++)
if(i==0||nums[i]!=nums[i-1]){//保证i不重复,不遗漏地取遍所有P[i]的值,即检查P的第一个元素和所有“与前一个元素不相同”的元素
int c1=0,c2=0;
for (int j = 0; j < cur; j++) {
if ((int)A.get(j) == nums[i]) c1++;//统计A[0]~A[cur-1] 中P[i]的出现次数
}
for(int j=0; j<nums.length; j++){
if(nums[j] == nums[i]) c2++;//统计数组P中P[i]的出现次数
}
if (c1 < c2) {//只要 c1<c2 就可递归调用
A.add(nums[i]);
Qpl(n, nums, A, cur + 1);
A.remove(A.size()-1);
}
}
}
}