zoukankan      html  css  js  c++  java
  • 回溯法

    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;
        }
    };
    
  • 相关阅读:
    用折半查找法找出整型数组中指定元素所在的位置,并输出(折半查找法只能用于有序数列)。
    统计母字符串中含有子串的个数。
    //插入排序法对数组中的元素按从小到大进行排序
    求斐波那契(fibonacci)数列前20项的值 ,递归调用
    C++实现一句英文句子中的单词逆置
    C语言-黑白棋(人机对战)
    第九届蓝桥杯-明码
    四连块dfs
    八连块dfs
    求素数
  • 原文地址:https://www.cnblogs.com/xytpai/p/13870360.html
Copyright © 2011-2022 走看看