框架
int main(){
finalresult = [] // 存放答案的所有种情况
backtrack(路径,1/选择列表) // 从第一层开始找,路径为当前正在寻找的某一种答案的记录
}
// 回溯-递归
void backtrack(路径,深度/选择列表)
if( (深度)满足结束条件/选择列表为空)
finalresult.add(路径) // 递归到了最深的一层,此时找到了一张答案,将其存储在finalresult中
return
for 选择 in 选择列表: // 遍历可以选择的所有情况
做选择(并判断当前选择是否满足情况 ifxxx continue)
backtrack(路径, 深度+1 /新选择列表)
撤销选择
}
路径:当前搜索记录的一条路径
深度:搜索的进度(树的深度)
下面是完全利用上述框架实现的两道经典例题
解决全排列问题
LeetCode地址:https://leetcode.cn/problems/permutations/
package leetcode.editor.cn;
import javax.sound.midi.Track;
import java.util.*;
/**
* 全排列
* @author WZP
* @date 2023-03-21 16:46:06
*/
public class P46_Permutations{
public static void main(String[] args) {
//测试代码
Solution solution = new P46_Permutations().new Solution();
solution.permute(new int[]{1, 2, 3}); // 测试1 2 3 全排列
}
//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
List<List<Integer>> finalresult = new ArrayList<List<Integer>>();
int N;
boolean[] booleans;
int[] nums;
public List<List<Integer>> permute(int[] nums) {
this.nums = nums;
List<Integer> result = new LinkedList<>();
booleans = new boolean[nums.length];
N = nums.length;
backtrack(result,0);
return finalresult;
}
public void backtrack(List<Integer> result,int n){
// 满足结束条件
if(n == N){
finalresult.add(new LinkedList<>(result)); // 必须新new一个添加到finalresult中,否则只是添加了引用的地址
return;
}
// 遍历可以选择的所有情况
for (int i = 0; i < nums.length;i++){
// 做选择(并判断当前选择是否满足情况)
if(booleans[i]){ // 判断是否已经用过
continue; // 是,则排除
}
result.add(nums[i]);
booleans[i] = true; // 标记为已用过
// 递归
backtrack(result,n+1); // 寻找下一个数
// 撤销选择
result.remove(result.size()-1);
booleans[i] = false;
}
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
解决8皇后问题
LeetCode题目地址:https://leetcode.cn/problems/n-queens/
package leetcode.editor.cn;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* N 皇后
* @author WZP
* @date 2023-03-21
*/
public class P51_NQueens{
public static void main(String[] args) {
//测试代码
Solution solution = new P51_NQueens().new Solution();
solution.solveNQueens(4);
}
//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
List<List<String>> finalresult = new ArrayList<>();
int N;
public List<List<String>> solveNQueens(int n) {
int[] result = new int[n+1]; // 注意下标从1开始,result[n]表示第n行存在的位置是第result[n]个
N = n; // N皇后,保存N的值
backtrack(result,1); // 从第一行开始找
return finalresult;
}
public void backtrack(int[] result,int n){
// 满足结束条件
if( n > N ){
finalresult.add(generateString(result)); // 将数组结果转换为满足题目要求的string结果
return;
}
// 遍历可以选择的所有情况 for 选择 in 选择列表:
for(int i = 1; i <= N; i++){ // 判断棋盘第n行的1-N种选择
// 做选择,排除不合法选择
result[n] = i;// 选择第i个
if(!PLACE(n,result)) { // 判断是否与之前的点处在同一列或者同一斜线
continue;// 是 则排除
}
// 递归,进入下一层决策树
backtrack(result,n + 1); //继续向更深一层找(继续向下一行找)
// 撤销选择
result[n] = 0;
}
}
/**
* 将其中一个解的答案转换为List<String>:将数组存放的答案转换为用List<String>列表字符串存储
* @param queens
* @return List<String>
*/
public List<String> generateString(int[] queens){
// 注意,queens中的下标从1开始
List<String> result=new ArrayList<>();
for(int i =1;i < queens.length;i++){
char[] chars=new char[queens.length-1];
Arrays.fill(chars,'.');
chars[queens[i]-1]='Q';
result.add(String.valueOf(chars));
}
return result;
}
/**
* 判断当前k行的选择节点result[k]的与k行之前行选择的位置是否满足要求
* @param k
* @return boolean
*/
public boolean PLACE(int k,int[] result) {
for (int i = 1;i<k;i++){
// 判断result[k]的正上方没有节点,并且不在一条斜线
if ((result[k]==result[i])||(Math.abs(k - i)==Math.abs(result[k]-result[i]))){
return false;
}
}
return true;
}
}
//leetcode submit region end(Prohibit modification and deletion)
}