1. 程式人生 > >leetCode 51.N-Queens (n皇後問題) 解題思路和方法

leetCode 51.N-Queens (n皇後問題) 解題思路和方法

dex 數據 我想 attack upload sar alt row queen

N-Queens

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
技術分享

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens‘ placement, where ‘Q‘ and ‘.‘ both indicate a queen and an empty space respectively.

For example,
There exist two distinct solutions to the 4-queens puzzle:

[
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],

["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]

]


思路:本題大的方法上我想到了兩個思路,第一個是將n皇後問題轉化為全排列問題。

設x[n]為一組解。代表第i行第x[i]列放置了皇後。

所以求出全排列,然後推斷是否合法就可以。

代碼例如以下(沒有Ac,進一步優化之後應該是能夠Ac的):

public class Solution {
        public List<List<String>> solveNQueens(int n) {
    	List<List<String>> returnList = new ArrayList<List<String>>();
    	/**
    	 * x[i]為第i列存放的位置
    	 * 轉化為0-(n-1)的全排列,然後推斷全排列的位置是否合法就可以
    	 */
        int[] num = new int[n];
        int i = 0;
        while(i < n){
        	num[i] = i;//填充數組為0-(n-1)
        	i++;
        }
        List<List<Integer>> list = permuteUnique(num);
        for(List<Integer> al : list){//對每一組數據處理
        	for(i = 0; i < al.size(); i++){
        		if(!check(al, i, al.get(i)))
        			break;//不合法跳出
        	}
        	if(i == n){//到最後一位,說明所有合法
        		List<String> ls = new ArrayList<String>();
        		for(i = 0; i < al.size(); i++){
        			String s = "";//每一組的String
        			for(int j = 0; j < n;j++){
        				if(j == al.get(i)){
        					s += "Q";//放置皇後的位置
        				}
        				else{
        					s += ".";//不放的位置
        				}
        			}
        			ls.add(s);//加入到ls
        		}
        		returnList.add(ls);//加入一組解
        	}
        }
        return returnList;
    }
    /**
     * 推斷是否合法
     * @param al 一組解
     * @param i 當前行
     * @param x 當前列
     * @return 是否合法
     */
    boolean check(List<Integer> al,int i,int x){
    	for(int k = 0; k < i; k++){//僅僅與上方比較,不然與會自身比較
    		if(al.get(k) == x || x - i == al.get(k) - k || x + i == al.get(k) + k)
    			return false;
    	}
		return true;
    }
    //求全排列
	public static List<List<Integer>> permuteUnique(int[] num) {
		List<List<Integer>> returnList = new ArrayList<List<Integer>>();
		returnList.add(new ArrayList<Integer>());
	 
		for (int i = 0; i < num.length; i++) {
			Set<List<Integer>> currentSet = new HashSet<List<Integer>>();
			for (List<Integer> l : returnList) {
				for (int j = 0; j < l.size() + 1; j++) {
					l.add(j, num[i]);
					List<Integer> T = new ArrayList<Integer>(l);
					l.remove(j);
					currentSet.add(T);
				}
			}
			returnList = new ArrayList<List<Integer>>(currentSet);
		}
	 
		return returnList;
	}
}


還有一種思路是回溯法,符合要求的往下走。不符合要求的往回退。

詳細代碼:

public class Solution {
    /**
     * 這題的總體思想是建一個x[n]的數組,意為第i放第x[i]列放置皇後
     * 皇後的合法推斷規則是列不相等,斜線上也不相等
     * i + x[i] == j + x[j] 表示正斜線一致
     * x[i] - i = x[j] - j 表示負斜線上一致  都不合法
     */
	List<List<String>> list;//保存結果
	public List<List<String>> solveNQueens(int n) {
		list = new  ArrayList<List<String>>();
		int[] x = new int[n];//保存結果
		queens(x, n, 0);
		return list;
	}
	
	void queens(int[] x,int n,int row){
		for(int i = 0; i < n; i++){
			if(check(x,n,row,i)){//推斷合法
				x[row] = i;//將皇後放在第row行,第i列
				if(row == n-1){//假設是最後一行,則輸出結果
					addList(x,n);
					x[row] = 0;//回溯,尋找下一個結果
					return;
				}
				queens(x, n, row+1);//尋找下一行
				x[row] = 0;//回溯
			}
		}
	}

	/**
	 * 將每一組的結果加入list
	 * @param x 數組解
	 * @param n 棋盤長寬
	 */
	private void addList(int[] x,int n) {
		//加入結果
		String[][] sArr = new String[n][n];
		List<String> al = new ArrayList<String>();
		for(int i = 0; i < n ; i++){
			Arrays.fill(sArr[i], ".");//先填充.
			sArr[i][x[i]] = "Q";//特定位置放置Q
			String s = "";
			for(String str:sArr[i]){
				s += str;//加在一起
			}
			al.add(s);//加入一行
		}
		list.add(al);//加入一組解
	}

	/**
	 * @param x 數組解
	 * @param n 棋盤長寬
	 * @param index 當前放置行
	 * @param i 當前放置列
	 * @return
	 */
	boolean check(int[] x,int n,int row, int col){
		for(int i = 0; i < row; i++){
		    //由於行不相等,推斷列是否相等。斜線上是否相等
			if(x[i] == col || x[i] + i == col + row || x[i] - i == col - row)
				return false;
		}
		return true;
	}
}


leetCode 51.N-Queens (n皇後問題) 解題思路和方法