开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情
前言
算法的重要性不言而喻!区分度高!
现在学习的门槛低了,只有能上网每个人都可以学编程!培训班6个月就可以培养出来能干活的人,你怎么从这些人中脱颖而出?没错!就是学算法,学一些底层和基础的东西。
说的功利点是为了竞争,卷死对手。真心话说就是能提高自己的基础能力,为技术可持续发展做好充分的准备!!!
提前入门学习书籍:CPrimerPlus、大话数据结构
刷题网站
我是按照代码随想录提供的刷题顺序进行刷题的,大家也可以去刷leetcode最热200道,都可以
刷题嘛,最重要的就是坚持了!!!
画图软件
OneNote
这个要经常用,遇见不懂的流程的话就拿它画一画!
笔记软件
Typoral
题目
解析
回溯三部曲
- 确定回溯的参数和返回值
回溯一般不需要返回值,然后参数的话传入三个参数,分别是n , k, startIndex
n和k的话就是题目要用的,从n个数中挑选k个组合
startIndex的作用就是防止出现重复的组合,如下图所示:
private void combineHelper(int n, int k, int startIndex){}
- 确定回溯终止的条件 到达叶子结点自然就要终止回溯啦!
if (path.size() == k){
result.add(new ArrayList<>(path));
return;
}
- 回溯搜索的遍历过程
首先使用for循环横向遍历,然后使用递归纵向遍历,如下图所示:
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){
path.add(i);
combineHelper(n, k, i + 1);
path.removeLast();
}
完整代码
这里我在详细解释下代码的逻辑
- 因为题目最终要的是一个二维结果数组,所以我们需要一个一维数组去保存递归得到的路径,最后再把这些一维数组全放到二位数组,这样就可以得到最后的二维结果数组的形式了!
对应代码如下:
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
- 题目给出的要求是要从n个数里挑k个进行组合,所以当一维数组收集到的元素到了k个,那就不收集了然后把一维数组放入二维数组中
对应代码如下:
if (path.size() == k){
result.add(new ArrayList<>(path));
return;
}
3.怎么保证不收集到重复元素呢?这里通过一个startIndex来完成,每收集完一次就把startIndex+1,这样收集过的元素就不会再被使用了
这里既然控制了startIndex的开始位置,那么循环的次数也要进行控制,不然就越界了。也就是收集一个数,那遍历的次数就减一呗。所以用k - path.size()表示收集元素的个数,然后用总数n-(k - path.size())即可表示需要循环的次数。
又因为startIndex是从1开始的,所以后面要加1,不然只能遍历1次
对应代码如下:
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){
path.add(i);
combineHelper(n, k, i + 1);
path.removeLast();
}
完整代码如下:
class Solution {
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combine(int n, int k) {
combineHelper(n, k, 1);
return result;
}
private void combineHelper(int n, int k, int startIndex){
//终止条件
if (path.size() == k){
result.add(new ArrayList<>(path));
return;
}
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){
path.add(i);
combineHelper(n, k, i + 1);
path.removeLast();
}
}
}