22.括号生成
class Solution
{
public:
vector<string> res;
vector<string> generateParenthesis(int n)
{
if (n == 0)
return {};
string track;
//可用的左括号和右括号数量
backtrack(n, n, track, res);
return res;
}
void backtrack(int left, int right, string &track, vector<string> &res)
{
//左括号剩的多,不合理
if (right < left)
return;
//数量小于0,肯定不合法
if (left < 0 || right < 0)
return;
//左右括号正好用完,得到一个合法组合
if(left==0&&right==0)
{
res.push_back(track);
return;
}
//放一个左括号
track.push_back('(');
backtrack(left - 1, right, track, res);
track.pop_back();//撤销选择
//放一个右括号
track.push_back(')');
backtrack(left, right-1, track, res);
track.pop_back();//撤销选择
}
};
46.全排列
法一:更好
class Solution
{
public:
vector<vector<int>> permute(vector<int>& nums)
{
vector<vector<int>> result;
permute(nums, result, 0);
return result;
}
void permute(vector<int>& nums, vector<vector<int>>& result, int first)
{
if (first == nums.size())
{
result.push_back(nums);
return;
}
for (int i = first; i < nums.size(); i++)
{
if (first != i)
swap(nums[first], nums[i]); //交换两数
permute(nums, result, first + 1);
if (first != i)
swap(nums[first], nums[i]);//换回来
}
}
};
法二
class Solution {
public:
vector<vector<int>> result;
vector<vector<int>> permute(vector<int>& nums) {
vector<int> track;
vector<bool> flag(nums.size(), false);//标记是否访问过了
backtrack(nums, track, flag);
return result;
}
void backtrack(vector<int>& nums, vector<int> &track,vector<bool>&flag) {
if(track.size() == nums.size()) {
result.push_back(track);
return;
}
int nums_size = nums.size();
for(int i = 0; i < nums_size; ++ i) {
//如果nums[i]还没被选择,即可供选择
if(!flag[i]) {
track.push_back(nums[i]);
flag[i] = true;
backtrack(nums, track,flag);
track.pop_back();
flag[i] = false;
}
}
}
};
47.全排列II
class Solution
{
public:
vector<vector<int>> result;
vector<vector<int>> permuteUnique(vector<int>& nums)
{
vector<int> track;
sort(nums.begin(), nums.end());//排序
vector<bool> flag(nums.size(), false); //标记是否反问过了
backtrack(nums, track, flag);
return result;
}
void backtrack(vector<int> nums, vector<int> track, vector<bool> flag)
{
if (track.size() == nums.size())
{
result.push_back(track);
return;
}
int nums_size = nums.size();
for (int i = 0; i < nums_size; ++i)
{
//如果nums[i]没有出现在track中,即可供选择
if (!flag[i])
{
//和上一题比,就增加了排序+下面两句
//当与前面的数字重复,并且前面的这数字被撤销了而不是正在使用
if (i > 0 && nums[i] == nums[i - 1] && !flag[i - 1])//剪枝,避免重复
continue;
track.push_back(nums[i]);
flag[i] = true;
backtrack(nums, track, flag);
track.pop_back();
flag[i] = false;
}
}
}
};
78.子集
class Solution {
public:
vector<vector<int>> res;
vector<vector<int>> subsets(vector<int>& nums) {
// 记录走过的路径
vector<int> track;
backtrack(nums, 0, track);
return res;
}
void backtrack(vector<int>& nums, int start, vector<int>& track) {
res.push_back(track);
// 注意 i 从 start 开始递增
for (int i = start; i < nums.size(); i++) {
// 做选择
track.push_back(nums[i]);
// 回溯
backtrack(nums, i + 1, track);
// 撤销选择
track.pop_back();
}
}
};
491. 递增子序列
思路:
哈希去重!回溯!
class Solution {
vector<vector<int>>res;
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
vector<int>cur;
dfs(cur, 0, nums);
return res;
}
void dfs(vector<int>&cur,int index, vector<int>& nums) {
if (cur.size() >= 2) {
res.push_back(cur);
}
/*if (index > nums.size())
return;*/
unordered_set<int>set;//哈希去重
for (int i = index; i < nums.size(); i++) {
if (set.count(nums[i]) || cur.size() && nums[i] < cur.back())
continue;
set.insert(nums[i]);
cur.push_back(nums[i]);
dfs(cur, i + 1, nums);//i+1不是index+1
cur.pop_back();//回溯
}
}
};
77.组合
剪枝优化
当前元素选择或不选择如何实现是难点
class Solution {
vector<vector<int>>res;
public:
vector<int>temp;
vector<vector<int>> combine(int n, int k) {
dfs(1,n,k);
return res;
}
void dfs(int cur, int n, int k) {
if(temp.size() + n - cur + 1 < k)//剪枝优化,不用继续dfs了,已经不可能是答案了
return;
if(temp.size() == k) {
res.push_back(temp);
return;
}
//考虑当前元素
temp.push_back(cur);
dfs(cur + 1, n, k);
temp.pop_back();//回溯
//不考虑当前元素
dfs(cur + 1,n, k);
}
};