回溯法

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;
    }
};
原文地址:https://www.cnblogs.com/xytpai/p/13870360.html