目前回溯算法可以解决的问题:
- 组合问题:N个数里面找出K个数的所有组合
- 子集问题:一个N个数的集合里面找出所有符合条件的子集
- 排列问题:N个数里面找出K个数的所有排列
- 切割问题:一个字符串按一定规律有几种切割方式
回溯的模版方法:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
其实子集问题也可以归在组合问题里面,同时切割问题实际上也是组合问题,只有一些参数比如startindex有新的含义,就是代表切割线。
在组合问题中又能分为两种组合问题,一种是在一个集合中找出所以符合条件的组合,另一种是在多个集合中找出符合条件的组合。这两种问题在处理上面也不一样,startindex在多集合组合中就没有作用了。不过模版是同样的,只是细节更多一些
排列问题和组合问题区别就在于,排列是讲究顺序的,不同的顺序也是符合条件的,同样使用模版,只是组合问题中的startindex在排列中就失效,需要使用一个used数组来标记已经加入过path数组中的元素,防止重复加入。
最后就是去重的问题,去重有两种方法,一种是使用used数组标记,但是使用used数组标记的前提是集合能够先进行排序。
另一种就是使用set存储,这一种方法不需要集合先进行排序,但是这一种的弊端就是在于时间复杂度和空间复杂度都变高了。