LeetCode刷题记录(回溯篇)
LeetCode刷题记录(回溯篇),个人向。
[46] Permutations
难度:Medium
语言:C++
题目描述。
使用used
来记录当前已使用的元素,尝试增加used
,递归调用,记录path
,在path
长度达到nums.size()
时将结果记录到result
即可。
class Solution {
public:
void backtracking(vector<int> &nums, vector<bool> &used, vector<int> &path,
vector<vector<int>> &result) {
int size = nums.size();
if (path.size() == size) {
result.push_back(path);
return;
}
for (int i = 0; i < size; ++i) {
if (used[i]) {
continue;
}
used[i] = true;
path.push_back(nums[i]);
backtracking(nums, used, path, result);
path.pop_back();
used[i] = false;
}
return;
}
vector<vector<int>> permute(vector<int> &nums) {
vector<bool> used(nums.size(), false);
vector<int> path;
vector<vector<int>> result;
backtracking(nums, used, path, result);
return result;
}
};
[78] Subsets
难度:Medium
语言:C++
题目描述。
相比上一题求全排列,这一题的不同点有二:
- 我们要求的是子集,单个集合不要求包含所有元素,因此在这棵递归树上,我们要求的不止是叶子节点,而是所有节点。因此不是在递归结束的时候记录结果,而是每次调用都记录一下结果。
- 相比全排列,集合对元素的顺序不再做要求。因此相比之前使用
used
数组,这里可以只记录startIndex
,然后每次递归从startIndex
往后遍历,来做到包含不同的元素组合。
class Solution {
public:
void backtracking(vector<int> &nums, int startIndex, vector<int> &path,
vector<vector<int>> &result) {
int size = nums.size();
result.push_back(path);
for (int i = startIndex; i < size; ++i) {
path.push_back(nums[i]);
backtracking(nums, i + 1, path, result);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int> &nums) {
vector<int> path;
vector<vector<int>> result;
backtracking(nums, 0, path, result);
return result;
}
};
[17] Letter Combinations of a Phone Number
难度:Medium
语言:C++
题目描述。
构造一个mapping
用来存数字到字母的映射,同时用mapping[digits[startIndex] - '2']
来取这个映射。回溯部分和之前大同小异,更新一下startIndex,同时记录路径,最后加进result
即可。
class Solution {
public:
const vector<string> mapping = {"abc", "def", "ghi", "jkl",
"mno", "pqrs", "tuv", "wxyz"};
void backtracking(string &digits, int startIndex, string &path,
vector<string> &result) {
int size = digits.size();
if (startIndex >= size) {
if (size > 0) {
result.push_back(path);
}
return;
}
string chars = mapping[digits[startIndex] - '2'];
int numChars = chars.size();
for (int i = 0; i < numChars; ++i) {
path.push_back(chars[i]);
backtracking(digits, startIndex + 1, path, result);
path.pop_back();
}
}
vector<string> letterCombinations(string digits) {
vector<string> result;
string path;
backtracking(digits, 0, path, result);
return result;
}
};
[39] Combination Sum
难度:Medium
语言:C++
题目描述。
对回溯的代码逐渐熟练,同样是一次写出答案。
和之前的代码大同小异。这里因为candidates[i]
是大于0的,所以出现new_sum == target
就不用继续递归了。
当我们选择了某个数字,则以后的递归只会考虑该数字以及之后的数字,不再考虑之前的数字,这保证了结果的唯一性(不出现重复组合)。
这道题的关键在于数字是可以重复使用的,这里我们用递归参数所使用的index
为i
而不是i+1
来体现。
class Solution {
public:
void backtracking(const vector<int> &candidates, const int target,
int index, int cur_sum, vector<int> &choosen,
vector<vector<int>> &result) {
int size = candidates.size();
if (index >= size) {
return;
}
for (int i = index; i < size; ++i) {
int new_sum = cur_sum + candidates[i];
if (new_sum > target) {
continue;
}
choosen.push_back(candidates[i]);
if (new_sum == target) {
result.push_back(choosen);
// 0 will not appear in candidates, and 2 <= candidates[i] <= 40
// so no need to backtrack further
} else {
backtracking(candidates, target, i, new_sum, choosen, result);
}
choosen.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int> &candidates, int target) {
vector<int> choosen;
vector<vector<int>> result;
backtracking(candidates, target, 0, 0, choosen, result);
return result;
}
};