原題如下:用1、2、2、3、4、5這六個數字,用java寫一個程序,打印出所有不同的排列,如:512234、412345等,要求:"4"不能在第三位,"3"與"5"不能相連。
解題思路:
很明顯,這是一個遞歸算法。我們可以排列將這6個數按從小到大的順序排一下,如果是1,2,3,4,5,6,那么會有1*2*3*4*5*6= 6!=720個遞增的數。但如果是1,2,2,3,4,5,那么在這720個數中一定會有相同的數對出現(由于在這6個數中只有兩個數兩同,也就是說,如果有重復的數,那么一定是一對數,如122345會出現兩次)。
排列的基本規則是分步進行。也就是說,要排列上面6個數,首先應該選擇第一個數,這第一個數可以選擇這6個數中的任意一個,如選擇1.第二步是選擇第二個數,這第二個數不能再選擇已經選過的數,如1.因此,它只能從后面5個數中選擇。如選擇2。以此類推。
我們也可以在程序中模擬這一過程。源程序如下:
public class test1
{
private int[] numbers = new int[]
{ 1, 2, 3, 3, 4, 5 };
public int n;
private String lastResult = "";
private boolean validate(String s)
{
if (s.compareTo(lastResult) <= 0)
return false;
if (s.charAt(2) == '4')
return false;
if (s.indexOf("35") >= 0 || s.indexOf("53") >= 0)
return false;
return true;
}
public void list(String index, String result)
{
for (int i = 0; i < numbers.length; i++)
{
if (index.indexOf(i + 48) < 0)
{
String s = result + String.valueOf(numbers[i]);
if (s.length() == numbers.length)
{
if (validate(s))
{
System.out.println(s);
lastResult = s;
n++;
}
break;
}
list(index + String.valueOf(i), s);
}
}
}
public static void main(String[] args)
{
test1 t = new test1();
t.list("", "");
System.out.println("總數:" + t.n);
}
}
其中list函數是這個算法的核心函數。index參數表示已經選擇過的數,用numbers數組的索引表示。如index="012",表示numbers的前三個數已經被選擇,也表示應該選擇第四個數了,而這第四個數應該從后三個數中選擇。result參數表示臨時的數字組合(這個數字組合最多是5個數字,因為,如果到了6個數字,就表示已經有一個結果產生了)。在默認情況下index和result的值都是""。
在validate中使用了 if (s.compareTo(lastResult) <= 0)進行判斷,由于按這種方法進行排列,如果這6個數是遞增給出的,那么排列的結果一定是遞增的,但上述的6個數其中第2和第3個位置上都是2,因此,如果出現了上一個結果不小于當前結果的情況,一定是有重復了,因此,要將這部分數過濾出去。
index保存了當前數字串的索引,index.indexOf(i + 48) < 0就是判斷當前的數字的索引是否在index中(由于給定的數字串有重復的數字,因此,只能使用索引來判斷了),如果不在,就會認為這個數字還沒有加到index中,如果存在了,說明這個數已經在數字串中了。當i=0的時候,i+48是0的ASCII,因為你index中存的畢竟是索引,是位置嘛,所以是從0開始的