前言
LeetCode题目:LeetCode 93、78、90
Takeaway:仍然是回溯算法的思路和模板,回溯算法的子集问题的处理方法(子集问题找全部节点,而不是只找叶子节点),最后一道题还是考同层去重和树枝去重的区别。
一、93
回溯法中的切割问题,需要start来避免重复切割,带一点字符串处理。
class Solution {
public:
vector<string> ans;
bool checkLegal(string &s, int start, int end){
if(start>end){
return false;
}
if(s[start]=='0' && start!=end){
return false;
}
int num = 0;
for(int i=start;i<=end;i++){
if(s[i]<'0' || s[i]>'9'){
return false;
}
num = num*10 + s[i]-'0';
if(num<0 || num>255){
return false;
}
}
return true;
}
// start 表示现切割到哪了; num 表示有几个逗号了
void traverse(string &s, int start, int num){
if(start>=s.size()){
return;
}
// 已经三个逗号,剩下的部分如果合法,那就对了
if(num == 3){
if(checkLegal(s, start, s.size()-1)){
ans.push_back(s);
}
return;
}
for(int i=start; i<s.size(); i++){
if(checkLegal(s, start, i)){
//字符串处理
s.insert(s.begin()+i+1,'.');
traverse(s, i+2, num+1);
s.erase(s.begin()+i+1);
}
}
}
vector<string> restoreIpAddresses(string s) {
traverse(s, 0, 0);
return ans;
}
};
二、78
回溯法中的子集问题,与分组和切割问题不同,后两个只关注叶子节点,而前者则关注所有节点(那怕只有一个元素,也是子集)。但是子集问题和组合有点像,不能重复取,所以需要start。
class Solution {
public:
vector<vector<int>> ans;
vector<int> each;
void traverse(vector<int>& nums, int start) {
if(start == nums.size()){
return;
}
for(int i=start; i<nums.size(); i++){
//子集类型题的特点就是收集所有节点
each.push_back(nums[i]);
ans.push_back(each);
traverse(nums, i+1);
each.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
traverse(nums, 0);
ans.push_back(each);
return ans;
}
};
三、90
回溯算法的子集问题,但是和昨天的切割问题中的去重有相似性,都需要进行同层去重(就是同一层不能有相同元素,因为同一层相同的话,后取的元素和先取的元素的结果集会重合)。
class Solution {
public:
vector<vector<int>> ans;
vector<int> each;
void traverse(vector<int>& nums, int start, vector<bool>& used) {
if(start >= nums.size()){
return;
}
for(int i=start; i<nums.size(); i++){
// 同层去重,
if(i>0 && nums[i]==nums[i-1] && used[i-1]==false){
continue;
}else{
each.push_back(nums[i]);
ans.push_back(each);
used[i] = true;
traverse(nums, i+1, used);
used[i] = false;
each.pop_back();
}
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
ans.push_back(each);
vector<bool> used(nums.size(), false);
traverse(nums, 0, used);
return ans;
}
};
总结
仍然是回溯算法的思路和模板,以及回溯算法的子集问题的处理方法(子集问题找全部节点,而不是只找叶子节点),最后一道题还是考同层去重和树枝去重的区别。