代码随想录算法训练营第25天|216.组合总和III、17.电话号码的字母组合

代码随想录算法训练营第25天|216.组合总和III、17.电话号码的字母组合

216.组合总和III

回溯三部曲

  • 回溯函数模板返回值及参数

依旧使用全局变量 res 和 path

vector> res;
vector path;
void backtracking(int targetSum, int k, int startIndex,int sum)
  • 回溯终止条件

只要取到了k个元素即可停止

if (path.size() == k) {
    if (sum == targetSum) res.push_back(path);
    return ;
}
  • 一次回溯搜索遍历过程

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

完整的代码:

class Solution {
private:
    vector> res;
    vector path;
    void backtracking(int targetSum, int k, int startIndex, int sum) {
        if (path.size() == k) {
            if (sum == targetSum) res.push_back(path);
            // 如果 个数满足,但是和不相等,直接返回
            return ;
        }
        for (int i = startIndex; i <= 9; ++i) {
    		sum += i;
        	path.push_back(i);
    		backtracking(targetSum, k,  i + 1, sum);
    		sum -= i;
    		path.pop_back();
		}
    }
public:
    vector > combinationSum3(int k, int n) {
        backtracking(n, k, 1, 0);
        return res;
    }
};

后序的改进就是可以进行剪枝操作,如果所选元素的和已经大于n,再往后面遍历是没有意义的,直接剪掉。

class Solution{
private:
    vector > res;
    vector path;
    void backtracking(int targetSum, int k, int startIndex, int sum) {
        // 剪枝
        if(sum > targetSum) return;
        if(path.size() == k) {
            if(sum == targetSum) result.push_back(path);
            return;
        }
        for(int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) {
            sum += i;
            path.push_back(i);
            backtracking(targetSum, k, i + 1, sum);
            sum -= i;  //回溯
            path.pop_back();
        }
    }
public:
    vector > combinationSum3(int k, int n) {
        backtracking(n, k, 1, 0);
        return res;
    }
};

17.电话号码的字母组合

如果使用暴力穷举,一旦字符串的长度上去,多层的for循环是不科学的,所以我们考考虑的首先还是回溯。首先考虑字符串的组成有,0-9。可以使用map或者二维数组来映射数字与字母之间的关系。

const string letterMap[10] = {
    "",  //0
    "",  //1
    "abc",  //2
    "def",  //3
    "ghi",  //4
    "jkl",  //5
    "mno",  //6
    "pqrs",  //7
    "tuv",  //8
    "wxyz"  //9
};

使用回溯三部曲:

  • 递归函数返回值与参数

需要定义两个全局变量

vector res;
string s;
// 使用index来记录遍历了第几个数字了
void backtracking(const string& digits, int index)
  • 回溯终止条件

if(index == digits.size()) {
    res.push_back(s);
    return ;
}
  • 单层循环的逻辑

// 字符转int
int digit = digits[index] - '0';
string letters = letterMap[digit];
for (int i = 0; i < letters.size(); ++i) {
    s.push_back(letters[i]);
    backtracking(digits, index + 1);
    s.popo_back();
}

全部的代码:

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

你可能感兴趣的:(日常小题,算法,leetcode,c++,数据结构)