本文已参与「新人创作礼」活动,一起开启掘金创作之路
(5) N - 皇后问题
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例 1:
输入:n = 4 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 解释:如上图所示,4 皇后问题存在两个不同的解法。 示例 2:
输入:n = 1 输出:[["Q"]]
提示:
1 <= n <= 9
N-皇后问题是可以通过回溯来解决,其实有点类似dfs递归寻找排列型枚举,排列型枚举本质上也是用到了回溯,即返回到上一个状态。N*N行格子,皇后无法在斜角和十字里遇到皇后,即每一行只能出现一个皇后,那我们就按行来进行枚举,在第一行放置完皇后后,将该点十字及斜角上的点都设置为可攻击的点,即设置为1,然后可以进入下一行,找到不是1的格子,放置皇后,同理及下,当遇到某一行不可放置皇后后,证明上一步是不可放置的点,则返回上一层寻找下一个可以放置的点,继续进行,若仍然无法放置皇后,则需要返回到可以放置的点后,才可以继续往下进行。
这里设计到的知识点是回溯,即回到上一个状态,那我们就需要将上一个状态记住,在无法到达或者下层已经搜寻结束,回到上一个状态。
这个过程遇到的问题有:
(1) List集合如何初始化,及如何构造二维List集合
如下:List<List l = new ArrayList<List();
初始化一维数组后,仍然需要初始化二维数组,这里我采用加入新的List
l.add(new ArrayList());
(2)数组的toString方法,并非是将数组内的元素转化为String类型,若要转化为String类型,需要使用String.valueOf(char[]);
(3)浅拷贝和深拷贝问题,若直接进行集合类直接的赋值的话,因为类是引用型变量,存的是指针(Java中无指针,只是借以说明),如果想要深拷贝的话,就涉及到ArrayList的构造函数,使用new ArrayList<>(List l),可以l为模板new 出一个新的ArrayList,且如果要使用到集合的copy函数的时候(collections.copy(desk,src)
//第一个参数是目的集合,第二个参数是源集合 static void copy(List<? super T> dest, List<? extends T> src) 将所有元素从一个列表复制到另一个列表中。
ArrayList声明时默认的元素个数是0,只有进行add(),remove()操作时size()的大小才有相应的变化。 进行集合复制时,一要声明目的集合的元素的个数,并且要等于或者大于源集合的元素的个数。 如果不声明或者小于源集合的元素个数,这样就会报错,报下标界的异常(java.lang.IndexOutOfBoundsException)。
import java.io.*;
import java.util.*;
public class Main{
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static int[] dx = {-1,1,0,0,-1,-1,1,1};
public static int[] dy = {0,0,-1,1,-1,1,-1,1};
public static List<List<String>> solveNQueens(int n){
List<List<String>> solve = new ArrayList<List<String>>();
List<List<Integer>> attack = new ArrayList<List<Integer>>();
List<String> queen = new ArrayList<String>();
char [] temp = new char[n];
Arrays.fill(temp,'.');
for(int i = 0; i < n; ++i) {
attack.add(new ArrayList<Integer>());
for(int j = 0; j < n; ++j) {
attack.get(i).add(0);
}
queen.add(String.valueOf(temp));
}
backtrack(0,n,queen,attack,solve);
return solve;
}
public static void backtrack(int k,int n,List<String> queen,
List<List<Integer>> attack,List<List<String>> solve) {
if(k == n) {
solve.add(new ArrayList<String>(queen));
return ;
}
for(int i = 0; i < n; ++i) {
if(attack.get(k).get(i) == 0) {
//1.ArrayList构造函数的问题
//2.Collections.copy复制函数的问题
//3.如何将一个进行集合的深拷贝
List<List<Integer>> temp = new ArrayList<List<Integer>>();
for(int j = 0; j < n; ++j) {
temp.add(new ArrayList<Integer>(attack.get(j)));
}
queen.set(k, replaceString(queen.get(k),i,'Q'));
put_queen(k,i,attack);
backtrack(k + 1,n,queen,attack,solve);
queen.set(k, replaceString(queen.get(k),i,'.'));
Collections.copy(attack,temp);
}
}
}
public static String replaceString(String s,int i,char c) {
char[] array = s.toCharArray();
array[i] = c;
return String.valueOf(array);
}
public static void put_queen(int x,int y,List<List<Integer>> attack) {
attack.get(x).set(y, 1);
for(int i = 0; i < attack.size(); ++i) {
for(int j = 0; j < 8; ++j) {
int x1 = x + i * dx[j];
int y1 = y + i * dy[j];
if(x1 >= 0 && x1 < attack.size() && y1 >=0 && y1 < attack.size()) {
attack.get(x1).set(y1, 1);
}
}
}
}
public static void main(String[] args) throws Exception{
String[] str = in.readLine().split(" ");
int n = Integer.parseInt(str[0]);
List<List<String>> result = solveNQueens(n);
for(List l: result) {
for(int i = 0; i < l.size(); i++) {
out.write(l.get(i) + "\n");
}
}
in.close();
out.close();
}
}
\