来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-queens
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
51.n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
- 对于国际象棋我也是一窍不同,但是n皇后问题就是研究在n*n棋盘如何放置皇后,使得任何两个皇后都不能处于同一条横行、纵行或斜线上。
- 本来看到题目的时候还是比较懵的,因为不知道要以何种形式表示每一种摆法以及要如何去获得每一种摆法。但是看了题解后有点豁然开朗,用一个n*n数组来代表棋盘上每一个格子,然后初始化每个元素都为‘.’,然后定义一个isValid的函数来判断如果皇后落在某个位置是否合法。于是开始进入递归函数,每一层递归相当于在每一行中找到一个合适的位置放置皇后,然后当每一行都放置完皇后之后,我们就找到一个合适的解法了。了解了这个思路之后来看代码就很清晰了。
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
//用于检查在chessboard[row][col]位置放置皇后是否合法
bool isValid(int row, int col, char** chessboard, int n) {
//检查同一列上是否已经有皇后
for (int i = 0; i < row; i++) {
if (chessboard[i][col] == 'Q')
return false;
}
// 由于在每次for循环只会选取一个位置放置皇后Q,所以不用检查同一行上是否已经有皇后
//检查左斜线上是否有皇后
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chessboard[i][j] == 'Q')
return false;
}
//检查右斜线上是否有皇后
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (chessboard[i][j] == 'Q')
return false;
}
return true;
}
// row用来记录棋盘上已经有多少行放置了皇后
void backtracking(int n, char*** res, int* returnSize, char** chessboard, int row) {
if (row == n) { //当row == n 则代表chessboard上已经有一种解法
res[*returnSize] = malloc(sizeof(char*) * n);
for (int i = 0; i < n; i++) {
res[*returnSize][i] = malloc(sizeof(char) * n);
for (int j = 0; j < n; j++) {
res[*returnSize][i][j] = chessboard[i][j];
}
}
(*returnSize)++;
return;
}
for (int col = 0; col < n; col++) {
//验证合法就可以在chessboard[row][col]位置上放置皇后
if (isValid(row, col, chessboard, n)) {
chessboard[row][col] = 'Q';
backtracking(n, res, returnSize, chessboard, row + 1);
chessboard[row][col] = '.'; //回溯,撤销放置皇后
}
}
}
char *** solveNQueens(int n, int* returnSize, int** returnColumnSizes){
*returnSize = 0;
char*** res = malloc(sizeof(char**) * 1000);
//新建一个n*n数组代表棋盘,初始化每个元素为.
char** chessboard = malloc(sizeof(char*) * n);
for (int i = 0; i < n; i++) {
chessboard[i] = malloc(sizeof(char) * n);
for (int j = 0; j < n; j++) {
chessboard[i][j] = '.';
}
}
backtracking(n, res, returnSize, chessboard, 0);
*returnColumnSizes = malloc(sizeof(int) * (*returnSize));
for (int i = 0; i < *returnSize; i++) {
(*returnColumnSizes)[i] = n;
}
return res;
}
- 明明感觉逻辑没有错,但是代码一直过不了,总是报错AddressSanitizer。
- 经过苦苦几个小时的找错,终于发现这个天坑,居然是结果数组中每个字符串没有加结束符’\0’惹的祸!真的是太坑了!
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
//用于检查在chessboard[row][col]位置放置皇后是否合法
bool isValid(int row, int col, char** chessboard, int n) {
//检查同一列上是否已经有皇后
for (int i = 0; i < row; i++) {
if (chessboard[i][col] == 'Q')
return false;
}
// 由于在每次for循环只会选取一个位置放置皇后Q,所以不用检查同一行上是否已经有皇后
//检查左斜线上是否有皇后
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chessboard[i][j] == 'Q')
return false;
}
//检查右斜线上是否有皇后
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (chessboard[i][j] == 'Q')
return false;
}
return true;
}
// row用来记录棋盘上已经有多少行放置了皇后
void backtracking(int n, char*** res, int* returnSize, char** chessboard, int row) {
if (row == n) { //当row == n 则代表chessboard上已经有一种解法
res[*returnSize] = malloc(sizeof(char*) * n);
for (int i = 0; i < n; i++) {
res[*returnSize][i] = malloc(sizeof(char) * (n + 1));
int j = 0;
for (j = 0; j < n; j++) {
res[*returnSize][i][j] = chessboard[i][j];
}
res[*returnSize][i][j] = '\0'; //巨坑!!!!!
}
(*returnSize)++;
return;
}
for (int col = 0; col < n; col++) {
//验证合法就可以在chessboard[row][col]位置上放置皇后
if (isValid(row, col, chessboard, n)) {
chessboard[row][col] = 'Q';
backtracking(n, res, returnSize, chessboard, row + 1);
chessboard[row][col] = '.'; //回溯,撤销放置皇后
}
}
}
char *** solveNQueens(int n, int* returnSize, int** returnColumnSizes){
*returnSize = 0;
char*** res = malloc(sizeof(char**) * 1000);
//新建一个n*n数组代表棋盘,初始化每个元素为.
char** chessboard = malloc(sizeof(char*) * n);
for (int i = 0; i < n; i++) {
chessboard[i] = malloc(sizeof(char) * n);
for (int j = 0; j < n; j++) {
chessboard[i][j] = '.';
}
}
backtracking(n, res, returnSize, chessboard, 0);
*returnColumnSizes = malloc(sizeof(int) * (*returnSize));
for (int i = 0; i < *returnSize; i++) {
(*returnColumnSizes)[i] = n;
}
return res;
}