题目大概是这样的:有七对数,{1,2,3,4,5,6,7},利用这七对数排列成一个14位数,要求是每对数中间相隔的位数是这一对数的值,如34563,一对3中间隔着三个数,其他类似,举一个用例25623745361417就是满足要求的一个排列。现在要求编程实现一个以74开头的一个排列。
思考如下:以74开头的一个排列,就是74****4*7*****,*号是要求的。首先我们不要考虑以74开头来思考算法,寻找一般性再说。7对数,14位数,我们先从这14个数中选一个数作为第一位,接着从剩下的13个数选择一个作为第二位数,以此类推。这就像我们数学中的排列组合问题了 ,总共的排列数为,不考虑重复的情况。其实,每一种就是从n个数中选一个数,都是同样的操作,这就想到用递归来解决这道题了。这里要考虑一个问题,但从中选择一个数m时,我们就要给这个数做标记,表示这个数已经选择过了,下一位数就从剩下的数中选择,同时,还要考虑这次选择了数m,下次我们就选择数n了,这时就要把之前给m做标记还原,表示未选择。我采取的方法是,如果这个数选择了,就把它置为0。
初始代码如下:
public class NumTest {
public static void main(String[] args) {
int[] num={1,1,2,2,3,3,4,4,5,5,6,6,7,7};//选择的数
int[] test=new int[14]; //装载要产生的14位数
run(num,num.length,test,0); //递归函数
}
//length为固定值,为数组的长度,from为test数组的下标
public static void run(int[] num,int length,int[] test,int from){
if(from==test.length){
testNum(test); //检验规则函数
return;
}
for(int i=0;i<length;i++){
<span style="white-space:pre"> </span>if(num[i]!=0 ){
<span style="white-space:pre"> </span>test[from]=num[i];
<span style="white-space:pre"> </span>num[i]=0;
<span style="white-space:pre"> </span>run(num, length, test, from+1);<span style="white-space:pre"> </span>//递归下一位
<span style="white-space:pre"> </span>num[i]=test[from];
}
}
}
public static void testNum(int[] test){
int length=test.length;
int sub=test.length-1;
int[] tempT=new int[14];//tempT数组用来判断这个数是否判断过
for(int i=0;i<length;i++){
if(tempT[i]==-1) //-1表示这对数已判断过
continue;
else{
int temp=test[i];//要间隔多少个数
int pos=temp+i+1; //求出相对应的位置
if(pos>sub) //如果这个数越界,表示此排列不满足要求
return;
if(temp!=test[pos])//相对应的位置不是一对数,不满足要求
return;
tempT[pos]=-1;
}
}
for(int k:test)
System.out.print(k);
System.out.println();
}
}
这段代码不要测试,因为没半个小时是运行不出来的,可能还要更久,你算算总的排列数就知道有多大了。下面我们考虑以74开头的排列,这是代码在原来的基础上修改就简单了。如下:
public class NumTest {
public static void main(String[] args) {
int[] num={1,1,2,2,3,3,5,5,6,6};//选择的数,排除4,7
int[] test=new int[14]; //装载要产生的14位数
test[0]=7;
test[1]=4;
test[6]=4;
test[8]=7;
run(num,num.length,test,0); //递归函数
}
//length为固定值,为数组的长度,from为test数组的下标
public static void run(int[] num,int length,int[] test,int from){
if(from==test.length){
testNum(test); //检验规则函数
return;
}
if(from==0 || from==1 || from==6 || from==8){<span style="white-space:pre"> </span>//如果遇到4,7的位置,直接递归下一位
run(num, length, test, from+1);
}else{
for(int i=0;i<length;i++){
if(num[i]!=0){
test[from]=num[i];
num[i]=0;
run(num, length, test, from+1);<span style="white-space:pre"> </span>//递归下一位
num[i]=test[from];
}
}
}
}
public static void testNum(int[] test){
int length=test.length;
int sub=test.length-1;
int[] tempT=new int[14];//tempT数组用来判断这个数是否判断过
for(int i=0;i<length;i++){
if(tempT[i]==-1) //-1表示这对数已判断过
continue;
else{
int temp=test[i];//要间隔多少个数
int pos=temp+i+1; //求出相对应的位置
if(pos>sub) //如果这个数越界,表示此排列不满足要求
return;
if(temp!=test[pos])//相对应的位置不是一对数,不满足要求
return;
tempT[pos]=-1;
}
}
for(int k:test)
System.out.print(k);
System.out.println();
}
}
这段代码你可以拿来测试了,运行后,你会发现输出了重复的排列数,原因在哪里呢?问题就在这七对数上,因为它是一对数,所以这次你选择了1,下一次还有一次选择了1,这样就导致重复了。解决办法是用一个数来记录这次选择的数,然后判断下一次选择的数是否和上一次相同,若相同则选择下一个数。最终代码如下:
public class NumTest {
public static void main(String[] args) {
int[] num={1,1,2,2,3,3,5,5,6,6};//选择的数
int[] test=new int[14]; //装载要产生的14位数
test[0]=7;
test[1]=4;
test[6]=4;
test[8]=7;
run(num,num.length,test,0); //递归函数
}
//length为固定值,为数组的长度,from为test数组的下标
public static void run(int[] num,int length,int[] test,int from){
if(from==test.length){
testNum(test); //检验规则函数
return;
}
if(from==0 || from==1 || from==6 || from==8){
run(num, length, test, from+1);
}else{
int temp=0;
for(int i=0;i<length;i++){
if(num[i]!=0 && num[i]!=temp){
test[from]=num[i];
num[i]=0;
run(num, length, test, from+1);
num[i]=test[from];
}
temp=num[i];
}
}
}
public static void testNum(int[] test){
int length=test.length;
int sub=test.length-1;
int[] tempT=new int[14];//tempT数组用来判断这个数是否判断过
for(int i=0;i<length;i++){
if(tempT[i]==-1) //-1表示这对数已判断过
continue;
else{
int temp=test[i];//要间隔多少个数
int pos=temp+i+1; //求出相对应的位置
if(pos>sub) //如果这个数越界,表示此排列不满足要求
return;
if(temp!=test[pos])//相对应的位置不是一对数,不满足要求
return;
tempT[pos]=-1;
}
}
for(int k:test)
System.out.print(k);
System.out.println();
}
}
最终结果为74151643752362。
好了,终于写完了,不知道你看懂了没,可能我讲解的不是条理很清晰。如果有问题的,可以在下面留言,我会努力帮你解答。