随想录一刷Day24——回溯算法

Day24_回溯算法

1. 回溯算法理论基础

回溯法也可以叫做回溯搜索法,它是一种搜索的方式。
回溯是递归的副产品,只要有递归就会有回溯。
回溯法,一般可以解决如下几种问题:

  • 组合问题:N个数里面按一定规则找出k个数的集合
  • 切割问题:一个字符串按一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 排列问题:N个数按一定规则全排列,有几种排列方式
  • 棋盘问题:N皇后,解数独等等
    组合: 不强调元素顺序。
    排列: 强调元素顺序。

2. 组合

77. 组合
思路:

由于是组合,没有顺序,为了确保不重不漏,每次在区间 [startIndex, n] 之间寻找 k 个数,startIndex 每次 +1,代码如下

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    void backtracking(int n, int k, int startIndex) {
        if (path.size() == k) { // 找到满足条件的答案,记录并返回
            ans.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) {
        ans.clear();
        path.clear();
        backtracking(n, k, 1);
        return ans;
    }
};

3. 组合(优化)

77. 组合
思路:

可以对上一问进行剪枝优化,当待查询的区间小于 k 时,一定找不到答案,不用在这些区间中查询

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    void backtracking(int n, int k, int startIndex) {
        if (path.size() == k) {
            ans.push_back(path);
            return ;
        }
		
		// 区间内的数个数加上已经被选了的path中的数的个数,要能够达到 k 个数
        for (int i = startIndex; i <= (n - k + 1 + path.size()); i++) { // k <= (n - i + 1) + path.size()
            path.push_back(i);
            backtracking(n, k, i + 1);
            path.pop_back();
        }
    }

public:
    vector<vector<int>> combine(int n, int k) {
        ans.clear();
        path.clear();
        backtracking(n, k, 1);
        return ans;
    }
};

4. 组合总和 III

216. 组合总和 III
思路:

[1,9] 里找 k 个数加和等于 n

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    void backtracking(int k, int n, int startIndex, int sum) {
        if (path.size() == k || sum >= n) {
            if (path.size() == k && sum == n) { // 满足条件的答案
                ans.push_back(path);
                return ;
            } else return ;
        }

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

public:
    vector<vector<int>> combinationSum3(int k, int n) {
        path.clear();
        ans.clear();
        backtracking(k, n, 1, 0);
        return ans;
    }
};

剪枝:

减两处:

  1. 由于是从前往后查询,当出现 sum > n 时,此后的 sum 一定大于 k,不用再继续往后找了
  2. 同前面的组合问题,当区间的长度加上 path 的长度不足 k 时,一定不满足条件,不必继续查询
class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    void backtracking(int k, int n, int startIndex, int sum) {
        if (path.size() == k || sum >= n) {
            if (path.size() == k && sum == n) { // 满足条件的答案
                ans.push_back(path);
                return ;
            } else return ; // 剪枝1
        }

        for (int i = startIndex; i <= (9 - k + 1 + path.size()); i++) { // 剪枝2
            path.push_back(i);
            backtracking(k, n, i + 1, sum + i);
            path.pop_back();
        }
    }

public:
    vector<vector<int>> combinationSum3(int k, int n) {
        path.clear();
        ans.clear();
        backtracking(k, n, 1, 0);
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值