递归之回溯
在许多的实际问题中,使用常规的算法十分难以解决一些具有递推性质的问题。但递推性质刚好和我们的递归相符合,而回溯也可以算是递归中的一种
我们最常见的回溯的算法就是八皇后的算法了
回溯法解决八皇后问题
我们在学习数据结构时的深度优先算法就是一种回溯
或者我们学习二叉树时三种遍历的方式在我看来也有回溯
回溯一般用在什么情景之下呢?
类似于寻找迷宫出口,遍历集合的子集之类的问题
回溯最重要的是在不成立的情况下使我们结果的状态返回为上一个递归的状态
下面来两个回溯的例子
一个是查找一个字符矩阵中连续的字符串是否存在的问题
public static boolean[][] flag;
public static boolean exist(char[][] board, String word){
//初始化标记矩阵,false为没走过
flag = new boolean[board.length][board[0].length];
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;j++){
if(board[i][j]==word.charAt(0)&&find(board, word, i, j, 0))
return true;
}
}
return false;
}
public static boolean find(char[][] board,String word,int i,int j,int num){//分别代表目标矩阵
//目标字符串,矩阵中元素的坐标,字符串的字符坐标
if(num==word.length())
return true;
//如果坐标已经超出界限,返回false
if(i<0||i>board.length-1||j<0||j>board[0].length-1||board[i][j]!=word.charAt(num)||flag[i][j])
return false;
//标记矩阵坐标i,j已经被走过
flag[i][j]=true;
//如果返回的时false,那么就回溯
if(find(board,word,i+1,j,num+1)||find(board,word,i-1,j,num+1)||
find(board,word,i,j+1,num+1)||find(board,word,i,j-1,num+1))
return true;
//回溯
flag[i][j]=false;
return false;
}
仔细揣摩一些收获颇丰
还有一道是查找出所有符合的子集
public static List<List<Integer>> res = new ArrayList<>();
public static List<List<Integer>> conbinationSum(int[] candidates,int target){
Arrays.sort(candidates);
List<Integer> list = new ArrayList<>();
find(candidates, list, 0, target, 0);
return res;
}
public static void find(int[] candidates,List<Integer>list,int sum, int target,int index){
//目标数组事先是排过队的
//参数分别是目标数组,需要添加的集合,当前的总和,目标数,当前的下标
if(sum>target){
return;
}
if(sum==target){//一个完整的解
res.add(list);
return;
}
for (int i = index; i < candidates.length; i++) {
List<Integer> t_list = new ArrayList<>(list);
t_list.add(candidates[i]);
find(candidates, t_list, sum + candidates[i], target,i);
}
}