77、★回溯-N皇后问题-困难题-LeetCode.51N 皇后

题目描述

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

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

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

来源:力扣(LeetCode)

思路

1)首先需要一个 判断位置是否合法的方法!

不仅要判断相邻位置还要判断之前的所有位置;需要一个记录之前每层摆放位置的List;

②近似看作两个位置不能组成一个正方形,判断的是 对角线!

 boolean isTrue(int index){
        //不符合规定的三种情况
        int num = level.size();//得到的是,现在要摆放的层数!
        for(int i = 0;i < num;i++){
            int a = level.get(i);
            if(index == a || (index - a == num - i) || (index  + num - i == a)) return false;
        }
        return true;
    }

2)回溯的内容:path列表、记录层数的level列表、每次设置的StringBuilder 三个内容!

            if(isTrue(i)){
                str.setCharAt(i,'Q');
                path.add(new String(str));
                level.add(i);
                backTrack(n,level);
                level.remove(level.size() - 1);
                path.remove(path.size() - 1);
                str.setCharAt(i,'.');//回溯

            }

3)剪枝优化:还不清楚!

字符数组模拟棋盘实现:

1)判断条件使用简单的数组位置上的属性进行判断;

2)声明一个将二维数组添加到结果集的方法;

3)使用了棋盘,回溯里的逻辑就简单了许多!

判断时,下标 0 n之类的只要前后一直,保持不变即可!

代码

1)手写回溯 + 各种判断条件

class Solution {
   List<List<String>> res = new ArrayList<>();//记录最后的结果!
    List<String> path = new ArrayList<>();//记录每次的路径
    StringBuilder stb = new StringBuilder();
    List<Integer> level = new ArrayList<>();//记录层数和摆放的位置
    public List<List<String>> solveNQueens(int n) {
        for(int i = 0;i < n;i++){
            stb.append('.');
        }//确定了一个全是 "."的字符串,每层只要修改就好
        //第一行的每个位置都可以尝试,所以 传入的为 -2
        backTrack(n,level);
        return res;
    }
    //结果集res中存储的List是n个String,一个String表示一层

    //要传入层数,和第几层在哪个位置上!
    //用数组记录!
    void backTrack(int n,List<Integer> level){
        //存够了 n 个层,就说明满足了结果
        if(path.size() == n){
            res.add(new ArrayList(path));
            return;
        }
        //是每一层都从头开始的回溯方式
        //难点在于 不符合摆放的条件判断
        StringBuilder str = new StringBuilder(stb);
        for(int i = 0;i < n;i++){
            //情况合适,就进入循环
            if(isTrue(i)){
                str.setCharAt(i,'Q');
                path.add(new String(str));
                level.add(i);
                backTrack(n,level);
                level.remove(level.size() - 1);
                path.remove(path.size() - 1);
                str.setCharAt(i,'.');//回溯

            }
            continue;
        }
    }
    //判断位置是否合法的情况
    //不能只判断相邻的 两层!
    //和之前的每一个点都不能在同一个正方形上
    boolean isTrue(int index){
        //不符合规定的三种情况
        int num = level.size();//得到的是,现在要摆放的层数!
        for(int i = 0;i < num;i++){
            int a = level.get(i);
            if(index == a || (index - a == num - i) || (index  + num - i == a)) return false;
        }
        return true;
    }
}

2)利用二维字符数组实现:

class Solution {
    List<List<String>> res = new ArrayList<>();//记录最后的结果!
    public List<List<String>> solveNQueens(int n) {
        //使用数组模拟一个棋盘
        char[][] chessboard = new char[n][n];
        //生成一个 . 的棋盘
        for (char[] c : chessboard) {
            Arrays.fill(c, '.');
        }
        backTrack(n,0,chessboard);//把总共可以尝试的 列传进去n,第几行row用来判断位置;chessboard用来更改棋盘
        return res;
    }
    void backTrack(int n,int row,char[][] chessboard){
    
        if(row == n){
            res.add(addPath(chessboard));
            return;
        }
        for(int i = 0;i < n;i++){
            //单层逻辑
            if(isTrue(row,i,n,chessboard)){
                chessboard[row][i] = 'Q';
                backTrack(n,row + 1,chessboard);
                chessboard[row][i] = '.';
            }
        }
    }
    //棋盘改变之后还要添加
    List<String> addPath(char[][] chessboard){
        List<String> path = new ArrayList<>();
        for(char[] ch : chessboard){//每次拿到的是一个char数组
            path.add(new String(ch));
        }
        return path;
    }
    //判断位置合法性
    boolean isTrue(int row,int col,int n,char[][] chessboard){
        //三种情况
        for(int i = 0;i < row;i++){//判断列
            if(chessboard[i][col] == 'Q') return false;
        }
        //对角线45°
        for(int i = row - 1,j = col - 1;i >=0 && j >= 0;i--,j--){
            if(chessboard[i][j] == 'Q') return false;
        }//左边135°对角线
        for(int i = row - 1,j = col + 1;i >= 0 && j <= n - 1;i--,j++){
            if(chessboard[i][j] == 'Q') return false;
        }
        return true;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值