『牛客|每日一题』N皇后问题

1,355 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

👨‍🎓作者简介:一位喜欢写作,计科专业的大三菜鸟

🏡个人主页:starry陆离 的个人主页

如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦

1.每日一题

原题链接:传送门-》戳我

N 皇后问题是指在 n * n 的棋盘上要摆 n 个皇后, 要求:任何两个皇后不同行,不同列也不在同一条斜线上, 求给一个整数 n ,返回 n 皇后的摆法数。

数据范围: 1≤n≤9

要求:空间复杂度 O(1) ,时间复杂度 O(n!)

例如当输入4时,对应的返回值为2,

对应的两种四皇后摆位如下图所示:

image-20220804000238141

2.解题思路

2.1思路分析

皇后问题很简单,因为每一行,每一列,每条斜线不能有重复的皇后,所以我们只需要从遍历行的角度出发,去检查新的一行里每一列和左右两条斜线是否有皇后冲突,当没有冲突的时候就坐标信息表示放置皇后。当一直找到最后一行时就表示找到了一种摆法,然后回溯去找新的解。

  • step 1:定义一个公共变量记录摆法的种数
    //皇后摆法得个数
       public int ans;
  • step 2:用一个一维数组来记录每一列是否放了皇后,数组的下标表示行,值表示列(很巧妙吧,如果是你去保存一个坐标的信息是不是只会开一个二维数组呢)

     //记录某一列是否放了皇后
         int col[]=new int[10];
    
  • step 3:调用深搜函数,我们按行来深搜,递归的结束条件就是搜索完最后一行后代表找到一种解,开始回溯。

    //如果搜索完棋盘的最后一行(下标从0开始最后一行是n-1)
       if(r==n){
           //摆放的方法+1
           ans++;
           return;
       }
  • step 4:如果没有搜索完最后一行,我们就遍历这一行的每一列,首先通过check()检查如果在这一列放是否与之前行已经放好的皇后冲突;如果不冲突的话才放置皇后,就是标记col[]数组,然后往下一行搜索;记得回溯时去皇后 col[r]=0;
   //遍历n列
       for(int c=0;c<n;++c){
           //剪枝操作
           if(check(r,c,col)){
               //标记在第r行的第c列放的皇后
               col[r]=c;
               //深度搜索下一行,在下一行放皇后
               dfs(r+1,n,col);
               //回溯,去除标记
               col[r]=0;
           }
       }
  • step 5:第四步中用到了check()函数检查冲突,冲突的检查规则就是不能同行同列同斜线,同行的检查是不需要的因为我们的深搜就是按行进行肯定不会在同一行放两个皇后。检查列就是比对此时的列是否已经被标记(记录过皇后的坐标col[i]==c);检查斜线这里也很巧,因为在同一斜线上的两点的横坐标之差与纵坐标之差会相等,所以只需判断(Math.abs(col[i]-c)==(Math.abs(i-r)))是否成立

3.关键代码

 import java.util.*;
 ​
 ​
 public class Solution {
     /**
      * 
      * @param n int整型 the n
      * @return int整型
      */
     //皇后摆法得个数
     public int ans;
     public int Nqueen (int n) {
         // write code here
         ans=0;
         //记录某一列是否放了皇后
         int col[]=new int[10];
         Arrays.fill(col,0);
         //深度搜索
         dfs(0,n,col);
         return ans;
     }
      //深度搜索
     public void dfs(int r,int n,int col[]){
         //如果搜索完棋盘的最后一行(下标从0开始最后一行是n-1)
         if(r==n){
             //摆放的方法+1
             ans++;
             return;
         }
         //遍历n列
         for(int c=0;c<n;++c){
             //剪枝操作
             if(check(r,c,col)){
                 //标记在第r行的第c列放的皇后
                 col[r]=c;
                 //深度搜索下一行,在下一行放皇后
                 dfs(r+1,n,col);
                 //回溯,去除标记
                 col[r]=0;
             }
         }
     }
     public boolean check(int r,int c,int col[]){
         //检查是否与前面已经放了皇后的r行是否冲突
         for(int i=0;i<r;++i){
             //检查列冲突和对角线冲突
             if(col[i]==c||(Math.abs(col[i]-c)==(Math.abs(i-r)))){
                 return false;
             }
         }
         return true;
     }
 }

image-20220804000419817

🍁每日推荐:算法面试神器:牛客网-面试神器 在这里插入图片描述

如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