【LeetCode】39. 组合总和
题意:给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
思路:关键是可以重复选取,也就是我们标记每一次回溯选取的下标时,不需要进行+1操作
代码:
class Solution {
public:
vector<int> m_path;
vector<vector<int> > m_res;
void backtracking(vector<int> &candidates, int idx, int num)
{
if (0 == num)
{
m_res.push_back(m_path);
return;
}
else if (0 > num)
{
return;
}
for (int i = idx; i < candidates.size(); ++i)
{
m_path.push_back(candidates[i]);
backtracking(candidates, i, num - candidates[i]);
m_path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
backtracking(candidates, 0, target);
return m_res;
}
};
【LeetCode】40.组合总和II
题意:给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
思路:强烈建议画出选择树。为了保证每个数字在每个组合中只能使用一次,所以要有startidx。而candidates中有重复数字,但为了保证解集中不包含重复的组合,引入了used数组,表示下标为i的值是否已经选择,同时表示是否进入了下一层,从而避免同一层有两个相同元素。
代码:
class Solution {
public:
vector<int> m_path;
vector<vector<int>> m_res;
void backtracking(vector<int> &candidates, int num, int idx, vector<bool> &used)
{
if (0 == num)
{
m_res.push_back(m_path);
return;
}
else if (0 > num)
{
return;
}
for (int i = idx; i < candidates.size(); ++i)
{
if (0 < i && candidates[i] == candidates[i - 1] && !used[i - 1])
{
continue;
}
m_path.push_back(candidates[i]);
used[i] = true;
backtracking(candidates, num - candidates[i], i + 1, used);
m_path.pop_back();
used[i] = false;
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<bool> used(candidates.size());
backtracking(candidates, target, 0, used);
return m_res;
}
};
【LeetCode】131.分割回文串
题意:给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是
回文串 。返回 s 所有可能的分割方案。
思路:分割问题也看做回溯问题,选择树是切割的位置,每次判断切割出来的子串是否回文串,递归出口就是切割到了最后。
代码:
class Solution {
public:
vector<string> m_path;
vector<vector<string>> m_res;
bool isTrue(string s, int left, int right)
{
while (left < right)
{
if (s[left] == s[right])
{
++left;
--right;
}
else
{
return false;
}
}
return true;
}
void backtracking(string s, int idx)
{
if (idx == s.size())
{
m_res.push_back(m_path);
return;
}
for (int i = idx; i < s.size(); ++i)
{
if (isTrue(s, idx, i))
{
string str = s.substr(idx, i - idx + 1);
m_path.push_back(str);
}
else
{
continue;
}
backtracking(s, i + 1);
m_path.pop_back();
}
}
vector<vector<string>> partition(string s) {
backtracking(s, 0);
return m_res;
}
};
心态:“第七章 回溯算法part02” 拿下!
参考资料