52. N 皇后 II
题目:
思路:
【1】皇后的走法是:可以横直斜走,格数不限。因此要求皇后彼此之间不能相互攻击,等价于要求任何两个皇后都不能在同一行、同一列以及同一条斜线上。
【2】基于集合的回溯(模拟的方式)
【3】基于位运算的回溯
代码展示:
【2】基于集合的回溯(模拟的方式)
//时间3 ms 击败 37.25% //内存39.1 MB 击败 27.81% //时间复杂度:O(N!),其中 N 是皇后数量。 //空间复杂度:O(N),其中 N 是皇后数量。 //空间复杂度主要取决于递归调用层数以及三个集合,递归调用层数不会超过 N,每个集合的元素个数都不会超过 N。 class Solution { public int totalNQueens(int n) { Set<Integer> columns = new HashSet<Integer>(); Set<Integer> diagonals1 = new HashSet<Integer>(); Set<Integer> diagonals2 = new HashSet<Integer>(); return backtrack(n, 0, columns, diagonals1, diagonals2); } /** * * @param n 表示在 n*n的棋盘上需要放N个皇后 * @param row * 记录每一列以及两个方向的每条斜线上是否有皇后 * @param columns * @param diagonals1 * @param diagonals2 * @return */ public int backtrack(int n, int row, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2) { // 如果能达到最低行就返回一次成功的排列 if (row == n) { return 1; } else { int count = 0; // 看这一行的皇后可以放在哪个列 for (int i = 0; i < n; i++) { // 如果列出现重复,那么就跳过 if (columns.contains(i)) { continue; } // 斜线为从左上到右下方向,同一条斜线上的每个位置满足行下标与列下标之差相等 int diagonal1 = row - i; if (diagonals1.contains(diagonal1)) { continue; } // 斜线为从右上到左下方向,同一条斜线上的每个位置满足行下标与列下标之和相等 int diagonal2 = row + i; if (diagonals2.contains(diagonal2)) { continue; } // 添加标记 columns.add(i); diagonals1.add(diagonal1); diagonals2.add(diagonal2); // 递归下一行看看皇后放哪 count += backtrack(n, row + 1, columns, diagonals1, diagonals2); // 删除标记对集合进行恢复 columns.remove(i); diagonals1.remove(diagonal1); diagonals2.remove(diagonal2); } return count; } } }
【3】基于位运算的回溯
//这个本质上是利用数值的进制位来替代 集合达到优化的效果 //时间0 ms 击败 100% //内存38.1 MB 击败 74.40% //时间复杂度:O(N!),其中 N 是皇后数量。 //空间复杂度:O(N),其中 N 是皇后数量。 //由于使用位运算表示,因此存储皇后信息的空间复杂度是 O(1), //空间复杂度主要取决于递归调用层数,递归调用层数不会超过 N。 class Solution { public int totalNQueens(int n) { return solve(n, 0, 0, 0, 0); } public int solve(int n, int row, int columns, int diagonals1, int diagonals2) { if (row == n) { return 1; } else { int count = 0; int availablePositions = ((1 << n) - 1) & (~(columns | diagonals1 | diagonals2)); while (availablePositions != 0) { int position = availablePositions & (-availablePositions); availablePositions = availablePositions & (availablePositions - 1); count += solve(n, row + 1, columns | position, (diagonals1 | position) << 1, (diagonals2 | position) >> 1); } return count; } } }