剪枝优化!力扣77:回溯算法求组合数

回溯算法求组合数中,backtracking函数一般为:

void backtracking(int pre,int n,int k){
    if(singlePath.size()==k){
        result.push_back(singlePath);
        return;
    }

    for(int i=pre+1;i<=n;i++){
        singlePath.push_back(i);
        backtracking(i,n,k);
        singlePath.pop_back();
    }
}

 然而,这个backtracking函数仍旧有值得优化的地方!

例如求组合数C_{5}^{3},回溯流程如下图,其中被红叉标记的地方都是没有意义、浪费掉的操作!——明明是这一层就可以排除掉的操作,结果到下一层,不但没有终止递归并输出结果,还发现pre+1已经大于n,结果还得回溯,确实是浪费、没有意义!

究其原因,就是因为执行完这些操作时,会发现剩下的元素不能够满足还需要的元素,导致最终无法输出组合数!

这些操作可以通过for循环的条件来避免!

未加入当前元素时,已装入元素个数为singlePath.size(),

设当前加入元素为i,则剩余元素为i+1, ..., n-1, n,总共n-i个元素。

加入当前元素后,还需要多少元素才能组成组合数呢?还需要k-singlePath.size()-1个(注意,这里的判断还在for循环的条件里面,还没执行到singlePath的push_back()函数!!!)

所以,循环条件应当为n-i\geqslant k-singlePath.size()-1,即i \leqslant n-(k-singlePath.size())+1

 

优化后代码:

void backtracking(int pre,int n,int k){
    if(singlePath.size()==k){
        result.push_back(singlePath);
        return;
    }

    for(int i=pre+1;i<=n-(k-singlePath.size())+1;i++){
        singlePath.push_back(i);
        backtracking(i,n,k);
        singlePath.pop_back();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值