今天开始正式刷回溯算法的题目了,由于之前学二叉树的时候已经提前接触过回溯的相关思想,所以听起来不是很费劲,今天的题目除了第一题看了视频讲解,其余两道题都是自己写出来的,用时还击败了100%的人,开心😊
77. 组合
这道题主要用来熟悉回溯算法的套路,回溯算法三部曲:1.确定输入参数和返回值(一般都是void);2.确定终止条件3.确定单层递归逻辑。
我感觉这个和之前二叉树的递归写法套路很像啊。回溯函数返回值为void,这就说明一般是需要定义全局变量来辅助操作的,回溯函数中就负责对这些全局变量进行操作。
这道题主要是一个排列组合问题,数学原理上没什么难的,重头戏在于剪枝,减去一些不必要的遍历情况。
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
vector<vector<int>> combine(int n, int k) {
BackTracking(n, k, 1);
return result;
}
void BackTracking(int n, int k, int Start_Index){
//确定终止条件
if(path.size() == k){
result.push_back(path);
return ;
}
//单层递归逻辑
for(int i = Start_Index; i <= n - (k - path.size()) + 1; i++){
path.push_back(i);
BackTracking(n, k, i + 1);
path.pop_back();
}
}
};
216.组合总和III
这道题和上一道题很像,区别在于组合里的树只能是1-9,且一个组合中的数字不能重复出现,组合中的数字之和必须等于目标值。那么这道题需要定义一个全局变量sum来记录当前数组中存储的元素之和,在遍历时,只需要判断当前的值是否小于等于n - sum,如果满足则进入循环体,否则直接退出循环(这就是一种剪枝的思路),在终止条件的判断上,不仅数组中的元素个数要满足要求,sum也必须恰好等于n才能将数组存入。
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
int sum = 0;
vector<vector<int>> combinationSum3(int k, int n) {
BackTracking(k, n, 1);
return result;
}
void BackTracking(int k, int n, int Start_Index){
//确认终止条件
if(path.size() == k && sum == n){
result.push_back(path);
return ;
}
//单层递归逻辑
for(int i = Start_Index; i <= n - sum && i <= 9; i++){
path.push_back(i);
sum += i;
BackTracking(k, n, i + 1);
sum -= i;
path.pop_back();
}
}
};
17.电话号码的字母组合
这道题本来是想看视频的,但是任务布置说先自己想想,然后想着想着就做出来了(●ˇ∀ˇ●),这道题需要建立一个哈希表,主要用map<char, vector>来实现,其中键为字符’2’ - ‘9’,值为对应的字符向量,里面存放数字字符对应的所有可能的字母,这道题需要用二重循环来实现,外层循环负责遍历数字字符串,内层循环负责将数字转化成字母,递归和回溯的逻辑写在内层循环中。
class Solution {
public:
vector<string> result;
string path;
map<char, vector<char>> My_Map = {
{'2', {'a', 'b', 'c'}}, {'3', {'d', 'e', 'f'}}, {'4', {'g', 'h', 'i'}},
{'5', {'j', 'k', 'l'}}, {'6', {'m', 'n', 'o'}}, {'7', {'p', 'q', 'r', 's'}},
{'8', {'t', 'u', 'v'}}, {'9', {'w', 'x', 'y', 'z'}}
};
vector<string> letterCombinations(string digits) {
BackTracking(digits, 0);
return result;
}
void BackTracking(string s, int Start_Index){
//确定终止条件
if(s.size() == 0) return ; //空字符串直接返回
if(path.size() == s.size()){
result.push_back(path);
return ;
}
//单层递归逻辑
for(int i = Start_Index; i < s.size(); i++){ //外层循环遍历数字字符串的所有字符
for(int j = 0; j < My_Map[s[i]].size(); j++){
//内层循环遍历某个数字对应的所有可能的字母
path += My_Map[s[i]][j];
BackTracking(s, i + 1);
path.resize(path.size() - 1);
}
}
}
};
nice!!!