问题描述
- leetcode N 皇后问题。要求在 N*N 的方格中放入皇后 'Q' ,要求皇后之间上下左右、斜对角均不能相互攻击。
- 也就是皇后之间出现的位置是有限制的。同一行、列、斜线上只能出现一个皇后,且每一行必有一个皇后。
- 给定 N,求出所有的不重复的解集。返回值类型为 List<List<String>>。
解决思路
- 又是 N*N 的方格,需要对每个位置进行皇后的填充,自然想到利用 DFS 进行处理。
- 在当前位置进行判断是否可以填入皇后时,需要判断该列、该位置所在的左斜线、右斜线上是否还有其他的皇后,有则跳过,无则添加。leetcode 官方题解上给出了一种巧妙的判断斜线上是否有皇后的方法,对于左斜线,可以看成是一条直线:x+y = Constant。 抓住横坐标 + 纵坐标的和为常数这个特点,就可以很好的进行判断了,右斜线同样如此。
- 先将所有的皇后所在的下标索引找出来,最后再根据每一个下标索引生成字符串。如在 N = 4 的时候,先求出这样的结果:list:[ [1302], [2031] ] 。
代码
1 public class Solution {
2
3 private static Set<Integer> col = new HashSet<>();
4 private static Set<Integer> pie = new HashSet<>();
5 private static Set<Integer> na = new HashSet<>();
6
7 public static List<List<String>> solveNQueens(int n) {
8 List<List<String>> res = new ArrayList<>();
9 List<List<Integer>> temp = new ArrayList<>();
10
11 DFS(n, 0, new ArrayList<>(), temp);
12 for (List<Integer> a: temp) {
13 for(int b: a) {
14 char[] curChar = new char[n];
15 Arrays.fill(curChar,'.');
16 curChar[b] = 'Q';
17 cur.add(new String(curChar));
18 }
19 res.add(cur);
20 }
21
22 return res;
23
24 }
25
26 public static void DFS(int n, int row, ArrayList<Integer> curRes, List<List<Integer>> res) {
27 // 递归终止条件
28 if (row >= n) {
29 // res.add(curRes); 注意这里如果不重新声明一个ArrayList的话,后面获取的
30 //ArrayList会将之前的结果覆盖。
31
32 res.add(new ArrayList<>(curRes));
33
34 // System.out.println("=====下面是DFS中的res遍历====");
35 // for(List a: res) {
36 // for(int i=0; i< a.size(); i++) {
37 // System.out.print(a.get(i));
38 // }
39 // System.out.println();
40 // }
41 // System.out.println("--------------------");
42
43 return;
44 }
45
46 for(int i=0; i<n; i++) {
47 // 对该行,所有的列遍历
48 if (col.contains(i) || pie.contains(i+row) || na.contains(i-row)) { continue; }
49
50 // 符合条件:继续走
51 col.add(i);
52 pie.add(i+row);
53 na.add(i-row);
54 curRes.add(i);
55
56 DFS(n, row+1, curRes, res);
57
58 // 回到上一层,修正
59 curRes.remove(curRes.size()-1);
60 col.remove(i);
61 pie.remove(i+row);
62 na.remove(i-row);
63 }
64 }
65 }
注意事项
在没有泛型类时,原始的 ArrayList 类提供的 get 方法别无选择只能返回 Object,因此,get 方法的调用者必须对返回值进行类型转换。
啥意思呢?看下面的代码
1 List<List<Integer>> test = new ArrayList<>();
2 List<Integer> a = new ArrayList<>();
3 a.add(1);
4 a.add(2);
5
6 List<Integer> b = new ArrayList<>();
7 b.add(4);
8 b.add(5);
9 b.add(6);
10
11 test.add(a);
12 test.add(b);
13
14 for (List e: test) {
15 for(Object o: e) {
16 // 这里为何是Object类型???虽然声明的时候是Integer类型,但是e没有声明泛型类
17 // 在没有泛型类时,原始的ArrayList类提供的get方法返回的只能是Object类型,get方法调用者必须对返回值进行类型转换。
18 System.out.println((int)o);
19 }
20 System.out.println("----------");
21 }
如何解决呢,声明泛型类
1 for (List<Integer> e: test) {
2 for(int o: e) {
3 System.out.println(o);
4 }
5 System.out.println("----------");
6 }