一、何为回溯法?
回溯法,顾名思义,当问题解不了时,向上回溯,重新选择路径求解。也就是说当问题很大时,我们常常会把一个大问题分解为一个个的小问题,而当每个小问题有多个解法(有对有错)时(类似二叉树),就需要将解法逐个实验,选择出符合既定规则的答案。那么回溯法就是当选择一个解法而解出不符合规则的解后,能回溯到前一步,选择另外一条解法的一种算法思想。
二、具体图例
比如下面的图,男主每当遇到小绿发就得回退到上一个步骤重新选择路径,直到救出女主!
三、解空间结构之排列树和子集树
- 子集树
所给的问题是从n个元素的集合S中找出满足某种性质的子集时,相应的解空间成为子集树。
如0-1背包问题,从所给重量、价值不同的物品中挑选几个物品放入背包,使得在满足背包不超重的情况下,背包内物品价值最大。它的解空间就是一个典型的子集树。(只放一部分) - 排列树
所给的问题是确定n个元素满足某种性质的排列时,相应的解空间就是排列树。
如旅行售货员问题,一个售货员把几个城市旅行一遍,要求走的路程最小。它的解就是几个城市的排列,解空间就是排列树。(全都要)
四、回溯法算法构造套路
1 定义问题的解空间
2 确定易于搜索的解空间结构
3 以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
五、练习:(选自Leetcode题库)
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
链接:https://leetcode-cn.com/problems/generate-parentheses
该题目倘若使用暴力法,需要选择出所有的可能,然后根据规则遍历挑选出符合规则的解,也就是时间复杂度为(2^(2n)n),代码量也有一定量。那么,因为该题也涉及有多种解,且要选择出符合要求的解,倘若我们使用回溯法如何?(建议先试着自个儿写,然后再看答案)
答案如下:
第一层得出答案((()))
而后逐步返回函数,直到回到括号数为((
故第二层答案(()())
而后逐步返回函数,直到回到括号数为(()
故第三层答案(())()
而后逐步返回函数,直到回到括号数为(
故第四层答案()(())
而后逐步返回函数,直到回到括号数为()(
故第五层答案()()()
class Solution {
public List<String> generateParenthesis(int n) {
List<String> lst = new ArrayList();
trackback(lst,"",0,0,n);
return lst;
}
public void trackback(List<String> lst,String curr,int open,int close,int max){
//当括号数等于给定括号数的两倍(左右括号),添加进容器
if(curr.length()==max*2){
lst.add(curr);
return ;
}
//当左括号小于给定的括号数,随便加
if(open<max){
trackback(lst,curr+"(",open+1,close,max);
}
//当右括号小于左括号数,随便加
if(close<open){
trackback(lst,curr+")",open,close+1,max);
}
}
}
练习二:八皇后问题