N 皇后问题是指在 n * n 的棋盘上要摆 n 个皇后,
要求:任何两个皇后不同行,不同列也不在同一条斜线上,
求给一个整数 n ,返回 n 皇后的摆法数。
要求:任何两个皇后不同行,不同列也不在同一条斜线上,
求给一个整数 n ,返回 n 皇后的摆法数。
数据范围:
要求:空间复杂度
,时间复杂度
例如当输入4时,对应的返回值为2,
对应的两种四皇后摆位如下图所示:
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型 the n
* @return int整型
*/
static int result = 0;
public static int Nqueen (int n) {
boolean[] cols = new boolean[n];
boolean[] diags1 = new boolean[2 * n - 1];
boolean[] diags2 = new boolean[2 * n - 1];
// write code here
backtrack(0, n, cols, diags1, diags2);
return result;
}
public static void backtrack(int row, int n, boolean[] cols, boolean[] diags1,
boolean[] diags2) {
if (row == n) {
result++;
}
for (int i = 0; i < n; i++) {
if (!cols[i] && !diags1[row - i + n - 1] && !diags2[row + i]) {
//选择当前列
cols[i] = true;
diags1[row - i + n - 1] = true;
diags2[row + i] = true;
backtrack(row + 1, n, cols, diags1, diags2);
cols[i] = false;
diags1[row - i + n - 1] = false;
diags2[row + i] = false;
}
}
}
} 在不会使用回溯的时候,我想过这样一种写法: //当个乐子看就行了
public int Nqueen (int n) {
// write code here
switch(n){
case 1:
return 1;
case 2:
return 0;
case 3:
return 0;
case 4:
return 2;
case 5:
return 10;
case 6:
return 4;
case 7:
return 40;
case 8 :
return 92;
case 9:
return 352;
}
return 0;
} int ans=0;
public int Nqueen (int n) {
//在build()中,放置第i个皇后
int[] arr=new int[n];//arr[i]表示第i个皇后在第j列
build(0,n,arr);//放置第0个皇后,总共放置n个皇后,arr[n]表示第n个皇后的列数
return ans;
}
public void build(int i,int n,int[] arr){
if(i==n){
ans++;
return;
}
for(int j=0;j<n;j++){
arr[i]=j;//把第i个皇后放到第j列
if(check(i,arr)==true){//如果第i个皇后可以放置
build(i+1,n,arr); //如果可以放置,那就递归调用放置第i+1个皇后
}
}
}
public boolean check(int i,int[] arr){
for(int j=0;j<i;j++){//只需要遍历0~i
if(arr[i]==arr[j]){ //第i个皇后和第j个皇后在同一列上
return false;
}
if(Math.abs(i-j)==Math.abs(arr[i]-arr[j])){ // |行i-行j|=|列i-列j|,则在一条斜线上
return false;
}
}
return true;
} import java.util.*;
public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
int count = 0;
public int Nqueen (int n) {
// write code here
//创建一个二维数组用来模拟棋盘并占位
int[][] board = new int[n][n];
dfs(n, 1, board);
return count;
}
public void dfs(int n, int row, int[][] board) {
//如果row等于n + 1,则计数+1
if (row > n) {
count++;
return;
}
//遍历本行棋盘
for (int i = 0; i < n; i++) {
//System.out.print("行:" + row);
//System.out.print("列:" + (i+1) + " ");
if (board[row - 1][i] == 1) {
continue;
}
int[][] newBoard = new int[n][n];
for (int q = 0; q < n; q++){
for (int p = 0; p < n; p++) {
newBoard[q][p] = board[q][p];
}
}
//将该棋子下方同列同斜线所有格子都标记
for (int below = row -1; below < n; below++) {
//正下方标记
newBoard[below][i] = 1;
//左斜下方标记
if (i - (below- row + 1) >= 0) {
newBoard[below][i - (below-row + 1)] = 1;
}
//右斜下方标记
if (i + (below- row + 1) < n) {
newBoard[below][i + (below-row + 1)] = 1;
}
}
//进入下一层
dfs(n,row+1,newBoard);
}
}
} public class Solution {
// 皇后
private static final char QUEUE = 'Q';
// 空位
private static final char EMPTY = '.';
// 解集数目
int ans;
public int Nqueen (int n) {
// 新建一个棋盘,本题就以它作为路径
char[][] board = new char[n][n];
// 初始化棋盘,将每一个位置都初始化为EMPTY
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
board[i][j] = EMPTY;
}
}
ans = 0;
// 回溯
backTrack(board, 0);
return ans;
}
private void backTrack(char[][] board, int row) {
// 收获结果
if (row == board.length) {
ans++;
return;
}
// 对这一行的每一个位置坐选择
for (int column = 0; column < board[row].length; column++) {
// 如果不合法,直接跳过本次选择,最后收获结果的时候也就不需要再做额外的判断了
if (!valid(board, row, column)) {
continue;
}
// 做出选择
board[row][column] = QUEUE;
backTrack(board, row + 1);
// 撤销选择
board[row][column] = EMPTY;
}
}
private boolean valid(char[][] board, int row, int column) {
// 向上找
for (int i = row; i >= 0; i--) {
if (board[i][column] == QUEUE) {
return false;
}
}
// 向左上方找
for (int i = row, j = column; i >= 0 && j < board[row].length; i--, j++) {
if (board[i][j] == QUEUE) {
return false;
}
}
// 向右上方找
for (int i = row, j = column; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == QUEUE) {
return false;
}
}
// 本次选择合法
return true;
}
} import java.util.*;
public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
int n;
int cnt =0;
boolean[] col;
boolean[] line1;
boolean[] line2;
public int Nqueen (int n) {
// write code here
this.n = n;
col = new boolean[n];
line1 = new boolean[2*n-1];
line2 = new boolean[2*n-1];
backtraking(0);
return cnt;
}
//固定到第n行
public void backtraking(int index){
//成功了一种
if(index==n){
cnt++;
return;
}
//摆放第index行的皇后
//同一斜线:row+col(index+i)相等,或者col-row(index-i)相等
//用三个数组存储列(i),index+i(范围是0到2n-2),index-i(-n+1到n-1)
for(int i=0;i<n;i++){
//列或者斜线上有
if(col[i]||line1[i+index]||line2[index-i+n-1]) continue;
col[i] = true;
line1[i+index] = true;
line2[index-i+n-1] = true;
backtraking(index+1);
col[i] = false;
line1[i+index] =false;
line2[index-i+n-1] = false;
}
}
} public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
int count = 0; // 记录共有多少种解法
public int Nqueen (int n) {
int[] arr = new int[n]; // 初始化一维数组保存皇后所在第几列, 下标正好表示皇后处在第几行,而下标对应的值是皇后在第几列
getNqueen (0, n, arr); // 递归求解
return count;
}
/**
*
* @param i 要插入数组元素的下标索引,
* @param n 最大n个皇后问题
* @param arr 保存皇后位置的数组
* @return
*/
public void getNqueen (int i, int n, int[] arr) {
if(i == n){ // i为要插入第i个皇后,如果i 等于最大数量n时,表示这一轮的解已然获取到,则count++
count++;
return;
}
for(int k = 0; k < n; k++){ // 从0开始,这里的循环0 - n 就是皇后要放入的那一列
arr[i] = k; // 先将第i个皇后放入第k列
if(check(i, arr)){ // 判断改皇后的位置是否冲突
getNqueen (i + 1, n, arr); // 如果不冲突,则递归放置下一个皇后的位置
}
}
}
/**
*
* @param i 检查第i个皇后 位置是否冲突
* @param arr 储存皇后位置的数组
* @return
*/
public boolean check(int i, int[] arr){
// 从第0个皇后位置开始检查 与 第i个皇后 位置是否冲突
for(int j = 0; j < i; j++){
// 1. 只要第j个皇后 和 第i个皇后的位置相等
// 2.判断解读: Math.abs(i - j) == Math.abs(arr[i] - arr[j]) 意思如下:
// Math.abs(i - j) 实际上获取的是两个皇后相差多少行,因为下标就是表示皇后在第几行上
// Math.abs(arr[i] - arr[j]) 取出第i个皇后所在的列,和第j个皇后所在列 相减得出的差 只要等于他们相差的行数,那就是在斜线上
// 举例子说明:
// 列号: 0 1 2 3 4 5 6 7
// 行号2: 0 0 1 0 0 0 0 0 这一行的 1 就与最下面一行的1 处于斜线。
// 行号1: 0 0 0 0 1 0 0 0
// 行号0: 1 0 0 0 0 0 0 0
// 行号2的1 与 行号0的1 两者之间相差行数为2, 并且行号2的1 所在列为2, 行号0的1 所在列为0
// 所以列的差2 - 0 = 2,行的差2 - 0 = 2,相等则两个在一个斜线
if(arr[i] == arr[j] || Math.abs(i - j) == Math.abs(arr[i] - arr[j])){
return false; // 符合条件就返回false,表示位置冲突
}
}
return true;
}
} import java.util.*;
public class Solution {
int result = 0;
public int Nqueen (int n) {
//用一个一维数组模拟二维数组,数组下标表示第I行,arr[i]的值表示放在第j列
int[] arr = new int[n];
backTracking(arr,0);
return result;
}
public void backTracking(int[] arr,int i){
int x = arr.length;
if(arr[x-1] > 0){
//最后一个棋子放完后,检查棋盘是否冲突,无冲突则将结果+1
if( check(arr,x-1)){
result ++;
}
return;
}
for(int j = 0;j < x;j ++){
arr[i] = j+1;
if(check(arr,i)){//无冲突则向下搜索
backTracking(arr,i+1);
}
//一列搜索完毕后回溯,进入下一次循环检测下一列是否符合要求
arr[i] = 0;
}
}
//检查当前棋盘是否存在冲突
//如果进入检查阶段,那么只需要检测最后一个棋子和前面的是否有冲突
//index为最后一个棋子的下标
public static boolean check(int[] arr,int index){
for(int i =0;i < index;i ++){
if(arr[i] == arr[index] || (Math.abs((index-i)) == Math.abs((arr[index] - arr[i])))){
return false;
}
}
return true;
}
} import java.util.*;
public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
int nums = 0;
public int Nqueen (int n) {
// write code here
// 思路 矩阵呢个 看作是n*n的二维数组
// 长度为n的矩阵必须放n个
// 根据规则 一行只能放一个 且必须有一个
// for循环遍历每一行 递归一次加一行
// 每一行找到数组中为零的位置 没有就继续遍历 直到遍历完
// 找到位置之后把该行 列 斜线 全部加1 表示这些位置不可用
// 为什么是加1 而不是等于1
// 因为 最后能返回的条件就是所递归的行数走到了最后 表示已经找到了一条路径
// 这时需要回溯 回溯的时候就需要把当前加1 的值减去
// 节点中在赋值的时候会出现交叉情况 如果直接置为零会把前面的部分已赋值的节点所改变
int[][] a = new int[n][n];
count(a, 0);
return nums;
}
public void count(int[][] a, int num) {
if (num == a.length) {
++nums;
return;
}
for (int i = 0; i < a.length; i++) {
if (a[i][num] == 0) {
addOne(a, i, num, 1);
count(a, num + 1);
addOne(a, i, num, -1);
}
}
}
public void addOne(int[][] a, int i, int j, int t) {
add1(a, i, j, t);
add2(a, i, j, t);
add3(a, i, 0, t);
add4(a, 0, j, t);
add5(a, i, j, t);
add6(a, i, j, t);
}
public void add1(int[][] a, int i, int j, int t) {
if (i < 0 || j < 0 || i > a.length - 1 || j > a[0].length - 1) {
return;
}
a[i][j] += t;
add1(a, --i, --j, t);
}
public void add6(int[][] a, int i, int j, int t) {
if (i < 0 || j < 0 || i > a.length - 1 || j > a[0].length - 1) {
return;
}
a[i][j] += t;
add6(a, ++i, --j, t);
}
public void add2(int[][] a, int i, int j, int t) {
if (i < 0 || j < 0 || i > a.length - 1 || j > a[0].length - 1) {
return;
}
a[i][j] += t;
add2(a, --i, ++j, t);
}
public void add3(int[][] a, int i, int j, int t) {
if (i < 0 || j < 0 || i > a.length - 1 || j > a[0].length - 1) {
return;
}
a[i][j] += t;
add3(a, i, ++j, t);
}
public void add4(int[][] a, int i, int j, int t) {
if (i < 0 || j < 0 || i > a.length - 1 || j > a[0].length - 1) {
return;
}
a[i][j] += t;
add4(a, ++i, j, t);
}
public void add5(int[][] a, int i, int j, int t) {
if (i < 0 || j < 0 || i > a.length - 1 || j > a[0].length - 1) {
return;
}
a[i][j] += t;
add5(a, ++i, ++j, t);
}
} import java.util.*;
public class Solution {
int count = 0;
public int Nqueen (int n) {
char[][] chars = new char[n][n];
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
chars[i][j] = '-';
}
}
backtrack(chars, n, 0);
return count;
}
public void backtrack(char[][] chars, int n, int i){
if(i==n){
count++;
return;
}
for(int j=0; j<n; j++){
if(!isValid(chars, i, j)) continue;
chars[i][j] = 'Q';
backtrack(chars, n, i+1);
chars[i][j] = '-';
}
}
// 合法性判断
public boolean isValid(char[][] chars, int x, int y){
for(int i=0; i<x; i++){
if(chars[i][y]=='Q') return false;
if(y-x+i>=0 && chars[i][y-x+i]=='Q') return false;
if(y+x-i< chars.length && chars[i][y+x-i]=='Q') return false;
}
return true;
}
} public class Solution {
int res = 0;
public int Nqueen (int n) {
//创建棋盘,并初始化填充'.'
char[][] board = new char[n][n];
for (char[] row : board) {
Arrays.fill(row, '.');
}
backtracking(board, 0);
return res;
}
void backtracking(char[][] board, int row) {
//遍历到叶子节点(即最后一层),记录结果并返回
if (row == board.length) {
res++;
return;
}
//在每一行的列中做选择
for (int col = 0; col < board[0].length; col++) {
//选择无效,判断当前列、左上和右上
if (!isValid(board, row, col)) {
continue;
}
//做选择
board[row][col] = 'Q';
//递归下一行
backtracking(board, row + 1);
//撤销选择
board[row][col] = '.';
}
}
//判断该位置是否可以放皇后:该列、左上和右上都没有皇后才可以
boolean isValid(char[][] board, int row, int col) {
//当前列
for (int i = 0; i < row; i++) {
if (board[i][col] == 'Q') {
return false;
}
}
//左上方
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0 ; i--, j--) {
if (board[i][j] == 'Q') {
return false;
}
}
//右上方
for (int i = row - 1, j = col + 1; i >= 0 && j < board[0].length; i--, j++) {
if (board[i][j] == 'Q') {
return false;
}
}
return true;
}
} // 烂代码,凑合看
import java.util.*;
public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
private static int counter =0;
public int Nqueen (int n) {
List<Pos> pool = new ArrayList<>();
//Integer counter = new Integer(0);
backtrack(n,pool,1);
return counter;
}
private void backtrack (int n,List<Pos>pool,int currRow) {
if (currRow==n+1) {
counter++;
return;
}
for (int c = 1; c <=n ; c++) {
if (!valid(pool,new Pos(currRow,c))) {
continue;
}
pool.add(new Pos(currRow,c));
backtrack(n,pool,currRow+1);
pool.remove(pool.size()-1);
}
}
private boolean valid(List<Pos>pool,Pos currPos) {
for (Pos pos : pool) {
if (pos.r==currPos.r || pos.c==currPos.c ||
currPos.c- currPos.r==pos.c- pos.r ||
currPos.c+ currPos.r== pos.c+ pos.r) {
return false;
}
}
return true;
}
class Pos {
public int r;
public int c;
public Pos(int r, int c) {
this.r = r;
this.c = c;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pos pos = (Pos) o;
return r == pos.r && c == pos.c;
}
@Override
public int hashCode() {
return Objects.hash(r, c);
}
}
} import java.util.*;
public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
int cnt =0;
public int Nqueen (int n) {
// write code here
char[][] chessboard = new char[n][n];
for (char[] c : chessboard) {
Arrays.fill(c, '.');
}
backTrack(n, 0, chessboard);
return cnt;
}
public void backTrack(int n, int row, char[][] chessboard) {
if (row == n) {
cnt++;
return;
}
for (int col = 0;col < n; ++col) {
if (isValid (row, col, n, chessboard)) {
chessboard[row][col] = 'Q';
backTrack(n, row+1, chessboard);
chessboard[row][col] = '.';
}
}
}
public boolean isValid(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;
}
} import java.util.*;
public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
// 记录多少种情况
int ans;
public int Nqueen(int n) {
//建立一个数组
int[] table = new int[n];
// 递归
dfs(0, n, table);
return ans;
}
private void dfs(int row, int n, int[] table) {
// 如果row 到达底部了 则是一种情况 直接返回
if (row == n) {
ans++;
return;
}
for (int col = 0; col < n; col++) {
boolean flag = true;
for (int i = 0; i < row; i++) {
// 如果每一行和每一列 相加 相减 列与列相等 则不符合情况 退出
if (table[i] == col || table[i] - i == col - row || table[i] + i == row + col) {
flag = false;
break;
}
}
if (flag) {
table[row] = col;
dfs(row + 1, n, table);
}
}
}
} 简单粗暴: DFS + 回溯
思路: 其实主要是判断正反对角线,放入一个元素之后,把不能放元素的位置加入到set集合中,然后遍历的时候,看是否在集合中,若在集合中,则表示不能放Q,若不在,则可以放,知道放入Q的数量和n维数组的长度相同即可。
正反对角线规律:可参看数学中坐标系
正对角线为:(0,0)、(1,1)、(2,2), 相差为0
反对角线为:(2,-2)(1,-1)、(0,0), 相加为0
import java.util.*;
/**
* N 皇后问题
*
* N皇后规则:所在行、列、对角线中不能存在元素
*
* 思路:DFS + 回溯
* 递归行,遍历列
*/
public class Solution {
private static int result = 0;
private static Set<Integer> columns = new HashSet<>(); // 列
private static Set<Integer> positiveDiagonal = new HashSet<>(); // 正对角线
private static Set<Integer> negativeDiagonal = new HashSet<>(); // 反对角线
/**
*
* @param n int整型 the n
* @return int整型
*/
public int Nqueen (int n) {
// write code here
dfs(0, n);
return result;
}
private void dfs(int row, int n) {
// 结束标志
if (row == n) {
result++;
return;
}
for (int i = 0; i < n; i++) {
// 判断该列中已经放过Q || 处于正反对角线上
// 正对角线为:(0,0)、(1,1)、(2,2), 相差为0
// 反对角线为:(2,-2)(1,-1)、(0,0), 相加为0
if (columns.contains(i) || positiveDiagonal.contains(row - i) || negativeDiagonal.contains(row + i)) {
continue;
}
columns.add(i);
positiveDiagonal.add(row - i);
negativeDiagonal.add(row + i);
dfs(row + 1, n);
negativeDiagonal.remove(row + i);
positiveDiagonal.remove(row - i);
columns.remove(i);
}
}
}
//向大佬学习
public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
//计数
private static Integer c=new Integer(0);
public int Nqueen (int n) {
// dfs遍历
formN(n);
return c;
}
//创建棋盘
public void formN(int n){
char[][] chess=new char[n][n];
for(int i=0;i<chess.length;i++)
for(int j=0;j<chess.length;j++)
chess[i][j]='a';
dfsN(chess,0);
}
//dfs遍历,按行寻找,若能找到底即x==n(chess.length)则计数加1
public void dfsN(char[][] chess,int x){
if(x==chess.length){
c++;
return;
}
for(int y=0;y<chess.length;y++){
if(findN(chess,x,y)){
chess[x][y]='b';
dfsN(chess,x+1);
chess[x][y]='a';//回溯
}
}
}
//按行+1的找,所以只需判断上面、左上、右上有无重复
private boolean findN(char[][] chess,int x,int y){
//up
for(int i=x-1;i>=0;i--){
if(chess[i][y]=='b'){return false;}
}
//upright
for(int i=x-1,j=y+1;i>=0&&j<chess.length;i--,j++){
if(chess[i][j]=='b'){return false;}
}
//upleft
for(int i=x-1,j=y-1;i>=0&&j>=0;i--,j--){
if(chess[i][j]=='b'){return false;}
}
return true;
}
} 评论区大佬好多
import java.util.*;
public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
Set<Integer> column = new HashSet<Integer>(); //标记列不可用
Set<Integer> posSlant = new HashSet<Integer>();//标记正斜线不可用
Set<Integer> conSlant = new HashSet<Integer>();//标记反斜线不可用
int result = 0;
public int Nqueen (int n) {
// write code here
compute(0, n);
return result;
}
private void compute(int i, int n){
if(i == n){
result++;
return;
}
for(int j = 0; j < n; j++){
if(column.contains(j) || posSlant.contains(i - j) || conSlant.contains(i + j)){
continue;
}
column.add(j);//列号j
posSlant.add(i - j);//行号i - 列号j 正斜线
conSlant.add(i + j);//行号i + 列号j 反斜线
compute(i + 1, n); //计算下一行
column.remove(j); //完成上一步递归计算后,清除
posSlant.remove(i - j);
conSlant.remove(i + j);
}
}
} static int count=0;//全局属性
static int arr[];
public int Nqueen (int n) {
// write code here
if(n==0)
return 0;
arr = new int[n];
put(arr,0,n);
return count;
}
public boolean judge(int arr[],int s){
for(int i=0;i<s;i++){
if(arr[s]==arr[i] || s-i==Math.abs(arr[s]-arr[i])){//遍历s以上元素,判断放置是否合理,不合理则回溯
return false;
}
}
return true;
}
public void put(int arr[],int i,int n){
if(i == n){//满足条件则通过
count++;//增加count的个数
return;
}
for(int j=0;j<n;j++){
arr[i]=j;//在第i+1行的j+1出放置
if(judge(arr,i)){//判断放置是否合理
put(arr,i+1,n);
}
}
} public class Solution {
/**
*
* @param n int整型 the n
* @return int整型
*/
public int res = 0; // 计数,作为返回结果
public int Nqueen (int n) {
// write code here
int[] graph = new int[n];
backTracking(0, graph);
return res;
}
public void backTracking(int n, int[] array){
if (n == array.length){
res += 1;
return ;
}
for (int i = 0; i < array.length; i++){ // 从第一列开始放置
array[n] = i; // 第n行皇后放在第i列
if (isConflict(n, array)){
backTracking(n + 1, array);
}else {
continue ;
}
}
}
public boolean isConflict(int n, int[] array){ // 判断第n行是否冲突
for (int i = 0; i < n; i++){
if (array[n] == array[i] || Math.abs(n - i) == Math.abs(array[n] - array[i])){
return false;
}
}
return true;
}
}