一、题目描述
求1~n的全排列。
示例1:
输入:3
输出:
(1,2,3)
(1,3,2)
(2,1,3)
(2,3,1)
(3,1,2)
(3,2,1)
二、解题思路
回溯方法的思想及模板参考回溯系列-算法思想与模板,根据此算法的模板我们就可以解决此题。
对{1,…,n}的全排列个数进行计数是生成这些置换的必要前提.对于置换(a1,a2,…,an)的第一个元素值来说,有n种不同的选项.一旦定下了a1,由于我们除了a1之外其他任意值都可用(全排列中不允许重复),所以对第二个位置来说还剩n-1个候选者.重复这个论证方法可获得所有互不相同的置换,共计n!种.
这种计数论证方案提出了一个合适的表达方式.我们建立一个具有n个单元的数组a作为解向量A.部分解中前i-1个元素对应着置换中的前i-1个元素,而第i个位置的候选者集合将会是没有出现在这i-1个元素中那些值.
在前述一般性回溯算法方案中,可设:Ck为第k个位置候选集合,有:
C k = { 1 , . . . , n } − ⋃ i = 1 k − 1 { a i } C_k = \lbrace 1,...,n \rbrace - \bigcup_{i=1}^{k-1}\lbrace a_i \rbrace Ck={1,...,n}−i=1⋃k−1{ai}
只要k=n时A(k)就是一个解.
三、代码实现
package com.design.backtrack;
/**
* 全排列问题
*
* @author hh
* @date 2021-5-30 19:58
*/
public class FullPermutation {
/**
* 最大候选者数量
*/
private int maxCandidates;
/**
* 回溯主方法
*
* @param a 解向量
* @param k a中当前元素位置k
* @param input 输入数据
*/
public void backtrack(int[] a,int k,int input){
//保存下一位置候选集合
int[] c = new int[input];
//下一位位置候选者数目
int nCandidates;
//计算器
int i;
if(isSolution(a,k,input)){
processSolution(a,k,input);
}else{
k = k + 1;
nCandidates = constructCandidates(a,k,input,c);
for(i = 0; i < nCandidates; i++){
a[k-1] = c[i];
makeMove(a,k,input);
backtrack(a,k,input);
unmakeMove(a,k,input);
}
}
}
/**
* 判断向量a是否是一解
*
* @param a 向量a是否构成一解向量
* @param k a中当前元素位置k
* @param input 输入数据
* @return 布尔变量
*/
private boolean isSolution(int[] a,int k,int input){
return k == input;
}
/**
* 处理解向量a,打印或保存操作
*
* @param a 解向量
* @param k a中当前元素位置k
* @param input 输入数据
*/
private void processSolution(int[] a,int k,int input){
StringBuilder sb = new StringBuilder();
sb.append("(");
for(int i = 0; i < k; i++){
sb.append(a[i]).append(",");
}
sb.deleteCharAt(sb.length()-1);
sb.append(")");
System.out.println(sb);
}
/**
* 根据当前解向量a及输入数据构建候选集合
*
* @param a 解向量
* @param k a中当前元素位置k
* @param input 输入数据
* @param c 输出变量,下一位置候选集合
* @return 候选集数量
*/
private int constructCandidates(int[] a,int k,int input,int[] c){
boolean[] flag = new boolean[input + 1];
int i;
for(i = 0; i < k-1; i++){
flag[a[i]] = true;
}
int j = 0;
for(i = 1; i <= input; i++){
if(!flag[i]){
c[j] = i;
j++;
}
}
return j;
}
/**
* 进行标记或其他处理
*
* @param a 解向量
* @param k a中当前元素位置k
* @param input 输入数据
*/
private void makeMove(int[] a,int k,int input){
}
/**
* 进行清除标记或其他处理
*
* @param a 解向量
* @param k a中当前元素位置k
* @param input 输入数据
*/
private void unmakeMove(int[] a,int k,int input){
}
public static void main(String[] args){
FullPermutation fullPermutation = new FullPermutation();
int input = 3;
int[] a = new int[input];
fullPermutation.backtrack(a,0,input);
}
}