全排列問題
給出1~n
,n個整數,把這n個整數按照這種順序輸出n個數的所有排列:
- 按照字典序從小到大順序輸出,如果說
(a1,a2,……an)
的字典序小於(b1,b2,……bn)
,指的是存在一個i
,使得a1=b1,a2=b2,……a(i-1)=b(i-1),ai<bi
- 例如:
1,2,3
三個數按順序輸出全排列就是(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)、(3,2,1)
解析
以輸入的是1,2,3
爲例,這個問題可以分解成這樣的幾個小問題:
拿出其中一個問題,以1
開頭的三位全排列內部可以分成三個小問題,這三個小問題其實就是在1
爲開頭的基礎上,判斷第二位後面的各個位
因爲1
已經在第一位出現過了,所以就不會出現在第二位,那麼第二位只有兩小小個問題
如此遞推下去,這就是這道題的解決思想
那麼我們可以設置一個boolean
類型的HashTable
,用來記錄到目前爲止,前幾位哪些數字已經使用了,已經使用的記爲true
設置一個index
,指示當前是第幾位
假設我們在第一位爲2
,第二位爲1
的基礎上到了第三位,第三位只能是三3
,到了這一步,這一種情況已經走到底了,hashTable
都爲true
,
之後返回到第二位,第一位的2
我們不能動,第二位還可以是3
,但是由於剛纔我們在第三位用到了3
,hashTable[3]
已經是true
了,第二位無法變成3
,這就說明,我們在返回到上這一位之後,要把子問題中變成true
的變回false
代碼實現
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main{
// 參與全排列的數字爲1~n,同時也是位數
static int n;
// hashTable表示 數字i 在前幾位中是否已經用過了
// 0位空着不用,這樣更方便理解
static boolean[] hashTable = new boolean[n+1];
// 存放當前排列的結果,從i=1開始,0位空着不用,這樣更方便理解
static int[] P = new int[n+1];
// index表示當前處理的是哪一位
public static void generateP(int index) {
// 如果當前位數是第n位(index是從1開始的),說明已經排完了
if(index == n+1) {
// 輸出整個排列
for(int i=1; i<n; i++) {
System.out.print(P[i]);
}
System.out.println();
}
// 對於1~n的每一個數,都嘗試放在第index位(當前位)上
for(int i=1; i<=n; i++) {
if(hashTable[i] == false) { // 數字i在前幾位中沒有出現過
//i設爲全排列的第index位
P[index] = i;
// 把i標記成已經用過了
hashTable[i] = true;
// 處理子問題(下一位往後
generateP(index + 1);
// 處理完子問題,把i標記還原,以保證當前位位可以使用
hashTable[i] = false;
}
}
}
public static void main(String[] args) throws IOException{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
// 參與全排列的數字爲1~n,同時也是位數
n = Integer.parseInt(bf.readLine());
// 從第一位開始
generateP(1);
}
}
參考:胡凡《算法筆記》