leetcode 77 学习笔记(组合,剪枝优化 一下)

前情回顾

我们先来回顾一下leetcode 77 给出的回溯代码

class Solution {
private:
    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 (int i = startIndex; i <= n; i++) {
            path.push_back(i); // 处理节点 
            backtracking(n, k, i + 1); // 递归
            path.pop_back(); // 回溯,撤销处理的节点
        }
    }
public:
    vector<vector<int>> combine(int n, int k) {
        result.clear(); // 可以不写
        path.clear();   // 可以不写
        backtracking(n, k, 1);
        return result;
    }
};

剪枝优化

先分析遍历过程中的代码:

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

其实,这个遍历可以剪枝优化。
如下图所示,
在这里插入图片描述
以n=4,k=4为例,第一层for循环的时候,从取2开始的for循环就没有意义了。到了第二层,从取3开始的for循环没有意义了。

图中每一个节点(图中矩形),就代表本层的一个for循环,那么每一层的for循环从第二个数开始遍历的话,都没有意义。

剪枝的地方,在递归汇中每一层的for循环所选择的起始位置。

如果for循环选择的起始位置之后的元素个数,不足我们需要的元素个数,不搜索。

代码中的i,就是for循环里选择的起始位置。

for (int i = startIndex; i <= n; i++) { 

优化步骤:
①已经选择的元素个数: path.size();

②还需要的元素个数:k-path.size();

③在集合n中至多要从该起始位置: n-(k-path.size())+1 开始遍历。
+1的目的是因为包括起始位置,需要一个左闭的集合。

for example:

n=4,k=2。

目前已经选取的元素为0(path.size为0),n-(k-0)+1 ,即4-(2-0)+1 =3。

从3开始搜索就变合理了,能组合为【3,4】。

优化后的for循环:

for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) 
// i为本次搜索的起始位置

代码

优化后整体代码:

class Solution {
private:
    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 (int i = startIndex; i <= n - (k - path.size()) + 1; i++) { 
        	// 优化的地方
            path.push_back(i); // 处理节点 
            backtracking(n, k, i + 1);
            path.pop_back(); // 回溯,撤销处理的节点
        }
    }
public:

    vector<vector<int>> combine(int n, int k) {
        backtracking(n, k, 1);
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓梦林

都看到这里了,支持一下作者呗~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值