遞歸:全排列問題

全排列問題

給出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,但是由於剛纔我們在第三位用到了3hashTable[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);
	}
}


參考:胡凡《算法筆記》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章