文章目录
回溯
回溯模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
组合问题
LeetCode77. 组合:从n个无重复数中选取k个数的组合,不可以重复选取,组合不可重复;
LeetCode216. 组合总和Ⅲ:从1~9中选取k个和为n的数的组合,不可以重复选取,组合不可重复;
LeetCode39. 组合总和:从一个无重复元素的数组中选取和为target的数的组合,可以重复选取,组合不可重复;
LeetCode40. 组合总和Ⅱ:从有重复元素的数组中选取和为target的数的组合,元素不可以重复选取,组合不可重复。
LeetCode77. 组合
题目描述:给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
链接:https://leetcode-cn.com/problems/combinations
class Solution {
public:
vector<vector<int>> ans; //存放符合条件结果的集合
vector<int> path; //存放符合条件的结果
void backtracking(int n, int k, int startindex) {
//终止条件
if (path.size() == k) {
ans.push_back(path);
return;
}
for (int i = startindex; i <= n; i++) {
path.push_back(i); //处理节点
backtracking(n, k, i + 1); //递归
path.pop_back(); //回溯,撤销处理结果
}
}
vector<vector<int>> combine(int n, int k) {
backtracking(n, k, 1);
return ans;
}
};
剪枝优化:
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
void backtracking(int n, int k, int startindex) {
if (path.size() == k) {
ans.push_back(path);
return;
}
for (int i = startindex; i <= n - (k - path.size()) + 1; i++) { //剪枝优化
path.push_back(i);
backtracking(n, k, i + 1);
path.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
backtracking(n, k, 1);
return ans;
}
};
分割问题
LeetCode131. 分割回文串
题目描述:给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是 回文串 。返回 s
所有可能的分割方案。
链接:https://leetcode.cn/problems/palindrome-partitioning
class Solution {
public:
vector<vector<string>> ans;
vector<string> path;
void dfs(string& s, int index) {
if (index >= s.size()) {
ans.push_back(path);
return;
}
for (int i = index; i < s.size(); i++) {
string temp = s.substr(index, i - index + 1);
if (isPalindrome(temp)) {
path.push_back(temp);
dfs(s, i + 1);
path.pop_back();
}
}
}
bool isPalindrome(const string& s) {
int left = 0;
int right = s.size() - 1;
while (left <= right) {
if (s[left] == s[right]) {
left++;
right--;
}else return false;
}
return true;
}
vector<vector<string>> partition(string s) {
dfs(s, 0);
return ans;
}
};
LeetCode93. 复原IP地址
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。
例如:“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “192.168@1.1” 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 ‘.’ 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
链接:https://leetcode.cn/problems/restore-ip-addresses
class Solution {
public:
vector<string> ans;
string path;
void dfs(string& s, int index, int num) {
//已经完成一组分割
if (num == 3) {
string cur = s.substr(index, s.size() - index + 1);
if (isValid(cur)) {
path += cur;
ans.push_back(path);
path.erase(path.end() - cur.size(), path.end());
}
return;
}
for (int i = index; i < s.size(); i++) {
string temp = s.substr(index, i - index + 1);
if (isValid(temp)) {
path += temp;
path += ".";
num++;
dfs(s, i + 1, num);
path.erase(path.end() - 1, path.end());
path.erase(path.end() - temp.size(), path.end());
num--;
}
}
}
bool isValid(const string& s) {
if (s.size() >= 4 || s.size() == 0) return false;
if (s.size() == 3) {
if (s[0] == '0') return false;
if ((s[0] - '0') * 100 + (s[1] - '0') * 10 + s[2] - '0' > 255) return false;
}
if (s.size() == 2) {
if (s[0] == '0') return false;
}
return true;
}
vector<string> restoreIpAddresses(string s) {
dfs(s, 0, 0);
return ans;
}
};
子集问题
LeetCode78. 子集
题目描述:给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集不能包含重复的子集。你可以按 任意顺序 返回解集。
链接:https://leetcode.cn/problems/subsets
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
void dfs(vector<int>& nums, int index) {
ans.push_back(path);
if (index >= nums.size()) return;
for (int i = index; i < nums.size(); i++) {
path.push_back(nums[i]);
dfs(nums, i + 1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
dfs(nums, 0);
return ans;
}
};
LeetCode90. 子集Ⅱ
题目描述:给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
链接:https://leetcode.cn/problems/subsets-ii
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
void dfs(vector<int>& nums, int index) {
ans.push_back(path);
if (index >= nums.size()) return;
for (int i = index; i < nums.size(); i++) {
if (i > index && nums[i] == nums[i - 1]) continue; //遇到重复元素则跳过
path.push_back(nums[i]);
dfs(nums, i + 1);
path.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
dfs(nums, 0);
return ans;
}
};
LeetCode491. 递增子序列
给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
链接:https://leetcode.cn/problems/increasing-subsequences
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
void dfs(vector<int>& nums, int index) {
if (path.size() > 1) ans.push_back(path);
if (index >= nums.size()) return;
unordered_set<int> st;
for (int i = index; i < nums.size(); i++) {
if (st.find(nums[i]) == st.end() && (path.size() == 0 || (path.size() > 0 && nums[i] >= path.back()))) {
st.insert(nums[i]);
path.push_back(nums[i]);
dfs(nums, i + 1);
path.pop_back();
}else continue;
}
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
dfs(nums, 0);
return ans;
}
};
排列问题
LeetCode46. 全排列
题目描述:给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
链接:https://leetcode.cn/problems/permutations
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
void dfs(vector<int>& nums, vector<bool> used) {
if (path.size() == nums.size()) {
ans.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (used[i] == false) {
path.push_back(nums[i]);
used[i] = true;
dfs(nums, used);
path.pop_back();
used[i] = false;
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<bool> used(nums.size(), false);
dfs(nums, used);
return ans;
}
};
LeetCode47. 全排列Ⅱ
题目描述:给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
链接:https://leetcode.cn/problems/permutations-ii
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
void dfs(vector<int>& nums, vector<bool>& used) {
if (path.size() == nums.size()) {
ans.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) continue;
if (used[i] == false) {
used[i] = true;
path.push_back(nums[i]);
dfs(nums, used);
path.pop_back();
used[i] = false;
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<bool> used(nums.size(), false);
dfs(nums, used);
return ans;
}
};