什么是回溯法
回溯法也可以叫做回溯搜索法,它是一种搜索的方式。
在二叉树系列中,我们已经不止一次,提到了回溯,例如二叉树:以为使用了递归,其实还隐藏着回溯 (opens new window)。
回溯是递归的副产品,只要有递归就会有回溯。
所以以下讲解中,回溯函数也就是递归函数,指的都是一个函数。
回溯法的性能如何呢,这里要和大家说清楚了,虽然回溯法很难,很不好理解,但是回溯法并不是什么高效的算法。
因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。
回溯法解决的问题
回溯法,一般可以解决如下几种问题:
- 组合问题:N个数里面按一定规则找出k个数的集合
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后,解数独等等
回溯法模板
- 回溯函数模板返回值以及参数
在回溯算法中,我的习惯是函数起名字为backtracking,这个起名大家随意。
回溯算法中函数返回值一般为void。
再来看一下参数,因为回溯算法需要的参数可不像二叉树递归的时候那么容易一次性确定下来,所以一般是先写逻辑,然后需要什么参数,就填什么参数。
但后面的回溯题目的讲解中,为了方便大家理解,我在一开始就帮大家把参数确定下来。
- 回溯函数终止条件
既然是树形结构,那么我们在讲解二叉树的递归 (opens new window)的时候,就知道遍历树形结构一定要有终止条件。
所以回溯也有要终止条件。
什么时候达到了终止条件,树中就可以看出,一般来说搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归。
- 回溯搜索的遍历过程
在上面我们提到了,回溯法一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度。
第77题. 组合
注意数据结构的应用
LinkedList 可以去掉栈尾的元素
class Solution { List<List<Integer>> ans = new ArrayList<>(); LinkedList<Integer> path = new LinkedList<>(); public List<List<Integer>> combine(int n, int k) { combination(n,k,1); return ans; } public void combination(int n, int k, int start){ if (k == 0) { ans.add(new ArrayList<>(path)); return; } for( int i = start; i <= n - k + 1; i++){ path.add(i); combination(n, k - 1, i+1); path.removeLast(); } } }
216.组合总和III
对于我来说的考点主要还是java的语法
对于list的使用规范
对于LinkList的使用,一定要左右都是后面才能使用我们的add以及.removeLast();
在我们copy的时候记得使用new 类型(拷贝对象)
class Solution { List<List<Integer>> ans = new ArrayList<>(); LinkedList<Integer> now_ans = new LinkedList<>(); public List<List<Integer>> combinationSum3(int k, int n) { combination(k, n, 1); return ans; } // n : target sum for the left nums // k : how many left // smallest: the smallest num we can use public void combination(int k, int n, int smallest){ if(smallest > 9 && n > 0) return; if(n == 0 && k == 0) { ans.add(new ArrayList<>(now_ans)); return; } for(int i = smallest; i <= 9; i++){ if (i > n) break; now_ans.add(i); combination(k-1, n-i, i+1); now_ans.removeLast(); } return; } }
17.电话号码的字母组合
本题对于我来说的考察内容是关于java的语法和数据结构的部分
首先是可以用表格的形式存储我们的数据
String[] num = {}
即表格的定义方式 是用大括号的
其次String类型取出值的方法为,string_name.charAt(n);
java中单引号‘’和双引号“”并不公用
其次关于char转换为int类型的方法是 char_num - '0' 一定是单引号的
class Solution { String[] num = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; List<String> ans = new ArrayList<>(); public List<String> letterCombinations(String digits) { if(digits == "" || digits.length() == 0) return ans; combination(digits, 0, ""); return ans; } public void combination(String digits, int n, String now){ if (n == digits.length()){ ans.add(now); return; } int find_n = digits.charAt(n)-'0'; String temp = num[find_n]; for(int i = 0; i < temp.length(); i++){ combination(digits, n+1, now + temp.charAt(i)); } return ; } }