leetcode51. N 皇后|C++|回溯|递归

题目链接:力扣

题目描述

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例 1:

 输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:

输入:n = 1
输出:[["Q"]]
 

提示:

1 <= n <= 9

果果念

又是很久没有刷题了,手感变陌生了,最快下周就要面试了,加油。

这是很经典的N皇后问题,调研的资料显示最优复杂度也是O(N!),因此和全排列差不多。回溯的话,找到边界条件;另外,要明白八皇后的规则。

皇后会在同一行或者同一列进行攻击,值得一提的是,他们也会在斜线上进行攻击,并不是简单的对角线的前后两行,而是很长的斜线上。这一点刚开始做的时候没有考虑到,导致出的结果不正确。即下图中的排列也是不行的,因为他们在同一条斜线上。

说一下具体的思路:可以按行或者按列进行检索,利用一个数组存储不同的位置。我使用的是一个path记录每次排放的各行的列下标,num指的是每一行。最后返回答案的时候,换成字符串即可。

 

 代码

这个代码算法复杂度是O(N)*O(N!),O(N)是判断对角线的,当然,这个可以用一个数组保存对角线的位置,进行标记,就像标记列一样,不过需要两个对角线数组,你知道为什么吗?因为左右对角线不同呀。这个在代码2中有,是我参考的一个大佬写的。膜拜。

class Solution {
    //不可以同行、同列、对角线
public:
    vector<vector<int>> pathSum;
    vector<int> book;//标记数组,此列是否标记

    vector<vector<string>> solveNQueens(int n) {
        
        for(int i=0;i<n;i++){
            book.push_back(0);//初始列都是0,没有皇后
        }

        vector<int> path;
        getPath(0,n,path);

        vector<vector<string>> pathAns;
        
        string a;
        for(int i=0;i<n;i++){
            a.push_back('.');
        }

        for(int i=0;i<pathSum.size();i++){
            vector<string> stringRow;
            for(int j=0;j<n;j++)
            {
                a[pathSum[i][j]]='Q';
                stringRow.push_back(a);
                a[pathSum[i][j]]='.';
            }
            pathAns.push_back(stringRow); 
        }
        return pathAns;

    }
    //按行索引,row;保证列不相同,0~n-1
    void getPath(int num,int n,vector<int>& path){
        if(num==n){

            pathSum.push_back(path);
     
            return;
        }
        
        for(int i=0;i<n;i++){
            if(num==0&&book[i]==0){
                // cout<<num<<endl;
                path.push_back(i);
                book[i]=1;
                getPath(num+1,n,path);
                path.pop_back();
                book[i]=0;
            }else if(book[i]==0&&num!=0){
                bool flag = false;//默认不在斜线上
                for(int j=num-1,index=1;j>=0;j--,index++){
                    //判断是否在斜线上
                    if(path[j]==i-index||path[j]==i+index){
                        flag=true;
                        break;
                    }
                }
                if(flag==false){
                    path.push_back(i);
                    book[i]=1;
                    getPath(num+1,n,path);
                    path.pop_back();
                    book[i]=0;
                }
                }
            }

    }
};

对角线优化

刚刚看了一个题解,博主对角线也记录了下来,这样就少了一个循环。算法复杂度O(N!)。

class Solution {
        public List<List<String>> solveNQueens(int n) {
            char[][] grid = new char[n][n];         // n * n 的棋盘
            boolean[] col = new boolean[n];         //列
            boolean[] dg = new boolean[2 * n - 1];  //对角线(右上到左下的对角线,dg[0]为左上角grid[0][0]的元素,dg[1]为grid[0][1]和gird[1][0],...)
            boolean[] udg = new boolean[2 * n - 1]; //反对角线(左上到右下的对角线,udg[0]为左下角grid[n-1][0]的元素,ud1[1]为grid[n-2][0]和gird[n-1][1],...)

            for (int i = 0; i < n; i++) {           //初始化棋盘
                for (int j = 0; j < n; j++) {
                    grid[i][j] = '.';
                }
            }

            List<List<String>> lists = new ArrayList<>();
            List<String> list = new ArrayList<>();
            dfs(0, n, grid, col, dg, udg, lists, list);
            return lists;
        }

