重拾C++之菜鸟刷算法第11篇---回溯算法(上)

今天是个好日子,二月二龙抬头,龙年龙日龙抬头,顺风顺水好兆头,万事万物开好头,金银珠宝往家里走!offer往家走!

回溯算法

回溯法可以解决的问题

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

回溯三部曲

  1. 回溯函数模板返回值以及参数
  2. 回溯函数终止条件
  3. 回溯搜索的遍历过程
void backtracking(参数){
	if(终止条件){
		存放结果;
		return;
	}
	
	for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)){
		backtracking(路径,选择列表); // 递归
		回溯,撤销处理结果
	}
		
}

组合

for循环横向遍历,递归纵向遍历,回溯不断调整结果集

题目

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

77. 组合 - 力扣(LeetCode)

题解

class Solution {
public:
    // 创建一个全局变量来放path
    vector path;
    // 创建一个全局变量来放所有的path
    vector> result;
    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();
        }
    }
    vector> combine(int n, int k) {
        backtracking(n, k, 1);
        return result;
    }
};

可以剪枝的地方在递归中每一层的for循环所选择的位置,比如说for循环选择的起始位置之后的元素个数已不足k个,那么就没有必要再进行for循环

组合总和III

题目

找出所有相加之和为 nk 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

216. 组合总和 III - 力扣(LeetCode)

题解

class Solution {
public:
    vector path;
    vector> result;

    void backtracking(int n, int k, int startIndex){
        if(path.size() == k){ 
            if (accumulate(path.begin(), path.end(), 0) == n) result.push_back(path);
            else return;
        }

        for(int i = startIndex; i <= 9; i++){
            path.push_back(i);
            backtracking(n, k, i + 1);
            path.pop_back();
        }
    }
    vector> combinationSum3(int k, int n) {
        backtracking(n, k, 1);
        return result;
    }
};

电话号码的字母组合

题目

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

17. 电话号码的字母组合 - 力扣(LeetCode)

题解

index:是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。

class Solution {
public:
    vector result;
    string path;
    void backtracking(const string &digits, int index){
        if(index == digits.size()){
            result.push_back(path);
            return;
        }
        int digit = digits[index] - '0';
        string letters = letterMap[digit];
        for(int i = 0; i < letters.size(); i++){
            path.push_back(letters[i]);
            backtracking(digits, index + 1);
            path.pop_back();
        }
    }
    vector letterCombinations(string digits) {
        if(digits.size() == 0) return result;
        backtracking(digits, 0);
        return result;
    }
private:
    const string letterMap[10] = {
            "", //0
            "", //1
            "abc", //2
            "def", //3
            "ghi", //4
            "jkl", //5
            "mno", //6
            "pqrs", //7
            "tuv", //8
            "wxyz", // 9
        };
};

你可能感兴趣的:(C++算法,算法,c++,开发语言)