前言
LeetCode51、52 屬於經典的八皇后問題,前者是輸入路徑總數,後者是計算路徑總數,可以說明白了51題,52題只需要在輸出一個結果那裏換成累加器就好了。此題主要是用了回溯法
,其實就是深搜,如果一條路能走通就走到底,如果走到某一步走錯了,回到上個岔路口換條路走就好了。
問題描述
先看51題
n 皇后問題研究的是如何將 n 個皇后放置在 n×n 的棋盤上,並且使皇后彼此之間不能相互攻擊。
給定一個整數 n,返回所有不同的 n 皇后問題的解決方案。
每一種解法包含一個明確的 n 皇后問題的棋子放置方案,該方案中 ‘Q’ 和 ‘.’ 分別代表了皇后和空位。
解題思路
利用回溯法,從第一行第一個位置開始放置第一個皇后,然後不斷向下一行每一個格嘗試放置皇后,如果可以放置就進行下一行直到第n行,如果不可以,回到上一行,把上一行的皇后嘗試換個位置,繼續。
代碼實現
// 棋盤,放皇后
public static int[][] arry;
// 棋盤大小
private static int size;
// 結果
private static List<List<String>> result = new ArrayList<>();
// 棋盤大小
public List<List<String>> solveNQueens(int n) {
// 棋盤
size = n;
arry = new int[n][n];
// 數據初始化,有A錯一次
result = new ArrayList<>();
// 邊界條件,A錯一次
if (n == 1) {
List<String> one = new ArrayList<>();
one.add("Q");
result.add(one);
System.out.println(result);
return result;
}
findQueen(0);
System.out.println(result);
return result;
}
// 尋找皇后節點
public static void findQueen(int i) {
// 八皇后的解
if (i > size - 1) {
List<String> list = new ArrayList<>();
for (int x = 0; x < size; x++) {
StringBuffer stringBuffer = new StringBuffer();
for (int y = 0; y < size; y++) {
if (arry[x][y] == 1) {
stringBuffer.append("Q");
} else {
stringBuffer.append(".");
}
}
list.add(stringBuffer.toString());
}
result.add(list);
return;
}
// 深度回溯,遞歸算法
for (int m = 0; m < size; m++) {
// 檢查皇后擺放是否合適
if (check(i, m)) {
arry[i][m] = 1;
findQueen(i + 1);
// 清零,以免回溯的時候出現髒數據
arry[i][m] = 0;
}
}
}
// 判斷節點是否合適
public static boolean check(int k, int j) {
// 檢查列衝突
for (int i = 0; i < size; i++) {
if (arry[i][j] == 1) {
return false;
}
}
// 檢查左對角線
for (int i = k - 1, m = j - 1; i >= 0 && m >= 0; i--, m--) {
if (arry[i][m] == 1) {
return false;
}
}
// 檢查右對角線
for (int i = k - 1, m = j + 1; i >= 0 && m < size; i--, m++) {
if (arry[i][m] == 1) {
return false;
}
}
return true;
}
52解題思路
直接上代碼,只需要把51題輸入皇后位置圖樣的地方換上累加器即可。
// 棋盤,放皇后
public static int[][] arry;
// 棋盤大小
private static int size;
// 結果
private static int count = 0;
// 棋盤大小
public int totalNQueens(int n) {
// 棋盤
size = n;
arry = new int[n][n];
count = 0;
// 邊界條件
if (n == 1) {
return 1;
}
findQueen(0);
return count;
}
// 尋找皇后節點
public static void findQueen(int i) {
// 八皇后的解
if (i > size - 1) {
count++;
return;
}
// 深度回溯,遞歸算法
for (int m = 0; m < size; m++) {
// 檢查皇后擺放是否合適
if (check(i, m)) {
arry[i][m] = 1;
findQueen(i + 1);
// 清零,以免回溯的時候出現髒數據
arry[i][m] = 0;
}
}
}
// 判斷節點是否合適
public static boolean check(int k, int j) {
// 檢查列衝突
for (int i = 0; i < size; i++) {
if (arry[i][j] == 1) {
return false;
}
}
// 檢查左對角線
for (int i = k - 1, m = j - 1; i >= 0 && m >= 0; i--, m--) {
if (arry[i][m] == 1) {
return false;
}
}
// 檢查右對角線
for (int i = k - 1, m = j + 1; i >= 0 && m < size; i--, m++) {
if (arry[i][m] == 1) {
return false;
}
}
return true;
}