题目
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。等价于要求任何两个皇后都不能在同一行、同一列以及同一条斜线上
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
如图:黄色代表放置皇后的位置
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位
例如:
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
解题的思路:
1,首先我们以行为基准,我们放置了第一行,那么只能去第二行寻找可以放置皇后的位置,以此类推,指导最后一行,如果到最后一行都能将皇后放置进去,说明这是一个可行的方案,
2,首先一个皇后放在了第一行,那么,它所在的列,以及交叉线都不能放置皇后了,那么我们怎么用状态标识呢,那我们不妨每列,和两个交叉线都用一个集合存放,每列我们好表示,把第一列或者第二列放到集合里说明,这列被用了,那么两个交叉线怎么表示呢?
如图,当皇后放置在(1,2)这个位置:
左上向下的这条斜线:
它们的位置分别是(0,1),(1,2),(2,3)那么每个坐标里的行坐标减去列坐标,0-1 == 1-2 == 2-3 ==-1,正好是等值。
右上向下的这条斜线:
它们的位置分别是(0,3),(1,2),(2,1),(3,0),那么每个坐标里的值相加,0+3 == 1+2== 2+1 == 3+0 ==3 ,正好是等值。
哈哈,是不是很神奇,你们自己随便找个位置试一下,是不是都有一个等值,并且都不重复,那么我们就把相应的值加入到集合里面,是不是就能标识,是不是这些位置都不能放置皇后了
3,接着我们就是用回溯去找每一种可能
知道上面的几点,代码就好理解了呢,现在我们去看一下,代码,有很多可以改良的地方,请大家多多指教
public static List<List<String>> solveNQueens(int n) {
//存放最终答案的集合
List<List<String>> list = new ArrayList<List<String>>();
//标识那些列不能被用了,不能放置皇后了
List<Integer> cloums = new ArrayList<Integer>();
//标识右上向下的斜线,不能放置皇后了
List<Integer> rDiagonals = new ArrayList<Integer>();
//标识左上向下的斜线,不能放置皇后了
List<Integer> lDiagonals = new ArrayList<Integer>();
List<int[]> result = new ArrayList<>();
//用于标识每一组(行),-1标识没有放置皇后,1标识为皇后
int[] queens = new int[n];
Arrays.fill(queens, -1);
return dolt(n, queens, result, list, cloums, rDiagonals, lDiagonals, 0);
}
public static List<List<String>> dolt(int n, int[] queens, List<int[]> result, List<List<String>> list, List<Integer> cloums, List<Integer> rDiagonals, List<Integer> lDiagonals, int row) {
if (row == n) {
list.add(transFromToString(result));
return list;
}
for (int col = 0; col < n; col++) {
if (cloums.contains(col)) {
continue;
}
if (rDiagonals.contains(row + col)) {
continue;
}
if (lDiagonals.contains(row - col)) {
continue;
}
//值为1时表明该位置是皇后
queens[col] = 1;
//为了将该组存入集合,需要新new一个数组,利用深拷贝,把queens数组里面的值拷贝过来,当queens重置时不会影响到该数组
int[] replaceQueen = new int[n];
replaceQueen = queens.clone();
result.add(replaceQueen);
//将列,两个交叉线,标识为不能在放置皇后了
cloums.add(col);
rDiagonals.add(row + col);
lDiagonals.add(row - col);
//重置queens
Arrays.fill(queens, -1);
dolt(n, queens, result, list, cloums, rDiagonals, lDiagonals, row + 1);
//重置状态
//list.remove(),有两个方法,一个是list.remove(Object object)删除的是元素,一个是list.remove(Integer integer)删除的是该索引
result.remove(result.size() - 1);
cloums.remove(new Integer(col));
rDiagonals.remove(new Integer(row + col));
lDiagonals.remove(new Integer(row - col));
}
return list;
}
public static List<String> transFromToString(List<int[]> queens) {
List list = new ArrayList();
for (int[] a : queens) {
char[] ch = new char[a.length];
Arrays.fill(ch, '.');
for (int i = 0; i < a.length; i++) {
if (a[i] != -1) {
ch[i] = 'Q';
}
}
list.add(new String(ch));
}
return list;
}