1. 找到所有子集(无重复)
输入: nums = [1,2,3] (没有重复)
输出: [[3],[1],[2],[1,2,3],[1,3],[2,3],[1,2],[]]
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> trace;
vector<vector<int>> res;
traceback(nums, 0, trace, res);
return res;
}
void traceback(vector<int> &nums, int pos,
vector<int> &trace, vector<vector<int>> &res) {
res.push_back(trace); // 结果输出
for(int i=pos; i<nums.size(); i++) { // 可行域搜索
trace.push_back(nums[i]); // 路径记录
traceback(nums, i+1, trace, res); // 回溯
trace.pop_back(); // 路径撤销
}
}
};
2. 找到所有子集(有重复)
输入: [1,2,2] (有重复)
输出: [[2],[1],[1,2,2],[2,2],[1,2],[]]
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end()); // 先排序
vector<int> trace;
vector<vector<int>> res;
traceback(nums, 0, trace, res);
return res;
}
void traceback(vector<int> &nums, int pos,
vector<int> &trace, vector<vector<int>> &res) {
res.push_back(trace); // 结果输出
for(int i=pos; i<nums.size(); i++) { // 可行域搜索
if(i != pos && nums[i] == nums[i-1]) continue; // 重复元素不可行
trace.push_back(nums[i]); // 路径记录
traceback(nums, i+1, trace, res); // 回溯
trace.pop_back(); // 路径撤销
}
}
};
3. 全排列(无重复)
输入: [1,2,3] (没有重复)
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<int> trace;
vector<vector<int>> res;
vector<int> visited(nums.size(), 0);
traceback(nums, visited, trace, res);
return res;
}
void traceback(vector<int> &nums, vector<int> &visited,
vector<int> &trace, vector<vector<int>> &res) {
if(trace.size() == nums.size())
res.push_back(trace); // 结果输出, 端点才输出
for(int i=0; i<nums.size(); i++) { // 可行域搜索
if(visited[i]) continue; // 已被访问, 不可行
trace.push_back(nums[i]); // 路径记录
visited[i] = 1;
traceback(nums, visited, trace, res); // 回溯
trace.pop_back(); // 路径撤销
visited[i] = 0;
}
}
};
4. 全排列(有重复)
输入: [1,1,2] (有重复)
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end()); // 先排序
vector<int> trace;
vector<vector<int>> res;
vector<int> visited(nums.size(), 0);
traceback(nums, visited, trace, res);
return res;
}
void traceback(vector<int> &nums, vector<int> &visited,
vector<int> &trace, vector<vector<int>> &res) {
if(trace.size() == nums.size())
res.push_back(trace); // 结果输出, 端点才输出
for(int i=0; i<nums.size(); i++) { // 可行域搜索
if(visited[i]) continue; // 已被访问, 不可行
// 这里 !visited[i-1] 确保上一元素没被访问过
// 这样可避免两一样的元素交换位置所造成的重复
if(i && nums[i] == nums[i-1] && !visited[i-1]) continue;
trace.push_back(nums[i]); // 路径记录
visited[i] = 1;
traceback(nums, visited, trace, res); // 回溯
trace.pop_back(); // 路径撤销
visited[i] = 0;
}
}
};
5. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,
找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
输入:candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end()); // 先排序
vector<int> trace;
vector<vector<int>> res;
traceback(candidates, target, trace, res);
return res;
}
void traceback(vector<int> &candidates, int remain,
vector<int> &trace, vector<vector<int>> &res) {
if(remain==0) res.push_back(trace);
for(int i=0; i<candidates.size(); i++) {
if(candidates[i]>remain) continue;
// 下面保证每次取的元素都不会比之前取的小以避免重复
if(trace.size() && candidates[i]<trace[trace.size()-1]) continue;
trace.push_back(candidates[i]);
traceback(candidates, remain-candidates[i], trace, res);
trace.pop_back();
}
}
};
6. 分割回文串
给定一个字符串 s,将 s 分割成一些子串,
使每个子串都是回文串。返回 s 所有可能的分割方案。
输入: "aab"
输出:
[
["aa","b"],
["a","a","b"]
]
class Solution {
public:
vector<vector<string>> partition(string s) {
// 用全排列的方法做
vector<string> trace;
vector<vector<string>> res;
traceback(s, 0, trace, res);
return res;
}
void traceback(string s, int pos,
vector<string> &trace, vector<vector<string>> &res) {
if (pos==s.size()) res.push_back(trace);
for(int i=pos+1; i<=s.size(); i++) {
if(!check(s.substr(pos, i-pos))) continue;
trace.push_back(s.substr(pos, i-pos));
traceback(s, i, trace, res);
trace.pop_back();
}
}
bool check(string s) {
if (s.size()==1) return true;
int i=0, j=s.size()-1;
while(i<j) {
if(s[i]!=s[j]) return false;
i++; j--;
}
return true;
}
};
7. 复原IP地址
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> trace;
vector<string> res;
if(s.size()>12) return res;
trackback(s, 0, trace, res);
return res;
}
void trackback(string s, int pos,
vector<string> &trace, vector<string> &res) {
if(pos==s.size()&&trace.size()==4) {
string temp;
for(int i=0;i<trace.size();i++) {
temp += trace[i];
if (i!=trace.size()-1) temp += ".";
}
res.push_back(temp);
}
for(int i=pos+1; i<=s.size()&&i<=pos+3; i++) {
if(!check(s.substr(pos, i-pos))) continue;
trace.push_back(s.substr(pos, i-pos));
trackback(s, i, trace, res);
trace.pop_back();
}
}
bool check(string s) {
int int_s;
stringstream ss; ss<<s; ss>>temp;
if(temp<0||temp>255) return false;
if(temp==0&&s.size()==1) return true; // 0.情况
for(char ch: s) { // 先导0情况
if (ch!='0') break;
else return false;
}
return true;
}
};