题目
解题思路
回溯:遍历棋盘,每次选择一个格子放皇后,然后封掉皇后可行的路,再接着往下找可放皇后的格子,找不到了就回去重新找下一个
class Solution {
private List<List<String>> resList = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
deepChoice(createMap(n), n, new ArrayList<>(), 0);
return resList;
}
private char[][] createMap(int n){
char[][] map = new char[n][n];
for (int i = 0; i < n; i++) {
Arrays.fill(map[i], '.');
}
return map;
}
private static class Pos{
int i,j;
public Pos(int i, int j) {
this.i = i;
this.j = j;
}
@Override
public boolean equals(Object obj) {
if (! (obj instanceof Pos)) {
return false;
}
Pos objPos = (Pos)obj;
return objPos.i == i && objPos.j == j;
}
}
private void deepChoice(char[][] map, int n, List<Pos> posList, int startI) {
for (int i = startI; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
if (map[i][j] == '.') {
posList.add(new Pos(i, j));
if (n - 1 == 0) {
char[][] map1 = createMap(map.length);
for (Pos pos: posList) {
map1[pos.i][pos.j] = 'Q';
}
List<String> tempList = new ArrayList<>();
for (int k = 0; k < map.length; k++) {
StringBuilder sb = new StringBuilder();
for (char ch: map1[k]) {
sb.append(ch);
}
tempList.add(sb.toString());
}
if (!resList.contains(tempList)) {
resList.add(tempList);
}
posList.remove(posList.size() - 1);
continue;
}
List<Pos> recover = new ArrayList<>();
toWhat(map, i, j, '#', recover);
deepChoice(map, n - 1, posList, i);
posList.remove(posList.size() - 1);
toWhat(map, i, j, '.', null);
// 恢复已经被占用的位置
for (Pos pos: recover) {
map[pos.i][pos.j] = '#';
}
map[i][j] = '.';
}
}
}
}
private void toWhat(char[][] map, int i, int j, char ch, List<Pos> recover) {
for (int tJ = 0; tJ < map.length; tJ++) {
// 左右
change(map, ch, recover, i, tJ);
// 上下
change(map, ch, recover, tJ, j);
// 右上
change(map, ch, recover, i + tJ, j + tJ);
// 左下
change(map, ch, recover, i - tJ, j - tJ);
// 左上
change(map, ch, recover, i + tJ, j - tJ);
// 右下
change(map, ch, recover, i - tJ, j + tJ);
}
}
private void change(char[][] map, char ch, List<Pos> recover, int i, int j) {
Pos temp = new Pos(i,j);
if (temp.i < 0 || temp.i >= map.length || temp.j < 0 || temp.j >= map[0].length) {
return;
}
// 要占用 且 该位置是已经被占用
if (ch == '#' && map[temp.i][temp.j] == '#' && !recover.contains(temp)) {
recover.add(temp);
return;
}
map[temp.i][temp.j] = ch;
}
}
优化
前面的方式是预占好位置,判断是否可坐,再恢复位置,其中预占位置和恢复位置花费了多余的时间,换个思路,不预占位置,每次判断该点的左上,正上,右上是否有皇后,就可以确定皇后是否可放在该位置,而且恢复也只需要恢复皇后占用的位置。
class Solution {
private final List<List<String>> resList = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
char[][] map = new char[n][n];
for (int i = 0; i < n; i++) {
Arrays.fill(map[i], '.');
}
deepChoice(map,0, n);
return resList;
}
private void deepChoice(char[][] map, int startI, int n) {
if (n == 0) {
List<String> tempList = new ArrayList<>();
for (char[] chars : map) {
StringBuilder sb = new StringBuilder();
for (char ch : chars) {
sb.append(ch);
}
tempList.add(sb.toString());
}
resList.add(tempList);
return;
}
for (int i = startI; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
if (judgeCan(map, i, j)) {
map[i][j] = 'Q';
deepChoice(map, i + 1, n - 1);
map[i][j] = '.';
}
}
}
}
private boolean judgeCan(char[][] map, int i, int j) {
if (map[i][j] == 'Q') {
return false;
}
// 正上
int t = i - 1;
while (t >= 0) {
if (map[t--][j] == 'Q') {
return false;
}
}
// 左上
t = 1;
while (i - t >= 0 && j - t >= 0) {
if (map[i - t][j - t] == 'Q') {
return false;
}
t++;
}
// 右上
t = 1;
while (i - t >= 0 && j + t < map.length) {
if (map[i - t][j + t] == 'Q') {
return false;
}
t++;
}
return true;
}
}