算法笔记1.1
本次内容是对于上次的组合问题进行的优化操作,优化的方法称之为剪枝,字面意思就是省去一些没有必要的操作,从而提高效率。
剪枝
在组合问题当中,我们在取节点的时候我们要注意一个问题,在同一层且取数不重复的情况下,假设我们的n = 4,数组为【1,2,3,4】,如果我们一开始取的数为1,那之后在分支上再取就要在2,3,4当中选,同理我们先取2,在它的分支我们就只能取3,4,这是为了让组合不重复。
回到题目里,当k = 2的时候,不好体现剪枝的作用,所以选取k = 3的情况。从下图可以看出来,有些元素组合的k不满3,很多遍历都是没有意义的,那么优化掉这些不必要的分支是不是就可以提高效率。 上节谈到树的宽度表示集合的大小,深度表示递归的深度,我们每次剪枝的地方就处于递归过程当中每层for循环的起始位置,那么就可以理解为,如果我们改变for循环中i的条件,是不是就可以就此实现剪枝操作本身。
优化过程
1.找到已经选好的元素个数:原本条件为i <= n,n为元素总个数,已经选好的元素个数就是指在path数组当中被push进去的内容,个数就是path数组的大小,即path.size()。 2.还有没选择过的元素个数:题目要求k个数的组合,没有被选择的元素个数是不是要求个数减去已经选择个数,即k-path.size()。 3.在整个集合当中要在起始位置进行遍历:拿元素总个数n减去未选择过的元素个数即可,n-(k-path.size()),这里就会出现问题,如果就这样设置条件可以发现最后得到的结果会缺少组合,这里是因为没有将初始位置的条件考虑在内,如果不理解可以自行去选择n与k代入式子中就可以理解,所以要在后面+1,就变为了n-(k-path.size())+1。
代码部分
for(int i=startIndex; i<=n-(k-path.size())+1; i++){
path.push_back(i);
backtracking(n, k, i+1);
path.pop_back();
}
}
总结
剪枝操作比较灵活,面对不一样的题目,考虑的点也会有所不同,但剪枝操作一般会在for循环中i的范围当中去操作,可以让我们更好地提前锁定范围,剩下的部分可能就需要通过题目的积累去慢慢完善本部分的内容,相应的视频讲解为组合剪枝优化,希望大家也能理解题目,有所收获,变得更强!
|