        private void dfs(int row, int n, char[][] grid, boolean[] col, boolean[] dg, boolean[] udg, List<List<String>> lists, List<String> list) {
            if (row == n) { //递归到最后一行
                for (int i = 0; i < n; i++) {
                    list.add(new String(grid[i]));  //全部排列完毕、将第i行添加进结果(list)中
                }
                lists.add(new ArrayList<>(list));   //将当前结果list添加进结果集(lists)中
                list.clear();
            } else {
                //当前在第row行,从第0列到n-1列进行循环
                for (int i = 0; i < n; i++) {
                    //当前列、对角线、反对角线有元素则跳过(剪枝)
                    if (col[i] || dg[i + row] || udg[i + n - 1 - row]) {
                        continue;
                    }
                    //当前位置(row = row,col = i)可用
                    grid[row][i] = 'Q';
                    //当前列和对角线设置为ture,即已经用过
                    col[i] = dg[i + row] = udg[i - row + n - 1] = true;
                    //递归进下一行
                    dfs(row + 1, n, grid, col, dg, udg,lists,list);
                    //回溯
                    grid[row][i] = '.';
                    col[i] = dg[i + row] = udg[i - row + n - 1] = false;
                }
            }
        }
    }

作者:Alkaidling
链接:https://leetcode-cn.com/problems/n-queens/solution/nhuang-hou-bu-yong-ha-xi-biao-shi-yong-b-d2vj/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。class Solution {
        public List<List<String>> solveNQueens(int n) {
            char[][] grid = new char[n][n];         // n * n 的棋盘
            boolean[] col = new boolean[n];         //列
            boolean[] dg = new boolean[2 * n - 1];  //对角线(右上到左下的对角线,dg[0]为左上角grid[0][0]的元素,dg[1]为grid[0][1]和gird[1][0],...)
            boolean[] udg = new boolean[2 * n - 1]; //反对角线(左上到右下的对角线,udg[0]为左下角grid[n-1][0]的元素,ud1[1]为grid[n-2][0]和gird[n-1][1],...)

            for (int i = 0; i < n; i++) {           //初始化棋盘
                for (int j = 0; j < n; j++) {
                    grid[i][j] = '.';
                }
            }

            List<List<String>> lists = new ArrayList<>();
            List<String> list = new ArrayList<>();
            dfs(0, n, grid, col, dg, udg, lists, list);
            return lists;
        }

        private void dfs(int row, int n, char[][] grid, boolean[] col, boolean[] dg, boolean[] udg, List<List<String>> lists, List<String> list) {
            if (row == n) { //递归到最后一行
                for (int i = 0; i < n; i++) {
                    list.add(new String(grid[i]));  //全部排列完毕、将第i行添加进结果(list)中
                }
                lists.add(new ArrayList<>(list));   //将当前结果list添加进结果集(lists)中
                list.clear();
            } else {
                //当前在第row行,从第0列到n-1列进行循环
                for (int i = 0; i < n; i++) {
                    //当前列、对角线、反对角线有元素则跳过(剪枝)
                    if (col[i] || dg[i + row] || udg[i + n - 1 - row]) {
                        continue;
                    }
                    //当前位置(row = row,col = i)可用
                    grid[row][i] = 'Q';
                    //当前列和对角线设置为ture,即已经用过
                    col[i] = dg[i + row] = udg[i - row + n - 1] = true;
                    //递归进下一行
                    dfs(row + 1, n, grid, col, dg, udg,lists,list);
                    //回溯
                    grid[row][i] = '.';
                    col[i] = dg[i + row] = udg[i - row + n - 1] = false;
                }
            }
        }
    }

作者:Alkaidling
链接:https://leetcode-cn.com/problems/n-queens/solution/nhuang-hou-bu-yong-ha-xi-biao-shi-yong-b-d2vj/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值