• LeetCode·51.N皇后·递归+回溯


    链接:https://leetcode.cn/problems/n-queens/solution/-by-xun-ge-v-dn14/
    来源:力扣(LeetCode
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 

    题目

     

    示例

     

    思路

    解题思路
    本题应该是回溯的经典题

    首先来看一下皇后们的约束条件:

    • 不能同行
    • 不能同列
    • 不能同斜线 (45度和135度角)

    确定完约束条件,来看看究竟要怎么去搜索皇后们的位置,其实搜索皇后的位置,可以抽象为一棵树。
    下面我用一个3 * 3 的***,将搜索过程抽象为一颗树,如图:


    具体实现
    我们定义一个n*n大小的棋盘,然后递归枚举棋盘上面每一个位置判断当前位置能不能成为皇后,能不能成为皇后的约束条件上面已经给出,如果当前位置不能成为皇后就直接跳过当前位置,如果当前位置能成为皇后,就重复上述步骤,直到枚举到最后一行为止 

    大体为递归枚举每一列,每层递归枚举行中每一个元素 

    代码注释超级详细
    分为【直接修改】和【间接修改】

    代码

    【直接修改】:直接在棋盘上进行改动

    1. /**
    2. * Return an array of arrays of size *returnSize.
    3. * The sizes of the arrays are returned as *returnColumnSizes array.
    4. * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
    5. */
    6. bool isValid(char ** res, int row, int col, int n) {
    7. // 检查列
    8. for (int i = 0; i < row; i++) { // 这是一个剪枝
    9. if (res[i][col] == 'Q') {
    10. return false;
    11. }
    12. }
    13. // 检查 45度角是否有皇后
    14. for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {
    15. if (res[i][j] == 'Q') {
    16. return false;
    17. }
    18. }
    19. // 检查 135度角是否有皇后
    20. for(int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
    21. if (res[i][j] == 'Q') {
    22. return false;
    23. }
    24. }
    25. return true;
    26. }
    27. void dfs(char *** ans, int * returnSize, int ** returnColumnSizes, char ** res, int index, int n)
    28. {
    29. //枚举到最后一行,保存当前棋盘,因为如果不能成为皇后就不能进入下一行
    30. //所以能到最后一行肯定是有效的
    31. if(index == n)
    32. {
    33. ans[(*returnSize)] = (char **)malloc(sizeof(char *) * n);
    34. for(int i = 0; i < n; i++)
    35. {
    36. ans[(*returnSize)][i] = (char *)malloc(sizeof(char) * (n+1));
    37. memcpy(ans[(*returnSize)][i], res[i], sizeof(char) * (n+1));
    38. }
    39. (*returnColumnSizes)[(*returnSize)++] = n;
    40. return;
    41. }
    42. //枚举当前行中每一个元素
    43. for(int i = 0; i < n; i++)
    44. {
    45. if(isValid(res, index, i, n) == true)//检查当前位置能不能放皇后
    46. {
    47. res[index][i] = 'Q';//可以直接放皇后
    48. dfs(ans, returnSize, returnColumnSizes, res, index+1, n);//进入下一行,重复当前步骤
    49. res[index][i] = '.';//回溯,进行判断下一个元素
    50. }
    51. }
    52. return ;
    53. }
    54. char *** solveNQueens(int n, int* returnSize, int** returnColumnSizes){
    55. char *** ans = (char ***)malloc(sizeof(char**) * 1000);
    56. *returnColumnSizes = (int *)malloc(sizeof(int) * 1000);//初始化变量
    57. *returnSize = 0;
    58. char ** res = (char **)malloc(sizeof(char *) * n);
    59. for(int i = 0; i < n; i++)//定义棋盘并初始化
    60. {
    61. res[i] = (char *)malloc(sizeof(char) * (n+1));
    62. memset(res[i], '.', sizeof(char) * n);
    63. res[i][n] = '\0';
    64. }
    65. //递归枚举每一个位置
    66. dfs(ans, returnSize, returnColumnSizes, res, 0, n);
    67. return ans;
    68. }
    69. 作者:xun-ge-v
    70. 链接:https://leetcode.cn/problems/n-queens/solution/-by-xun-ge-v-dn14/
    71. 来源:力扣(LeetCode)
    72. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    【间接修改】:利用数组保存皇后位置,棋盘不做修改 

    1. /**
    2. * Return an array of arrays of size *returnSize.
    3. * The sizes of the arrays are returned as *returnColumnSizes array.
    4. * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
    5. */
    6. bool isVaild(int* path, int row, int col) {
    7. /* 依次遍历当前行row的之前所有行 */
    8. for (int i = 0; i < row; i++) {
    9. /* path[i] == col 表示这一列上有其他皇后
    10. * row + col == path[i] + 1 表示右上角有其他皇后
    11. * row - col == i - path[i] 表示左上角有其他皇后
    12. */
    13. if (path[i] == col || row + col == path[i] + i || row - col == i - path[i]) {
    14. /* 出现皇后相互冲突,返回true */
    15. return true;
    16. }
    17. }
    18. /* 未出现皇后互相冲突,返回false */
    19. return false;
    20. }
    21. void backtrack(int n, int row, int* path, char*** res, int* returnSize) {
    22. /* 1、当前行数为n,表示已经找到了N皇后的一个解 */
    23. if (row == n) {
    24. /* 当前解的行数为n,为其分配空间 */
    25. res[*returnSize] = (char**)malloc(sizeof(char*) * n);
    26. for (int i = 0; i < n; i++) {
    27. /* 当前解的当前行的列数为n+1,因为存储的时字符串,所以需要一个'\0'
    28. * 使用memset将当前解的当前行全部赋值为0
    29. */
    30. res[*returnSize][i] = (char*)calloc(n+1, sizeof(char));
    31. /* 将当前解的当前行全部赋值为'.' */
    32. memset(res[*returnSize][i], '.', n);
    33. /* 再将当前解的当前行中皇后为位置赋值为'Q' */
    34. res[*returnSize][i][path[i]] = 'Q';
    35. }
    36. /* 解的数量加一 */
    37. (*returnSize)++;
    38. /* 返回上一层决策树 */
    39. return;
    40. }
    41. /* 2、当前行数 < n,还未到达决策树的底层 */
    42. for (int j = 0; j < n; j++) {
    43. /* 排除当前行row的当前列j上是否发送皇后冲突 */
    44. if (isVaild(path, row, j)) {
    45. /* 发生冲突,跳过此列继续查找下一列 */
    46. continue;
    47. }
    48. /* 当前列j可以放置皇后 */
    49. path[row] = j;
    50. /* 进入下一层决策树,查找下一行的皇后位置
    51. * 这里没有[选择]和[取消选择]是因为
    52. * 这里的[选择]就是当前行数row,而传入下一层决策树的[选择]就是row+1
    53. * 所以不许要[选择]和[取消选择]了
    54. */
    55. //row++; /* [选择] */
    56. //backtrack(n, row, path, res, returnSize); /* 进入下一层决策树 */
    57. //row--; /* [取消选择] */
    58. backtrack(n, row+1, path, res, returnSize);
    59. }
    60. }
    61. char*** solveNQueens(int n, int* returnSize, int** returnColumnSizes) {
    62. /* 1、赋值解的个数,初值为0 */
    63. *returnSize = 0;
    64. /* 2、定义[路径]数组,用于存储一行中皇后的列位置下标 */
    65. int* path = (int*)calloc(n, sizeof(int));
    66. /* 3、定义返回数组 */
    67. char*** res = (char***)malloc(sizeof(char**) * n*n*n);
    68. /* 4、进行回溯查找
    69. * 参数1:皇后的个数
    70. * 参数2:当前行数,从0行开始查找
    71. * 参数3: 路径数组path,用于存储当前行皇后所在位置;列下标
    72. * 参数4:返回数组,存储N皇后排列的解
    73. * 参数5:解的个数
    74. */
    75. backtrack(n, 0, path, res, returnSize);
    76. /* 5、分配用于存储解中列数的空间 */
    77. *returnColumnSizes = (int*)malloc(sizeof(int) * (*returnSize));
    78. for (int i = 0; i < (*returnSize); i++) {
    79. /* 解为NxN矩阵,每一行的列数均为N */
    80. (*returnColumnSizes)[i] = n;
    81. }
    82. /* 6、打印解的个数,用于调试 */
    83. //printf("the number of res is %d\n", *returnSize);
    84. /* 7、返回解数组 */
    85. return res;
    86. }
    87. 作者:xun-ge-v
    88. 链接:https://leetcode.cn/problems/n-queens/solution/-by-xun-ge-v-dn14/
    89. 来源:力扣(LeetCode)
    90. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    HarmonyOS NEXT:华为开启全新操作系统时代
    使用mac自带VNC公网远程控制macOS
    入职半年,加薪50%,这4类人是如何搭建办公知识体系的?
    CUDA编程:矩阵乘运算从CPU到GPU
    Three.js的学习资料和学习计划,统统安排上
    用Python写爬虫有哪些好处?
    固体物理 2022.9.30
    LeetCode 子串 子数组 系列题目总结
    Windows 10 数据恢复与预防数据丢失指南
    晶振是如何起振的
  • 原文地址:https://blog.csdn.net/m0_64560763/article/details/126703206