问题描述
https://leetcode.com/problems/n-queens/#/description
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-皇后问题
因为国际象棋中,皇后可以在横、竖、斜线上不限步数地吃掉其他棋子,所以N个皇后不能在同一行、同一列以及同一斜线上。
考虑n
个皇后的放法时,我们先按照简单暴力算法的思路来捋一捋题目。
我们首先一个一个位置试探,比如先在(1,1)
,即第一行、第一列上放置第一个皇后,,然后在(1,2)
放置第二个皇后,这时候,就看皇后们是不是在同行、同列或同斜线,皇后不能在同一行,所以第二个皇后放(1,2)
就不行,同时第二个皇后放第一行都不可行,所以我们就可以直接考虑第二行了,根据不能同行这个特点,我们在遍历解法时, 就可以直接排除掉“行”这个因素了。这时候,一个解法就可以实现使用一个数组c[n]
表示,c[i]=j
,表示第i行的皇后放在第j列。
接下来,考虑根据c[n]
如何判断皇后是同列或同斜线的。
同列容易,如果c[i]=c[j]
,就表明两个皇后在同一列,解法不可取;同斜即当i-j
= c[i]-c[j]
时,第i行的皇后和第j行的皇后同斜线,即行之间的差等于列之间的差时,两个皇后同斜线。
考虑好了一个解法怎么出来后,就只需要使用递归回溯就可以得出所有解法了。
代码
public List<List<String>> solveNQueens(int n) {
List<List<String>> res = new ArrayList<>();
solve(res, new int[n], n, 0, new String[n]);
return res;
}
public void solve(List<List<String>> list, int[] c, int n, int index, String[] cur) {
if(index == n) {
list.add(Arrays.asList(cur.clone()));
return;
}
// 从第一列开始遍历
for(int j=0;j<n;j++) {
c[index] = j; // 将第index行的皇后放在第j列
boolean has = false; // 是否有冲突标志位
// 遍历当前已放置好的皇后,看是否有冲突
for(int i=0;i<index;i++) {
if(c[i] == c[index] || Math.abs(i-index)==Math.abs(c[i]-c[index])) {
has = true;
}
}
if(!has) {
char[] row = new char[n];
Arrays.fill(row, '.');
row[j] = 'Q';
cur[index] = new String(row);
// 如果没有冲突,当前解法可行,增加一位皇后
solve(list, c, n, index+1, cur);
}
}
}