回溯理论

什么是回溯

回溯,顾名思义,返回溯源,记录当前节点后返回前一节点继续的过程。本质上是一种罗列所有情况的穷举搜索。

递归

递归,函数间接或者直接调用自身,回到最初最简单的情况。目前的情况归根结底就是一棵树的情况。

回溯与递归

为什么说回溯常常伴随递归?递归是把一棵大二叉树返回到一个最基本的三个节点的树,在每一次树变小的过程中,都有一个数的子树返回根节点的过程。

n个数中k个数的组合

问题

1.返回值问题:返回值必须与返回类型相匹配(-1)
2.私有成员变量的作用域问题
核心代码模式下,不管声明为private、public还是protected,都属于类内,所以可以访问。
private:类内访问;
protected:类内和派生类访问;
public:类内、派生类和类外都可以访问。
剪枝问题

代码

class Solution {
private:
    vector<int> vec;
    vector<vector<int>> res;

public:
    void backTrack(int n, int k, int startIndex) {
        if (vec.size() == k) {
            res.push_back(vec);
            return;
        }
        for (int i = startIndex; i <= n-(k-vec.size()+1); i++) {
            vec.push_back(i);
            backTrack(n, k, i + 1);
            vec.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        backTrack(n, k, 1);
        return res;
    }
};

总结

组合相当于把K层循环的过程用递归来实现。树的宽度要遍历的数组中的每一个元素,是循环的第一层。

k个不相同数相加为n的组合

思路

1.递归函数的返回值和参数
返回值是void类型,参数是传入的n与k。以及用sum记录当前的和。
2.终止条件
相加为n且是k个数;
3.单层递归的逻辑
一层循环下面,每次sum+i,压入;
回溯过程和处理过程一一对应。

代码

class Solution {
public:
    vector<int> path;
    vector<vector<int>> res;
    void backtrack(int n, int k,int sum, int startIndex) {
        if (sum == n&&path.size()==k) {
            res.push_back(path);
            return;
        }
        for (int i = startIndex; i <= 9; i++) {
            sum += i;
            path.push_back(i);
            backtrack(n, k, sum, i + 1);
            sum -= i;
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        int sum=0;
        backtrack(n,k,sum,1);
        return res;
    }
};

电话键有限数字对应的字母组合

思路

1.建立数字与字母的映射关系;const string lettermap[10]={,,}
2.树的宽度与递归的深度;
3.回溯过程
结果用一个字符串string s和一个字符串数组vector res保存;
<1>确定返回值(void)和参数(digits,int index);
<2>确定终止条件:string的长度和digit的长度相等;digits.size()==index
<3>单层循环逻辑
压入--遍历--弹出

代码

class Solution {
public:
    vector<string> res;
    string path;
    const string lettermap[10] = {",",   ",",   "abc",  "def", "ghi",
                                  "jkl", "mno", "pqrs", "tuv", "wxyz"};
    void backTrack(string&digits, int index) {
        if (index == digits.size()) {
            res.push_back(path);
            return;
        }
        // 建立数字--字母映射
        int digit = digits[index] - '0'; // 把字符类型转化为int;
        string letters = lettermap[digit]; // 建立数字和字母的对应关系;
        for (int i = 0; i <letters.size() ; i++) {
            path.push_back(letters[i]);
            backTrack(digits, index + 1);
            path.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        backTrack(digits, 0);
        return res;
    }
};
posted on 2025-11-26 15:44  FAfa_C++  阅读(5)  评论(0)    收藏  举报