排列问题
类型一:固定序列,1,2,3,...,n全排列
/*
*
* 从1...n之中进行全排列,传入n,默认数据:[1,2,...,n]
*
* */
public class allArrange {
//数组的个数
private int n;
//数组中每个数是否被访问过的标记
private int []x;
//结果数组
private int []result;
//记录全排列种数。
private int sum;
public allArrange(int n){
this.n=n;
sum=0;
x=new int [n];
result=new int [n];
for(int i=0;i<n;i++)
x[i]=0;
backtrack(0);
System.out.println("总共有 "+sum+" 种全排列方式");
}
private void backtrack(int t){
//递归出口:到第n层,打印结果。
if(t>n-1) { print();return;}
else{
//采用循环递归的方式 (回溯法)
for(int i=0;i<n;i++){
//没有被访问过,标记,记录该数,进入下一层
if(bound(i)){
x[i]=1;
result[t]=i+1;
backtrack(t+1);
x[i]=0;
}
}
}
}
//被访问过,则返回false
private boolean bound(int t){
if(x[t]==1)return false;
return true;
}
//打印输出
public void print(){
sum++;
for(int i=0;i<n;i++)
System.out.print(result[i]+" ");
System.out.print("\n");
}
}
类型二: 含重复数的全排列
public class generalAllArrange {
private int n;
private int []x;
private int []result;
private int sum;
public generalAllArrange(int []a){
this.n=a.length;
x=a;
result=new int[n];
/*显示更直观一点,利用快排排个序*/
//sort(0,n-1);
backtrack(0);
System.out.println("总共有 "+sum+" 种全排列方式");
}
void swap(int [] arr,int m,int n){
int temp=arr[m];
arr[m]=arr[n];
arr[n]=temp;
}
/*
* 快排函数
* */
private void sort(int l,int r) {
// TODO Auto-generated method stub
if(l<r){
int q=position(l,r);
sort(l,q-1);
sort(q+1,r);
}
}
private int position(int l,int r){
int i=l,j=r+1;
int a=x[l];
while(true){
while(x[++i]<a&&i<r);
while(x[--j]>a);
if(i>=j)break;
swap(x,i,j);
}
x[l]=x[j];
x[j]=a;
return j;
}
/*
* 回溯
* */
private void backtrack(int t){
if(t>n-1) { print();return;}
else{
for(int i=t;i<n;i++){
if(bound(i)){
swap(x,i,t);
backtrack(t+1);
swap(x,i,t);
}
}
}
}
//当后面的数和该层的数相同,则不需要交换
private boolean bound(int t){
for(int i=t+1;i<n;i++)
if(x[t]==x[i])return false;
return true;
}
public void print(){
sum++;
for(int i=0;i<n;i++)
System.out.print(x[i]+" ");
System.out.print("\n");
}
}
组合问题
类型一:
固定序列,1,2,3,...,n的K组合
/*
* 已知非负整数n,k,列出集合S属于{1,2,...,n}的所有k组合
* */
public class kArrange {
//数组个数
private int n;
//选取个数
private int k;
//数组中每个数是否被访问过的标记
private int []x;
//结果数组
private int []result;
//记录K组合种数。
private int sum;
public kArrange(int n,int k){
this.n=n;
this.k=k;
sum=0;
x=new int [n];
result=new int [k];
for(int i=0;i<n;i++)
x[i]=0;
backtrack(0);
System.out.println("总共有 "+sum+" 种K组合方式");
}
private void backtrack(int t){
if(t>k-1) { print();return;}
else{
for(int i=t;i<n;i++){
if(bound(i)&&constraint(t,i)){
x[i]=1;
result[t]=i+1;
backtrack(t+1);
x[i]=0;
}
}
}
}
//被访问过,则返回false
private boolean bound(int t){
if(x[t]==1)return false;
return true;
}
//从大到小的顺序, 去重。
private boolean constraint(int t,int i) {
if(t>0&&(result[t-1]>i+1)) return false;
return true;
}
public void print(){
sum++;
for(int i=0;i<k;i++)
System.out.print(result[i]+" ");
System.out.print("\n");
}
}
类型二:含重复数的K组合问题
(不会,以后再来写。)
java完整链接:链接:https://pan.baidu.com/s/1o8IFJHg 密码:7md7