Leetcode每日一题--77. 组合

80 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情

前言

算法的重要性不言而喻!区分度高!

现在学习的门槛低了,只有能上网每个人都可以学编程!培训班6个月就可以培养出来能干活的人,你怎么从这些人中脱颖而出?没错!就是学算法,学一些底层和基础的东西。

说的功利点是为了竞争,卷死对手。真心话说就是能提高自己的基础能力,为技术可持续发展做好充分的准备!!!

提前入门学习书籍:CPrimerPlus、大话数据结构

image-20220705103735001

刷题网站

代码随想录 (programmercarl.com)

leetcode

我是按照代码随想录提供的刷题顺序进行刷题的,大家也可以去刷leetcode最热200道,都可以

刷题嘛,最重要的就是坚持了!!!

画图软件

OneNote

这个要经常用,遇见不懂的流程的话就拿它画一画!

笔记软件

Typoral

题目

leetcode.cn/problems/co…

解析

回溯三部曲

  1. 确定回溯的参数和返回值

回溯一般不需要返回值,然后参数的话传入三个参数,分别是n , k, startIndex

n和k的话就是题目要用的,从n个数中挑选k个组合

startIndex的作用就是防止出现重复的组合,如下图所示:

image.png

private void combineHelper(int n, int k, int startIndex){}
  1. 确定回溯终止的条件 到达叶子结点自然就要终止回溯啦!
if (path.size() == k){
    result.add(new ArrayList<>(path));
    return;
}
  1. 回溯搜索的遍历过程

首先使用for循环横向遍历,然后使用递归纵向遍历,如下图所示:

for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){
    path.add(i);
    combineHelper(n, k, i + 1);
    path.removeLast();
}

image.png

完整代码

这里我在详细解释下代码的逻辑

  1. 因为题目最终要的是一个二维结果数组,所以我们需要一个一维数组去保存递归得到的路径,最后再把这些一维数组全放到二位数组,这样就可以得到最后的二维结果数组的形式了!

对应代码如下:

List<List<Integer>> result = new ArrayList<>();
    
LinkedList<Integer> path = new LinkedList<>(); 
  1. 题目给出的要求是要从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();
        }
    }
}