一、概念
回溯法是一种优选搜索法,按照优先条件深度优先搜索,以达到目标。当搜索到某一步时,发现原先选择并不是最优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术成为回溯法,而满足回溯条件的某个状态成为“回溯点”
二、思想
回溯法是从初始状态出发,按照深度优先搜索的方式,根据产生子节点的条件约束,搜索问题的解。当发现当前节点不满足条件时,就回溯,尝试其他的路径。回溯法是一种“能进则进,进不了则换,换不了则退”
回溯法的核心是递归,递归一定要会有个函数出口,否则会有死循环。
三、应用示例
1、N皇后
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> res = new ArrayList<>();
int[] queen = new int[n];
helper(queen, 0, n, res);
return res;
}
private void helper(int[] queen, int row, int n, List<List<String>> res) {
for (int i = 0; i < n; i++) {
queen[row] = i;
if (place(queen, row)) {
if (row == n - 1) {
addToRes(queen, res);
} else {
helper(queen, row + 1, n, res);
}
}
}
}
private boolean place(int[] queen, int row) {
for (int i = 0; i < row; i++) {
if (queen[i] == queen[row] || Math.abs(queen[i] - queen[row]) == row - i) {
return false;
}
}
return true;
}
private void addToRes(int[] queen, List<List<String>> res) {
List<String>tmp=new ArrayList<>();
for (int i = 0; i < queen.length; i++) {
StringBuffer sb=new StringBuffer();
for (int j=0;j<queen.length;j++){
if (queen[i] == j) {
sb.append("Q");
}
else {
sb.append(".");
}
}
tmp.add(sb.toString());
}
res.add(tmp);
}
}
class Solution {
private int count = 0;
public int totalNQueens(int n) {
int[] queen=new int[n];
helper(queen,0,n);
return count;
}
private void helper(int[] queen, int row, int n) {
for (int i = 0; i < n; i++) {
queen[row] = i;
if (place(queen, row)) {
if (row == n - 1) {
count++;
} else {
helper(queen, row + 1, n);
}
}
}
}
private boolean place(int[] queen, int row) {
for (int i = 0; i < row; i++) {
if (queen[i] == queen[row] || Math.abs(queen[i] - queen[row]) == row - i) {
return false;
}
}
return true;
}
}
2、数独
class Solution {
public void solveSudoku(char[][] board) {
solveSudokuTmp(board);
}
public boolean solveSudokuTmp(char[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == '.') {
for (char c = '1'; c <= '9'; c++) {
if (isValid(board, i, j, c)) {
board[i][j] = c;
if (solveSudokuTmp(board)) {
return true;
} else {
board[i][j] = '.';
}
}
}
return false;
}
}
}
return true;
}
private boolean isValid(char[][] board, int i, int j, char c) {
for (int k = 0; k < 9; k++) {
if (board[i][k] == c) {
return false;
}
if (board[k][j] == c) {
return false;
}
if (board[3 * (i / 3) + k / 3][3 * (j / 3) + k % 3] == c) {
return false;
}
}
return true;
}
}
还有很多经典例子,不断更新中