第四周第五天|回溯法基础、力扣77、组合

回溯法理论基础

回溯的本质是一种穷举,之所以要用琼剧来解决问题,是因为有些问题如果不用穷举的话升值不好写出来,因此用递归回溯的方法来解决,当然,一些剪枝操作还是可以做的。

那么,都说回溯这种方法和递归很像,很像在哪呢?通过回溯三部曲,我们就能有所体会。

回溯的第一步是要确定函数的返回值和函数参数,第二步是要确定终止条件,接着保存结果,return,第三步是确定单层递归逻辑,可以发现,回溯的解题步骤和递归是一脉相承的。

当然,要想深入了解回溯,还是要结合具体的问题来进行理解。

力扣77、组合

细节:首先区分下组合和排列,组合是无序的,排列是有序的。

思路:对于本题而言,如果用暴力解的话,那么就是用for循环去嵌套遍历了,如果k很大的话那这个循环是没法写的,这个时候我们就可以考虑回溯了,我们需要两个全局变量,一个变量保存结果集,一个变量用二维数组保存各个结果集。
首先明确函数的返回值,一般回溯的返回值都是void,接着确定函数的参数,我们肯定要用到题目给的n和k,还需要什么呢?我们现在还不知道,在做回溯的时候,我们往往无法一次性写完所有参数,在书写逻辑的时候,缺什么补什么就可以了,现在让我们进行第二部,终止条件的确定,本题终止的条件就是当前结果集中的元素已经达到k个时,我就可以结束递归,保存结果了。第三步单层递归的逻辑,我们用for循环去横向便利,也就是说集合的元素个数决定了树的宽度,用递归回溯去纵向遍历,也就是用k的大小去决定树的深度,这样我们就可以遍历完所有结果了。

代码:

class Solution {
public:
    vector<vector<int>>result;//保存结果集的集合
    vector<int>path;//保存结果集
    void backtracking(int n,int k,int startIndex){
        if(path.size()==k){
            result.push_back(path);
            return;
        }
        //单层递归的逻辑
        //先要用for循环来横向遍历,决定树的宽度,回溯来纵向遍历,决定树的深度。
        for(int i=startIndex;i<=n;++i){
            path.push_back(i);
            backtracking(n, k, i+1);
            path.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        result.clear();
        path.clear();
        backtracking(n, k, 1);
        return result;
    }
};

优化:不难看出,这份代码中有一些情况显然没有继续下去的价值,比如说n=4,k=3的时候,如果从3开始遍历,根本就找不到答案,3之后就更不用说了,这个时候我们就可以进行一些剪枝的操作,对于本题而言:
结果集中的元素个数为k;
当前还需要的元素个数为k-path.size();
至多从下标为n-(k-path.size())+1开始遍历
例如,n=4,k=3,假设当前结果集中元素数量为0,那么至多从2开始遍历,没毛病。
因此,对于下标大于它的元素,就没有进入for循环的必要了。

这就是剪枝操作,也可以提高效率。

代码:

class Solution {
public:
    vector<vector<int>>result;//保存结果集的集合
    vector<int>path;//保存结果集
    void backtracking(int n,int k,int startIndex){
        if(path.size()==k){
            result.push_back(path);
            return;
        }
        //单层递归的逻辑
        //先要用for循环来横向遍历,决定树的宽度,回溯来纵向遍历,决定树的深度。
        for(int i=startIndex;i<=n-(k-path.size())+1;++i){//优化的地方
            path.push_back(i);
            backtracking(n, k, i+1);
            path.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        result.clear();
        path.clear();
        backtracking(n, k, 1);
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值