【LeetCode力扣题库】52. N皇后 II(困难)

原题目链接:52. N皇后 II


题目描述:

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

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

示例 1:


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

输入:n = 1
输出:1

 

  • 1 <= n <= 9
  • 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-queens-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

做题思路:

  1. 八皇后问题要采用回溯和剪枝来解决,那么什么是回溯和剪枝呢?
  2. 什么是回溯?

2.1  假设我们用前序遍历,遍历下面的二叉树,前序遍历就是先遍历根节点,然后左子节点,接着右子节点

2.2  红色线就是前序遍历的路线,而绿色就是回溯的路线,例如7 -> 4 -> 2 -> 1,此时,我们发现1往下没得走了,因为 1 没有子节点,所以退回到 2 节点,这个过程就叫做回溯

  

3.  什么是剪枝?

3.1  假如有个四皇后的问题,如图所示

3.2  在摆放第一个皇后后,我们会发现出现不可摆放的位置即黑色,那这些位置我们就可以判断出来,从而不用花费时间去尝试这些位置能不能摆放皇后,这就是剪枝操作

4.  在了解完这两个知识点之后,我还得解释一下如果利用数学的斜率k判断两个点(皇后)是否在一条对角线上

4.1  在我画的图,每个小矩形就代表一个点,假设有两个点(皇后),坐标分别是Q1(x1,y1),Q2(x2,y2),由于斜率k的计算公式是,如果这个k的值等于-1或者1,就说明两个点(皇后)是同一条对角线,那么也就是说,同一对角线只有两种情况。

4.2  第一种,(x1 - x2)  =  -1 * (y1 - y2),第二种,(x1 - x2)  =  1 * (y1 - y2),合并上面两个情况就是,(x1 - x2)  =  | (y1 - y2) |

5.  最后我用四皇后的流程图走一遍

废话不多说,直接上代码,为了让各位看官更能清晰理解,我的代码写得不精简,我的代码里加了大量的注释,相信各位看官可以理解,如果我有些没写清楚或者写错的,可以评论区或者私信我喔

class Solution {
    //数组下标代表行号,数组元素代表列号
    //例如:cols[0] = 3,就代表第0行第3列有皇后
    int[] cols;
    //存放摆放皇后的方法数量
    int ways;
    public int totalNQueens(int n) {
        if(n < 1) return 0; //如果皇后个数小于1,就没有摆放的必要了
        cols = new int[n];  //初始化数组
        place(0);   //从第0行开始摆放
        return ways;
    }
    /**
     * 摆放皇后的方法
     * @param row 代表第几行 
     */
    void place(int row){
        if(row == cols.length){ 
            //由于是从第0行开始摆放,依次往下摆放,说明当摆放到n行的时候,前面的已经摆放好了
            //所以就算是一种正确的摆放方法
            ways++;
            return;
        }
        //确定了行,那么现在就要确定哪一列
        for(int col = 0; col < cols.length; col++){
            if(isValid(row,col)){   //是否可以摆放皇后
                cols[row] = col;
                place(row + 1); //递归调用摆放皇后的方法,一旦摆好一个皇后,就立马跳到下一行摆放下一个皇后
            }
        }
        //代码执行到这里,说明了在进行剪枝操作
    }
    /**
     *  判断第row行第col列是否能摆放皇后
     *  @param row 代表第几行
     *  @param col 代表第几列
     */
     boolean isValid(int row, int col){
         //遍历所有行
         for(int i = 0; i < row; i++){
             //我们依次列举三种不能摆放的情况
             //第一种情况,摆好皇后后,下一个皇后不能摆放在相同行,这里由于一旦摆好一个皇后,就立马跳到下一行摆放下一个皇后,所以可以不进行处理
             //第二种情况,摆好皇后后,下一个皇后不能摆放在相同列
             if(cols[i] == col) return false;
             //第三种情况,摆好皇后后,下一个皇后不能摆放在对象线,我这里利用数学的斜率对对角线的情况进行了处理
             if(row - i == Math.abs(col - cols[i])) return false;    //abs方法返回绝对值
         }
         //代码执行到这里,说明是可以的
         return true;
     }
}

都看到这里了,不考虑点个赞再走嘛?

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值