51. 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.
Example:
Input: 4 Output: [ [".Q..", // Solution 1 "...Q", "Q...", "..Q."], ["..Q.", // Solution 2 "Q...", "...Q", ".Q.."] ] Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.
经典的递归(dfs)问题,要求棋盘上的皇后不能两两在同一行,同一列,或者对角线上,打印出所有的解法
图转自https://blog.csdn.net/you_will_know_me/article/details/78419088
*****判断在不在一条对角线上,即有两棋子坐标分别为(X1,Y1),(X2,Y2),则|X1-X2|!=|Y1-Y2|。
参考之后,整个代码将分为几个部分:
1. 得出一个解,创建一个长度为n的全是" . "的数组,然后填充“Q”。
2. dfs本体:从0到n,一行一行寻找合适的位置放Q,用到isValid函数
3. isValid函数,用来判断当前位置可否正常放Q
public class Solution { public List<List<String>> solveNQueens(int n) { List<List<String>> result = new ArrayList<>(); int[] C = new int[n]; // C[i]表示第i行皇后所在的列编号 dfs(C, 0, result); return result; } private static void dfs(int[] C, int row, List<List<String>> result) { final int N = C.length; if (row == N) { // 终止条件,也是收敛条件,意味着找到了一个可行解 List<String> solution = new ArrayList<>(); for (int i = 0; i < N; ++i) { char[] charArray = new char[N]; Arrays.fill(charArray, '.'); for (int j = 0; j < N; ++j) { if (j == C[i]) charArray[j] = 'Q'; } solution.add(new String(charArray)); } result.add(solution); return; } for (int j = 0; j < N; ++j) { // 扩展状态,一列一列的试 final boolean ok = isValid(C, row, j); if (!ok) continue; // 剪枝,如果非法,继续尝试下一列 // 执行扩展动作 C[row] = j; dfs(C, row + 1, result); // 撤销动作 // C[row] = -1; } } /** * 能否在 (row, col) 位置放一个皇后. * * @param C 棋局 * @param row 当前正在处理的行,前面的行都已经放了皇后了 * @param col 当前列 * @return 能否放一个皇后 */ private static boolean isValid(int[] C, int row, int col) { for (int i = 0; i < row; ++i) { // 在同一列 if (C[i] == col) return false; // 在同一对角线上 if (Math.abs(i - row) == Math.abs(C[i] - col)) return false; } return true; } }
class Solution { public List<List<String>> solveNQueens(int n) { List<List<String>> res = new ArrayList(); int[] q = new int[n]; dfs(res, q, 0, n); return res; } public void dfs(List<List<String>> res, int[] q, int start, int n) { if(start == n) { List<String> cur = new ArrayList(); for(int i = 0; i < n; i++) { char[] ch = new char[n]; Arrays.fill(ch, '.'); ch[q[i]] = 'Q'; cur.add(new String(ch)); } res.add(cur); return; } else { for(int i = 0; i < n; i++) { if(!isValid(start, i, q)) continue; q[start] = i; dfs(res, q, start+1, n); q[start] = 0; } } } public boolean isValid(int ro, int co, int[] q) { for(int i = 0; i < ro; i++) { if(co == q[i] || Math.abs(i - ro) == Math.abs(q[i] - co)) return false; } return true; } }
总结:
This is a typical backtracking question, we want to try every possible solution and get invalid ones.
So like normally we set a variable start means the level we current in. And an array int[ ] q whose length is n, means in i-th level we set queen in q[i] place.
The isValid method is to check if current position is okay to set queen, it basically check from row 0 to row (ro - 1), cuz ro is the row we want to put queen. So we just check if queen is in conflict vertically or diagnonally by check (co == q [ i ] || (i - ro) == (q[i] - co)
When we have a valid answer, create n char array and set relevant queen to it, then convert to string and store in result.