题目描述:
题号:51
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
解题思路:
思路一:回溯 + 动态规划
回溯法求解N皇后问题的基本步骤包括:
-
定义解空间:将棋盘看作一个N×N的矩阵,每个位置可以放置一个皇后或者为空。
-
搜索解空间:以深度优先的方式搜索解空间树。在每一行,尝试在当前行的每一列放置皇后,并检查是否满足条件(即不在同一列、同一斜线上有其他皇后)。
-
剪枝:如果在当前位置放置皇后后,无法满足后续行的放置条件,则回溯到上一行,尝试其他列。
-
记录解:当成功放置了N个皇后后,记录当前棋盘布局作为一个解。
时间复杂度:O(N!)
空间复杂度:O(N)
C++
// C++
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> res;
vector<vector<char>> map(n, vector<char>(n, '.'));
backTrack(map, 0, n, res);
return res;
}
void backTrack(vector<vector<char>>& map, int row, int n, vector<vector<string>>& res) {
if (row == n) {
res.push_back(help(map, n));
return;
}
for (int col = 0; col < n; col++) {
if (isValid(map, row, col, n)) {
map[row][col] = 'Q';
backTrack(map, row + 1, n, res);
map[row][col] = '.';
}
}
}
bool isValid(vector<vector<char>>& map, int row, int col, int n) {
// 判断列
for (int i = 0; i < row; i++) {
if (map[i][col] == 'Q') {
return false;
}
}
// 判断右斜
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (map[i][j] == 'Q') {
return false;
}
}
// 判断左斜
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (map[i][j] == 'Q') {
return false;
}
}
return true;
}
vector<string> help(vector<vector<char>>& map, int n) {
vector<string> temp;
for (int i = 0; i < n; i++) {
string build;
for (int j = 0; j < n; j++) {
build += map[i][j];
}
temp.push_back(build);
}
return temp;
}
};
go
// go
func solveNQueens(n int) [][]string {
res := [][]string{}
m := make([][]byte, n)
for i := 0; i < n; i++ {
m[i] = make([]byte, n)
for j := 0; j < n; j++ {
m[i][j] = '.'
}
}
backTrack(m, 0, n, &res)
return res
}
func backTrack(m [][]byte, row, n int, res *[][]string) {
if row == n {
*res = append(*res, help(m, n))
return
}
for col := 0; col < n; col++ {
// 判断能否存放皇后
if isValid(m, row, col, n) {
m[row][col] = 'Q'
backTrack(m, row+1, n, res)
m[row][col] = '.'
}
}
}
func isValid(m [][]byte, row, col, n int) bool {
// 判断列
for i := 0; i < row; i++ {
if m[i][col] == 'Q' {
return false
}
}
// 判断右斜
for i, j := row-1, col-1; i >= 0 && j >= 0; i, j = i-1, j-1 {
if m[i][j] == 'Q' {
return false
}
}
// 判断左斜
for i, j := row-1, col+1; i >= 0 && j < n; i, j = i-1, j+1 {
if m[i][j] == 'Q' {
return false
}
}
return true
}
func help(m [][]byte, n int) []string {
temp := []string{}
for i := 0; i < n; i++ {
temp = append(temp, string(m[i]))
}
return temp
}