上圖爲 8 皇后問題的一種解法。java
給定一個整數 n,返回 n 皇后不一樣的解。算法
示例:
輸入: 4
解釋: 4 皇后問題存在以下兩個不一樣的解法。
[
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],數組
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]函數
n皇后問題有兩種解的要求,一種僅要求輸出解決方案個數,一種要求輸出全部的具體解決方案。this
暴力破解不可行,時間複雜度爲O(n^n)。
回溯法,其中在進行深搜時,剪枝的關鍵在於:code
每一行放置時,相比於上一行能放置棋子的空位就會少1,時間複雜度O(n!),空間複雜度O(n)。blog
class Solution { public int dfs_backtrace(int row, int count, int n, int[] z, int[] x, int[] y) { //每一層遞歸攜帶了row參數,因此每一個dfs_backtrace函數表明row行在嘗試放置棋子 //所以只需一層for循環遍歷row行的每一列 for(int col = 0; col < n; col++){ //若是各個方向都沒有標記,說明此處能夠放置棋子 if(z[col] + x[n + row - col] + y[row + col] == 0) { //標記 z[col] = 1; x[n + row - col] = 1; y[row + col] = 1; //dfs if(row + 1 == n) { count++; } else { count = dfs_backtrace(row+1, count, n, z, x, y); } //回溯 z[col] = 0; x[n + row -col] = 0; y[row + col] = 0; } } return count; } public int totalNQueens(int n) { int[] z = new int[n]; // z[i]表示第i列是否有棋子 int[] x = new int[2*n]; // x[n + row - col]表示(row,col)點所在主對角線(\)是否有棋子 int[] y = new int[2*n]; // y[row + col]表示(row,col)點所在副對角線(/)是否有棋子 return dfs_backtrace(0, 0, n, z, x, y); } }
僅須要添加一個queue[n]數組,queue[i] = j, 表示爲第i行的皇后放置在第j列;
將queue在放棋子與撤銷棋子時同步更新便可,引入queue數組是爲了記錄皇后位置,用於輸出解決方案。
如下代碼與上個代碼思路徹底一致,僅將一些過程寫成了函數。遞歸
class Solution { int n; int[] x; int[] y; int[] z; int[] queue; List<List<String>> output = new ArrayList<List<String>>(); private boolean is_not_attack(int row, int col) { return x[n+row-col]+y[row+col]+z[col] == 0; } private void placeQueue(int row, int col) { x[n + row - col] = 1; y[row + col] = 1; z[col] = 1; queue[row] = col; } private void removeQueue(int row, int col) { x[n + row - col] = 0; y[row + col] = 0; z[col] = 0; queue[row] = 0; } private void addOutput() { List<String> list = new ArrayList<String>(); for(int i = 0; i < n; i++) { char[] str = new char[n]; Arrays.fill(str, '.'); str[queue[i]] = 'Q'; list.add(new String(str)); } output.add(list); } private void traceback(int row) { for(int col = 0; col < n; col++) { if(is_not_attack(row, col)) { //放置棋子 placeQueue(row, col); //DFS if(row + 1 == n) { addOutput(); } else { traceback(row + 1); } //回溯棋子 removeQueue(row, col); } } } public List<List<String>> solveNQueens(int n) { this.n = n; x = new int[2*n]; y = new int[2*n]; z = new int[n]; queue = new int[n]; traceback(0); return output; } }
方陣主副對角線行列值的特殊關係。leetcode
遞歸:算法結構,函數調用自身。
回溯:算法思想,會「剪枝」的窮舉。
DFS:回溯搜索是深度優先搜索的一種,回溯法在搜索過程當中不保留完整樹結構,DFS搜索樹結構完整。
rem
連接:https://leetcode-cn.com/problems/n-queens
連接:https://leetcode-cn.com/problems/n-queens-ii