Leetcode 77 组合

题意理解

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

如:n=3,k=2,则有:12 13 23

一般,我们使用回溯法来解决组合问题

组合问题没有顺序要求,所以 12 21 是同一个组合(如果是排列12 21 是两种排列)

一般我们可以把回溯法要解决的问题抽象成树结构

集合大小=树的宽度=n 组合大小=递归深度=k

所以

我们可以将这个问题抽象为树问题,在递归方法中使用回溯来暴力搜索。

由于回溯是暴力解锁的方式,为了实现性能优化,我们提前对于一些不可能搜到正确结果的树枝进行剪枝操作

1.暴力解锁的回溯

注意

removeLast()是LinkedList的方法,List<> list=new LinkedListM<>()是调用不到的。

添加结果是,path的内容要复制给一个新的对象new LinkedList<>(),否则对同一个path对象修改的话,results记录的结果值也会发生改变,最终的结果就是result里面重复加入相同的path对象。。

java 复制代码
/**
     * 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合
     * @param n
     * @param k
     * @return
     */
    List<List<Integer>> results=new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        backtracking(n,k,1);
        return results;
    }
    public void backtracking(int n,int k,int startIndex){
        //结果收集,结束
        if(path.size()==k){
            //重新new一个是因为如果对同一个path操作,最终result是一堆相同的path
            results.add(new ArrayList<>(path));
            return;
        }
        //未收集结果,遍历当前分支子孩子
        for(int i=startIndex;i<=n;i++){
            path.add(i);
            backtracking(n,k,i+1);
            path.removeLast();
        }
    }

2.采用剪枝的回溯

采用剪枝是为了在进行暴力的回溯搜索时,及时剪除不可能搜到正确结果的树枝,对整体搜索过程进行优化。

图摘自《代码随想录》

复制代码
【剪枝优化】
从startIndex收集path
n-pathSize=还需要收集的数据量
n-statIndex=剩余的数据量
如果 k-pathSize<n-startIndex+1,则剩余的搜索,现有数据不足以搜到大小为k的组合
所以我们要保证k-pathSize<n-startIndex+1,变形得  startIndex<n-(k-pathSize)+1
java 复制代码
       /**
     * 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合
     * @param n
     * @param k
     * @return
     */
    List<List<Integer>> results=new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        backtracking(n,k,1);
        return results;
    }
    public void backtracking(int n,int k,int startIndex){
        //结果收集,结束
        if(path.size()==k){
            //重新new一个是因为如果对同一个path操作,最终result是一堆相同的path
            results.add(new ArrayList<>(path));
            return;
        }
        //未收集结果,遍历当前分支子孩子
        //【剪枝优化】
        for(int i=startIndex;i<=n-(k-path.size())+1;i++){
            path.add(i);
            backtracking(n,k,i+1);
            path.removeLast();
        }
    }

3.分析

时间复杂度:

暴力回溯:O(2^n)

剪枝回溯:O()

空间复杂度:

暴力回溯:O(k)

简直回溯:O(k)

相关推荐
皮卡蛋炒饭.4 分钟前
数据结构—排序
数据结构·算法·排序算法
??tobenewyorker1 小时前
力扣打卡第23天 二叉搜索树中的众数
数据结构·算法·leetcode
贝塔西塔1 小时前
一文读懂动态规划:多种经典问题和思路
算法·leetcode·动态规划
众链网络2 小时前
AI进化论08:机器学习的崛起——数据和算法的“二人转”,AI“闷声发大财”
人工智能·算法·机器学习
2 小时前
Unity开发中常用的洗牌算法
java·算法·unity·游戏引擎·游戏开发
飒飒真编程3 小时前
C++类模板继承部分知识及测试代码
开发语言·c++·算法
GeminiGlory3 小时前
算法练习6-大数乘法(高精度乘法)
算法
熬了夜的程序员4 小时前
【华为机试】HJ61 放苹果
算法·华为·面试·golang
马特说4 小时前
基于随机森林的金融时间序列预测系统:从数据处理到实时预测的完整流水线
算法·随机森林·金融
呆呆的小鳄鱼4 小时前
leetcode:HJ18 识别有效的IP地址和掩码并进行分类统计[华为机考][字符串]
算法·leetcode·华为