四、算法分类经典题目练习:递归、回溯与分治

递归回溯

回溯法:又称为试探法,即当探索到某一步时,发现原先的选择达不到目的,就退回一步重新选择

78.子集
<1>回溯法

class Solution {
     
public:
    vector<vector<int>> subsets(vector<int>& nums) {
     
        vector<int> item;
        vector<vector<int>> res;
        res.push_back(item);
        generate(0,nums,item,res);
        return res;
    }
    void generate(int i, vector<int>& nums, vector<int>& item, vector<vector<int>>& res){
     
        if(i>=nums.size())
            return;
        item.push_back(nums[i]);
        res.push_back(item);
        generate(i+1, nums, item, res);
        item.pop_back();
        generate(i+1, nums, item, res);
    }
};

<2>位运算

class Solution {
     
public:
    vector<vector<int>> subsets(vector<int>& nums) {
     
        int all_set = 1 << nums.size();
        vector<vector<int>> res;
        for(int i = 0; i < all_set; ++i){
     
            vector<int> item;
            for(int j = 0; j < nums.size(); ++j){
     
                if((1<<j)&i){
     
                    item.push_back(nums[j]);
                }
            }
            res.push_back(item);
        }
        return res;
    }
};

90.子集II
排序,set去重

class Solution {
     
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
     
        vector<vector<int>> res;
        set<vector<int>> res_set;
        int all_set = 1 << nums.size();
        sort(nums.begin(), nums.end());
        for(int i = 0; i < all_set; ++i){
     
            vector<int> item;
            for(int j = 0; j < nums.size(); ++j){
     
                if(i&(1<<j))
                    item.push_back(nums[j]);
            }
            if(res_set.find(item)==res_set.end()){
     
                res_set.insert(item);
                res.push_back(item);
            }
        }
        return res;
    }
};

40.组合总和II
在回溯过程中进行剪枝操作

class Solution {
     
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
     
        sort(candidates.begin(), candidates.end());
        vector<vector<int>> res;
        set<vector<int>> res_set;
        vector<int> item;
        generate(0, candidates, item, res, res_set, 0, target);
        return res;
    }
    void generate(int i, vector<int>& candidates, vector<int>& item, vector<vector<int>>& res, set<vector<int>>& res_set, int sum, int target){
     
        if(i>=candidates.size() || sum > target) return;
        sum += candidates[i];
        item.push_back(candidates[i]);
        if(sum==target && res_set.find(item)==res_set.end()){
     
            res_set.insert(item);
            res.push_back(item);
        }
        generate(i+1, candidates, item, res, res_set, sum, target);
        sum -= candidates[i];
        item.pop_back();
        generate(i+1, candidates, item, res, res_set, sum, target);       
    }
};

22.括号生成

class Solution {
     
public:
    vector<string> generateParenthesis(int n) {
     
        vector<string> res;
        generate("", n, n, res);
        return res;
    }
    void generate(string item, int left, int right, vector<string>& res){
     
        if(left==0&&right==0){
     
            res.push_back(item);
            return;
        }
        if(left > 0){
     
            generate(item+"(", left-1, right,res);
        }
        if(left < right){
     
            generate(item+")", left, right-1, res);
        }
    }
};

51.N皇后
回溯法

class Solution {
     
public:
    vector<vector<string>> solveNQueens(int n) {
     
        vector<vector<string>> res;
        vector<string> loc;
        vector<vector<int>> mark;
        for(int i = 0; i < n; ++i){
     
            mark.push_back(vector<int>(n,0));
            loc.push_back(string(n,'.'));
        }
        generate(0, n, mark, loc, res);
        return res;
    }
    void generate(int k, int n, vector<vector<int>>& mark, vector<string>& loc, vector<vector<string>>& res){
     
        if(k==n){
     
            res.push_back(loc);
            return;
        }
        for(int i = 0; i < n; ++i){
     
            if(mark[k][i]==0){
     
            vector<vector<int>> tmp_mark = mark;
            loc[k][i] = 'Q';
            put_down_queen(k,i,mark);
            generate(k+1, n, mark, loc, res);
            mark = tmp_mark;
            loc[k][i] = '.';
            }
        }
    }
    void put_down_queen(int x, int y, vector<vector<int>>& mark){
     
        static const int dx[] = {
     -1,1,0,0,-1,-1,1,1};
        static const int dy[] = {
     0,0,-1,1,-1,1,-1,1};
        for(int i = 1; i < mark.size(); ++i){
     
            for(int j = 0; j < 8; ++j){
     
                int new_x = x + i*dx[j];
                int new_y = y + i*dy[j];
                if(new_x >= 0 && new_y >= 0 && new_x <mark.size() && new_y < mark.size()){
     
                    mark[new_x][new_y] = 1;
                }
            }
        }
    }
};

分治法归并

分治算法:将一个规模为N的问题分解K规模较小的子问题,而且这些子问题相互独立且与原问题性质相同。求出子问题的解后进行合并,就可以得到原问题的解。

315.计算右侧小于当前元素的个数

class Solution {
     
public:
    vector<int> countSmaller(vector<int>& nums) {
     
        vector<pair<int,int>> vec;
        vector<int> count;
        for(int i = 0; i < nums.size(); ++i){
     
            vec.push_back(make_pair(nums[i], i));
            count.push_back(0);
        }
        merge_sort(vec,count);
        return count;
    }

    void merge_sort(vector<pair<int,int>>& vec, vector<int>& count){
     
        if(vec.size() < 2) return;
        int mid = vec.size()/2;
        vector<pair<int,int>> sub_vec1;
        vector<pair<int,int>> sub_vec2;
        for(int i = 0; i < mid; ++i){
     
            sub_vec1.push_back(vec[i]);
        }
        for(int i = mid; i < vec.size(); ++i){
     
            sub_vec2.push_back(vec[i]);
        }
        merge_sort(sub_vec1,count);
        merge_sort(sub_vec2,count);
        vec.clear();
        merge_sort_two_vec(sub_vec1,sub_vec2,vec,count);
    }

    void merge_sort_two_vec(vector<pair<int,int>>& sub_vec1, vector<pair<int,int>>& sub_vec2, vector<pair<int,int>>& vec, vector<int>& count){
     
        int i = 0, j = 0;
        while(i < sub_vec1.size() && j < sub_vec2.size()){
     
            if(sub_vec1[i].first <= sub_vec2[j].first){
     
                count[sub_vec1[i].second] += j;
                vec.push_back(sub_vec1[i]);
                i++;
            }else{
     
                vec.push_back(sub_vec2[j]);
                j++;
            }
        }
        for(; i < sub_vec1.size(); ++i){
     
            count[sub_vec1[i].second] += j;
            vec.push_back(sub_vec1[i]);
        }
        for(; j < sub_vec2.size(); ++j){
     
            vec.push_back(sub_vec2[j]);
        }
    }
};

你可能感兴趣的:(算法分类练习,算法,分治算法,递归法,leetcode)