力扣(51困难) N皇后问题

 

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

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

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

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

该解法基本为傻瓜式解法,还有许多可以优化的地方,现代码如下,附上注释

 

  • class Solution {
        public List<List<String>> solveNQueens(int n) {
    
            List<List<String>> res=new ArrayList<List<String>>();
            //新建棋盘
            char[][] jieguo=new char[n][n];
            //复制一个棋盘,保证行无queen
            boolean[][] line=new boolean[n][n];
            //Set集合,保证不会有重复的列被使用
            Set<Integer> columns = new HashSet<Integer>();
            //初始化棋盘
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    jieguo[i][j]='.';
                }
            }
    
            dfs(jieguo,n,line,res,0,columns);
            return res;
        }
        public void dfs(char[][] jieguo,int n,boolean[][] line,List<List<String>> res,int indexL,Set<Integer> columns ){
            //回溯的结束条件
            if(n==0){
                //将jieguo数组转换为List<String>
                List<String> ans=zhuanhuan(jieguo);
                //加入到集合中去
                res.add(ans);
                return;
            }
            //保证行不越界
            if(indexL>=jieguo.length||indexL<0){
                return;
            }
            //标志位,保证交叉方向无queen
            boolean isTrue=false;
            //对每一列试探性填入queen
            for(int indexC=0;indexC<jieguo.length;indexC++){
                //保证目前位置行列方向无queen
                if(!Arrays.asList(line[indexL]).contains(true)){
                    //保证当前列无queen
                    if(columns.contains(indexC)){
                        continue;
                    }
                    //保证交叉方向无queen
                    int indexLL=indexL;
                    int indexLL2=indexL;
                    int indexCC=indexC;
                    int indexCC2=indexC;
                    //交叉的右上方向
                    if(indexLL!=0&&indexCC!=0){
                        while(indexLL!=0&&indexCC!=0){
                            indexLL--;
                            indexCC--;
                        }                
                    }
                    //遍历右上方向是否有queen
                    for(int i=indexCC;i<jieguo.length&&indexLL<jieguo.length;i++,indexLL++){
                        if(jieguo[indexLL][i]=='Q'){
                            isTrue=true;
                        }
                    }
                    //交叉的右下方向
                    if(indexLL2!=0&&indexCC2!=jieguo.length-1){
                        while(indexCC2!=jieguo.length-1&&indexLL2!=0){
                            indexLL2--;
                            indexCC2++;
                        }
                    }
                    //遍历左上方向是否有queen
                    for(int j=indexCC2;j>=0&&indexLL2<jieguo.length;j--,indexLL2++){
                        if(jieguo[indexLL2][j]=='Q'){
                            isTrue=true;
                        }
                    }
                    
    
                    //标志位为false,该位置可以填入
                    if(isTrue!=true){
                        //在棋盘当前位置填入queen
                        jieguo[indexL][indexC]='Q';
                        //将该位置置为true,保证下一次该行不会填入queen
                        line[indexL][indexC]=true;
                        //将该列加入到Set集合中去
                        columns.add(indexC);
                        //对下一行进行回溯
                        dfs(jieguo,n-1,line,res,indexL+1,columns);
                    }
                }
                //回溯,保证下一个位置的插入
                jieguo[indexL][indexC]='.';
                //恢复棋盘的行状态
                line[indexL][indexC]=false;
                //恢复棋盘的列状态
                columns.remove(indexC);
                //恢复标志位
                isTrue=false;
            }
        }
    
        public List<String> zhuanhuan(char[][] jieguo){
            List<String> ans=new ArrayList<String>();
            for(int i=0;i<jieguo.length;i++){
                String bb=new String(jieguo[i]);
                ans.add(bb);
            }
            return ans;
        }
    
    }

反思:

  •  对于数组的列状态的判断在一开始想用空间换时间的做法,最后发现想法错误,交换数组的下标无法判断数组的列状态
  • 在恢复棋盘状态时,忘记将标志位也恢复,导致找了很长时间的逻辑错误,在leetcode上找逻辑错误是真的难
  • 虽然结果都通过了,但是速度比较慢,还有很多优化的地方,代码比较冗余

 优化:

  • 可以将标志位isTrue去掉,直接使用continue代替
  • 可以将line数组去掉,判断行有无queen时,直接使用jieguo数组直接判断
  • 对于交叉方向有无queen的判断可以再次进行优化,这里使用了太多的变量保存行列的坐标

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值