回溯算法
- 實際上就是一個決策樹的遍歷過程
- 路徑:已經做出的選擇
- 選擇列表:是你當前可以做的選擇
- 結束條件:到達決策樹底層,無法再做選擇的條件
- 經典問題:【全排列】【N皇后問題】
1. 全排列問題
https://imgconvert.csdnimg.cn/aHR0cHM6Ly9tbWJpei5xcGljLmNuL3N6X21tYml6X2pwZy9naWJrSXowTVZxZEYxdW1BZHlYdVBxNTRpYnc3WDIzbW5hR0ppYW1idHBxYzR2a2hzcVpZb0VaV2lhbmlic0ltdER2bVhSTUNKdVVCOGdrTGZDSlZBUUR0MlJBLzY0MD93eF9mbXQ9anBlZw?x-oss-process=image/format,png
// 全排列問題
public class Backtrack {
List<List<Integer>> res = new LinkedList<>();
List<List<Integer>> permute(int[] nums) {
LinkedList<Integer> list = new LinkedList<>();
backtrack(nums, list);
return res;
}
?
void backtrack(int[] nums, LinkedList<Integer> list) {
if (nums.length == list.size()) {
res.add(list);
return;
}
for (int i = 0; i < nums.length - 1; i++) {
if (list.contains(nums[i])) {
continue;
}
// 做決策
list.add(nums[i]);
// 進入下一層決策樹
backtrack(nums, list);
// 取消決策
list.removeLast();
}
}
}
2. N皇后問題
給你一個NxN的期盼,讓你放置N個皇后,使得他們不能互相攻擊
皇后可以攻擊同一行,同一列,左上左下,右上右下 四個方向的任意單位
-
解法也就是上述全排列方案的適當調整
- 添加了isValid()的函數校驗是否有皇后沖突
- 初始化了一個字符串鏈表棋盤
public class Backtrack {
List<List<String>> queueMatrix = new LinkedList<>();
List<String> board = new LinkedList<>();
int n = 0;
List<List<String>> solveNQueens(int n) {
this.n = n;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) sb.append('.');
for (int i = 0; i < n; i++) board.add(sb.toString());
queenBacktrack( 0);
return queueMatrix;
}
void queenBacktrack(int row) {
if (row == n) {
// 結束了一次決策樹(全排列)
queueMatrix.add(new LinkedList<>(board));
return;
}
for (int col = 0; col < n; col++) {
if (!isValid(row, col)) {
continue;
}
// 合法,做決策
StringBuilder sb = new StringBuilder(board.get(row));
sb.setCharAt(col, 'Q');
board.set(row, sb.toString());
// 遞歸
queenBacktrack(row + 1);
// 回退
StringBuilder sb2 = new StringBuilder(board.get(row));
sb2.setCharAt(col, '.');
board.set(row, sb2.toString());
}
}
boolean isValid(int row, int col) {
for (int i = 0; i < row; i++) {
// 上面不能有Q
if (board.get(i).charAt(col) == 'Q') {
return false;
}
}
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
// 左上方,不能有Q
if (board.get(i).charAt(j) == 'Q') {
return false;
}
}
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
// 右上方,不能有Q
if (board.get(i).charAt(j) == 'Q') {
return false;
}
}
return true;
}
}