2999 字
约 9 分钟
9
077.组合
无标签

077.组合

作者:沉默王二
发布时间:2023-03-23T17:43:45.022+0800


本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记,数学表达公式也能显示出来),访问地址和密码:https://t.zsxq.com/6iuzn6I

题意

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

难度

中等

示例

示例 1:

输入:n = 4, k = 2

[   [2,4],  [3,4],  [2,3],  [1,2],  [1,3],  [1,4],]

示例 2:

输入:n = 1, k = 1

分析

本题是一道经典的搜索入门题。

我们一开始可能会想到,利用k层的枚举,每层都从1到n枚举一遍。这样子就产生了[1,1,1,1,1]、[1,1,1,1,2]…… 诸如此类的所有含有重复数字的集合,但是这样子,我们就要对含有重复数字的集合进行去重。

如果依靠上述的算法,我们不仅需要花来枚举,还要在去重上大费周章,太麻烦了,时间复杂度也难以接受。

所以我们考虑换个方法,从排列的本质来考虑,其实我们只需要从n个数字中挑出k个即可,所以我们可以利用深度优先搜索来模拟这个选择的过程,代码如下:

void DFS(List list,int pos,int limit,int maxInt) {

        return ;    if(list.size() == limit){        res.add(new ArrayList<>(list));        return ;    }    list.add(pos);    DFS(list,pos + 1,limit,maxInt);    list.remove(list.size() - 1);    DFS(list,pos + 1,limit,maxInt);}

我们来分析一下这个方法,list是已经选择的数字集合,limit是最多能选的数字,maxInt则是最大能选择的数字。

  • 判断当前选择的数字有没有超过maxInt,如果超过,说明已经枚举完所有的数字了,直接返回。
  • 判断当前已经选择数字的数量是否已经和k相等,如果相等,说明已经找到了合法的答案,直接返回。
  • 接下来就是选择当前数字和不选择当前数字,继续下一次搜索。

这样子的时间复杂度就是,因为我们一共找出了个可行的集合,然后又用的时间将其计入答案。

我们还可以对它进行剪枝优化(剪枝:在保证搜索的正确性、准确性的前提下,省略一些不必要的循环和枚举)。

对于本题来说,if(pos > maxInt)也能够算作剪枝的一种,但它是必要的剪枝,因为如果没用它,我们的算法就不没法停止。它是剪枝,也是搜索算法的结束条件。

除此之外,我们还可以对它进行优化,如果当前list的元素数量加上还没有被选择过的数字总量小于k,那么就算是全都选上了,也不能满足题目的条件——选够k个元素,这一大块的无必要的枚举就可以直接剪掉。

最终代码:

class Solution {

    public List<List> combine(int n, int k) {        List list = new ArrayList<>();        DFS(list,1,k,n);        return res;    }    private void DFS(List list,int pos,int limit,int maxInt) {        if(list.size() + (maxInt - pos + 1) < limit)            return ;        if(list.size() == limit){            res.add(new ArrayList<>(list));            return ;        }        list.add(pos);        DFS(list,pos + 1,limit,maxInt);        list.remove(list.size() - 1);        DFS(list,pos + 1,limit,maxInt);    }}

效率不错:

总结

搜索算法是一类常用的暴力算法,但是如何优雅地暴力是我们刷题党需要考虑的,一边优化程序,一边优化自身的水平。

力扣链接:https://leetcode.cn/problems/combinations/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 1900 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记,数学表达公式也能显示出来),访问地址和密码:https://t.zsxq.com/6iuzn6I

题意

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

难度

中等

示例

示例 1:

输入:n = 4, k = 2

[   [2,4],  [3,4],  [2,3],  [1,2],  [1,3],  [1,4],]

示例 2:

输入:n = 1, k = 1

分析

本题是一道经典的搜索入门题。

我们一开始可能会想到,利用k层的枚举,每层都从1到n枚举一遍。这样子就产生了[1,1,1,1,1]、[1,1,1,1,2]…… 诸如此类的所有含有重复数字的集合,但是这样子,我们就要对含有重复数字的集合进行去重。

如果依靠上述的算法,我们不仅需要花来枚举,还要在去重上大费周章,太麻烦了,时间复杂度也难以接受。

所以我们考虑换个方法,从排列的本质来考虑,其实我们只需要从n个数字中挑出k个即可,所以我们可以利用深度优先搜索来模拟这个选择的过程,代码如下:

void DFS(List list,int pos,int limit,int maxInt) {

        return ;    if(list.size() == limit){        res.add(new ArrayList<>(list));        return ;    }    list.add(pos);    DFS(list,pos + 1,limit,maxInt);    list.remove(list.size() - 1);    DFS(list,pos + 1,limit,maxInt);}

我们来分析一下这个方法,list是已经选择的数字集合,limit是最多能选的数字,maxInt则是最大能选择的数字。

  • 判断当前选择的数字有没有超过maxInt,如果超过,说明已经枚举完所有的数字了,直接返回。
  • 判断当前已经选择数字的数量是否已经和k相等,如果相等,说明已经找到了合法的答案,直接返回。
  • 接下来就是选择当前数字和不选择当前数字,继续下一次搜索。

