|
| 1 | +# 题目描述(困难难度) |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +和[上一题](https://leetcode.windliang.cc/leetCode-51-N-Queens.html)一样,只不过这次不需要返回所有结果,只需要返回有多少个解就可以。 |
| 6 | + |
| 7 | +# 解法一 |
| 8 | + |
| 9 | +我们直接把上道题的 ans 的 size 返回就可以了,此外 currentQueen.size ( ) == n 的时候,也不用去生成一个解了,直接加一个数字占位。 |
| 10 | + |
| 11 | +```java |
| 12 | +public int totalNQueens(int n) { |
| 13 | + List<Integer> ans = new ArrayList<>(); |
| 14 | + backtrack(new ArrayList<Integer>(), ans, n); |
| 15 | + return ans.size(); |
| 16 | +} |
| 17 | + |
| 18 | +private void backtrack(List<Integer> currentQueen, List<Integer> ans, int n) { |
| 19 | + if (currentQueen.size() == n) { |
| 20 | + ans.add(1); |
| 21 | + return; |
| 22 | + } |
| 23 | + for (int col = 0; col < n; col++) { |
| 24 | + if (!currentQueen.contains(col)) { |
| 25 | + if (isDiagonalAttack(currentQueen, col)) { |
| 26 | + continue; |
| 27 | + } |
| 28 | + currentQueen.add(col); |
| 29 | + backtrack(currentQueen, ans, n); |
| 30 | + currentQueen.remove(currentQueen.size() - 1); |
| 31 | + } |
| 32 | + |
| 33 | + } |
| 34 | + |
| 35 | +} |
| 36 | + |
| 37 | +private boolean isDiagonalAttack(List<Integer> currentQueen, int i) { |
| 38 | + int current_row = currentQueen.size(); |
| 39 | + int current_col = i; |
| 40 | + for (int row = 0; row < currentQueen.size(); row++) { |
| 41 | + if (Math.abs(current_row - row) == Math.abs(current_col - currentQueen.get(row))) { |
| 42 | + return true; |
| 43 | + } |
| 44 | + } |
| 45 | + return false; |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +时间复杂度: |
| 50 | + |
| 51 | +空间复杂度: |
| 52 | + |
| 53 | +# 解法二 |
| 54 | + |
| 55 | +参考[这里](https://leetcode.com/problems/n-queens-ii/discuss/20048/Easiest-Java-Solution-(1ms-98.22))。 |
| 56 | + |
| 57 | +既然不用返回所有解,那么我们就不需要 currentQueen 来保存当前已加入皇后的位置。只需要一个 bool 型数组,来标记列是否被占有就可以了。 |
| 58 | + |
| 59 | +由于没有了 currentQueen,所有不能再用之前 isDiagonalAttack 判断对角线冲突的方法了。我们可以观察下,对角线元素的情况。 |
| 60 | + |
| 61 | + |
| 62 | + |
| 63 | +可以发现对于同一条副对角线,row + col 的值是相等的。 |
| 64 | + |
| 65 | +对于同一条主对角线,row - col 的值是相等的。 |
| 66 | + |
| 67 | +我们同样可以用一个 bool 型数组,来保存当前对角线是否有元素,把它们相加相减的值作为下标。 |
| 68 | + |
| 69 | +对于 row - col ,由于出现了负数,所以可以加 1 个 n,由 [ - 3, 3 ] 转换为 [ 1 , 7 ] 。 |
| 70 | + |
| 71 | +```java |
| 72 | +public int totalNQueens(int n) { |
| 73 | + List<Integer> ans = new ArrayList<>(); |
| 74 | + boolean[] cols = new boolean[n]; // 列 |
| 75 | + boolean[] d1 = new boolean[2 * n]; // 主对角线 |
| 76 | + boolean[] d2 = new boolean[2 * n]; // 副对角线 |
| 77 | + return backtrack(0, cols, d1, d2, n, 0); |
| 78 | +} |
| 79 | + |
| 80 | +private int backtrack(int row, boolean[] cols, boolean[] d1, boolean[] d2, int n, int count) { |
| 81 | + if (row == n) { |
| 82 | + count++; |
| 83 | + } else { |
| 84 | + for (int col = 0; col < n; col++) { |
| 85 | + int id1 = row - col + n; //主对角线加 n |
| 86 | + int id2 = row + col; |
| 87 | + if (cols[col] || d1[id1] || d2[id2]) |
| 88 | + continue; |
| 89 | + cols[col] = true; |
| 90 | + d1[id1] = true; |
| 91 | + d2[id2] = true; |
| 92 | + count = backtrack(row + 1, cols, d1, d2, n, count); |
| 93 | + cols[col] = false; |
| 94 | + d1[id1] = false; |
| 95 | + d2[id2] = false; |
| 96 | + } |
| 97 | + |
| 98 | + } |
| 99 | + return count; |
| 100 | +} |
| 101 | + |
| 102 | +``` |
| 103 | + |
| 104 | +时间复杂度: |
| 105 | + |
| 106 | +空间复杂度: |
| 107 | + |
| 108 | +# 总 |
| 109 | + |
| 110 | +和上一题相比,通过三个 bool 型数组来标记是否占有,不存储具体的位置,从而解决了这道题。 |
0 commit comments