力扣刷题笔记 → 77. 组合

250 阅读1分钟

这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

题目

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

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

示例

输入: n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
输入: n = 1, k = 1
输出: [[1]]

提示

  • 1 <= n <= 20
  • 1 <= k <= n

解题思路

回溯

如果解决一个问题有多个步骤,每个步骤有多种方法,又需要求得所有的方法,那么就可以使用回溯算法。

如本题,要求得[1,n]区间内所有由k个数组成的子数组集合,我们可以将其转换成一个多叉树,再通过穷举,得到所有的子数组。

1.png

图形画出来了,根据图中总结出的步骤,我们可以发现如下结构:

  1. 获取当前数值,再从后续区间找多一个数值进行组合;
  2. 排除前面已统计过的数值。

以此类推,可体现出递归结构。

由于需要统计路径上的多个节点,因此我们需要一个存储的变量l用来记录节点信息,该变量采用LinkedList类型来保存节点信息,便于我们对其进行添加删除节点,使其可以复用。

class Solution {
    private List<List<Integer>> list;
    public List<List<Integer>> combine(int n, int k) {
        this.list = new ArrayList<>();
        if(k == 0) return list;
        // 回溯入口
        backtracking(n, k, new LinkedList());
        // 返回结果
        return list;
    }

    /**
     * 回溯
     * @param n 区间
     * @param k 子数组长度
     * @param l 保存路径上的节点
     */
    public void backtracking(int n, int k, LinkedList<Integer> l){
        // 边界判断
        if(n < k - l.size() - 1){return;}
        // 添加子数组到集合中
        if(l.size() == k){
            list.add(new ArrayList(l));
            return;
        }

        // 遍历后续元素
        for(int i = n; i > 0; --i){
            // 添加元素为头节点
            l.addFirst(i);
            // 递归,添加后续节点
            backtracking(i - 1, k, l);
            // 删除头节点,返回最初始初始状态,进入下一轮
            l.removeFirst();
        }
    }
}

 复杂度分析

  •   时间复杂度:O(NK)O(NK)
  •   空间复杂度:O(N+K)O(N+K)

最后

文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!

如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!

题目出处: leetcode-cn.com/problems/co…