这样子的时间复杂度就是,因为我们一共找出了个可行的集合,然后又用的时间将其计入答案。

我们还可以对它进行剪枝优化(剪枝:在保证搜索的正确性、准确性的前提下,省略一些不必要的循环和枚举)。

对于本题来说,if(pos > maxInt)也能够算作剪枝的一种,但它是必要的剪枝,因为如果没用它,我们的算法就不没法停止。它是剪枝,也是搜索算法的结束条件。

除此之外,我们还可以对它进行优化,如果当前list的元素数量加上还没有被选择过的数字总量小于k,那么就算是全都选上了,也不能满足题目的条件——选够k个元素,这一大块的无必要的枚举就可以直接剪掉。

最终代码:

class Solution {

    public List<List> combine(int n, int k) {        List list = new ArrayList<>();        DFS(list,1,k,n);        return res;    }    private void DFS(List list,int pos,int limit,int maxInt) {        if(list.size() + (maxInt - pos + 1) < limit)            return ;        if(list.size() == limit){            res.add(new ArrayList<>(list));            return ;        }        list.add(pos);        DFS(list,pos + 1,limit,maxInt);        list.remove(list.size() - 1);        DFS(list,pos + 1,limit,maxInt);    }}

效率不错:

总结

搜索算法是一类常用的暴力算法,但是如何优雅地暴力是我们刷题党需要考虑的,一边优化程序,一边优化自身的水平。

力扣链接:https://leetcode.cn/problems/combinations/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 1900 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记,数学表达公式也能显示出来),访问地址和密码:https://t.zsxq.com/6iuzn6I

题意

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

难度

中等

示例

示例 1:

输入:n = 4, k = 2

[   [2,4],  [3,4],  [2,3],  [1,2],  [1,3],  [1,4],]

示例 2:

输入:n = 1, k = 1

分析

本题是一道经典的搜索入门题。

我们一开始可能会想到,利用k层的枚举,每层都从1到n枚举一遍。这样子就产生了[1,1,1,1,1]、[1,1,1,1,2]…… 诸如此类的所有含有重复数字的集合,但是这样子,我们就要对含有重复数字的集合进行去重。

如果依靠上述的算法,我们不仅需要花来枚举,还要在去重上大费周章,太麻烦了,时间复杂度也难以接受。

所以我们考虑换个方法,从排列的本质来考虑,其实我们只需要从n个数字中挑出k个即可,所以我们可以利用深度优先搜索来模拟这个选择的过程,代码如下:

void DFS(List list,int pos,int limit,int maxInt) {

        return ;    if(list.size() == limit){        res.add(new ArrayList<>(list));        return ;    }    list.add(pos);    DFS(list,pos + 1,limit,maxInt);    list.remove(list.size() - 1);    DFS(list,pos + 1,limit,maxInt);}

我们来分析一下这个方法,list是已经选择的数字集合,limit是最多能选的数字,maxInt则是最大能选择的数字。

  • 判断当前选择的数字有没有超过maxInt,如果超过,说明已经枚举完所有的数字了,直接返回。
  • 判断当前已经选择数字的数量是否已经和k相等,如果相等,说明已经找到了合法的答案,直接返回。
  • 接下来就是选择当前数字和不选择当前数字,继续下一次搜索。

这样子的时间复杂度就是,因为我们一共找出了个可行的集合,然后又用的时间将其计入答案。

我们还可以对它进行剪枝优化(剪枝:在保证搜索的正确性、准确性的前提下,省略一些不必要的循环和枚举)。

对于本题来说,if(pos > maxInt)也能够算作剪枝的一种,但它是必要的剪枝,因为如果没用它,我们的算法就不没法停止。它是剪枝,也是搜索算法的结束条件。

除此之外,我们还可以对它进行优化,如果当前list的元素数量加上还没有被选择过的数字总量小于k,那么就算是全都选上了,也不能满足题目的条件——选够k个元素,这一大块的无必要的枚举就可以直接剪掉。

最终代码:

class Solution {

    public List<List> combine(int n, int k) {        List list = new ArrayList<>();        DFS(list,1,k,n);        return res;    }    private void DFS(List list,int pos,int limit,int maxInt) {        if(list.size() + (maxInt - pos + 1) < limit)            return ;        if(list.size() == limit){            res.add(new ArrayList<>(list));            return ;        }        list.add(pos);        DFS(list,pos + 1,limit,maxInt);        list.remove(list.size() - 1);        DFS(list,pos + 1,limit,maxInt);    }}

效率不错:

总结

搜索算法是一类常用的暴力算法,但是如何优雅地暴力是我们刷题党需要考虑的,一边优化程序,一边优化自身的水平。

力扣链接:https://leetcode.cn/problems/combinations/

一步一个脚印

不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。

PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。

一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 1900 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!

            知识星球
            
    
    
        
        扫码加入星球
        查看更多优质内容
    
    https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412
077.组合
https://clxhxhhr.top/posts/2531/
作者
clxstart
发布于
2026-09-19
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。
☰ 文章目录