回溯的基本模板:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { //横向遍历
处理节点;
backtracking(路径,选择列表); // 递归 纵向遍历
回溯,撤销处理结果
}
}
1. 电话号码的字母组合
1.1 思路
本题采用回溯的思想,因为需要通过电话号码的数字来得到相应的字母,所以需要一个hash来存储数字对应的字母,本题使用数组存十分方便。利用上述回溯的思想很容易得到结果。
1.2 代码
class Solution {
public:
const string letter[10] = {
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz"
};
vector<string> letterCombinations(string digits) {
vector<string> result;
string path = "";
if(digits.size() == 0)
return result;
trackbacking(result, path, 0, digits);
return result;
}
void trackbacking(vector<string>& result, string path, int i, string digits){
if(path.size() == digits.size()){
result.push_back(path);
return;
}
string le = letter[digits[i] - '0'];
for(int j = 0; j < le.size(); j++){
path.push_back(le[j]);
trackbacking(result, path, i + 1, digits);
path.pop_back();
}
}
};
2. 组合总和II
2.1 思路
本题中的数组中可能存在重复元素,但是题目规定不能有重复组合。因此,需要去重。去重有两种思路:先对数组进行排序,将重复元素放到一起。在同一层,不允许有重复元素,在不同层中,允许出现重复元素,从而达到题目中的去重效果。
1、使用一个bool变量来判断是否元素是在同一层中
2、通过index来判断是否元素在同一层中
if(!canrepeat && i > 0 && candidates[i] == candidates[i - 1]){
continue;
}
2.2 代码
//方法一
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void trackbacking(vector<int> candidates, int target, int sum, int index, bool canrepeat){
if(sum == target){
result.push_back(path);
return;
}
for(int i = index; i < candidates.size() && sum + candidates[i] <= target; i++){
if(!canrepeat && i > 0 && candidates[i] == candidates[i - 1]){
continue;
}
canrepeat = true; //每一层之间
path.push_back(candidates[i]);
sum += candidates[i];
trackbacking(candidates, target, sum, i + 1, canrepeat);
sum -= candidates[i];
path.pop_back();
canrepeat = false;
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)