回溯总结

 

解题思路:
1.DFS 和回溯算法区别
DFS 是一个劲的往某一个方向搜索,而回溯算法建立在 DFS 基础之上的,但不同的是在搜索过程中,达到结束条件后,恢复状态,回溯上一层,再次搜索。因此回溯算法与 DFS 的区别就是有无状态重置

2.何时使用回溯算法
当问题需要 "回头",以此来查找出所有的解的时候,使用回溯算法。即满足结束条件或者发现不是正确路径的时候(走不通),要撤销选择,回退到上一个状态,继续尝试,直到找出所有解为止

3.怎么样写回溯算法(从上而下,※代表难点,根据题目而变化)
①画出递归树,找到状态变量(回溯函数的参数),这一步非常重要※
②根据题意,确立结束条件
③找准选择列表(与函数参数相关),与第一步紧密关联※
④判断是否需要剪枝
⑤作出选择,递归调用,进入下一层
⑥撤销选择

 

 17. 电话号码的字母组合(dfs)

 

括号生成

22. Generate Parentheses(回溯)

 

子集、组合 子集、子集 II、组合、组合总和、组合总和 II

39. Combination Sum(回溯)

class Solution {
public:
    vector<vector<int>> res;
    void backtrack(vector<int>& candidates, vector<int>& path, int start, int sum, int target) {
        if(target==sum) {
            res.push_back(path);
        }
        for (int i = start; i < candidates.size(); ++i ) {
            if(sum > target) {
                continue;
            }
            path.push_back(candidates[i]);
            backtrack(candidates,path,i, sum+candidates[i],target);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<int> path;
        backtrack(candidates,path,0,0,target);
        return res;
    }
};

 

 

 

 

 

40. Combination Sum II

 

class Solution {
public:
    vector<vector<int>> res;
    void backtrack(vector<int>& candidates, vector<int>& path, int start, int sum, int target) {
        if(target == sum) {
            res.push_back(path);
        }
        for(int i = start; i < candidates.size(); ++i) {
            if(target < sum) {
                continue;
            }
            if (i>start && candidates[i-1]==candidates[i]) {
                continue;
            }
            path.push_back(candidates[i]);
            backtrack(candidates,path,i+1,sum+candidates[i],target);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<int> path;
        sort(candidates.begin(),candidates.end());
        backtrack(candidates,path,0,0,target);
        return res;
    }
};

 

 

 216. Combination Sum III

class Solution {
public:
    vector<vector<int>> res;
    void backtrack(vector<int>& path,int k ,int n,int sum, int start) {
        if (path.size() == k && sum == n) {
            res.push_back(path);
            return;
        }
        for(int i = start; i <= 9 ; ++i) {
            if(sum > n) {
                continue;
            }
            path.push_back(i);
            backtrack(path,k,n,sum+i,i+1);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        vector<int> path;
        backtrack(path,k,n,0,1);
        return res;
    }
};

 

 

 377. Combination Sum IV

 

 

 77. Combinations(回溯)

 

class Solution {
public:
    vector<vector<int>> res;
    void dfs(vector<int>& path, int n, int k, int level) {
        if (path.size() == k) {
            res.emplace_back(path);
            return;
        }
        for (int i = level; i <= n; i++) {
            path.emplace_back(i);
            dfs(path,n,k,i+1);
            path.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        vector<int> path;
        dfs(path,n,k,1);
        return res;

    }
};

 

 

 

78. Subsets(回溯)

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

 

 79. Word Search (dfs)

 

90. Subsets II

 

class Solution {
public:
    vector<vector<int>> res; 
    void backtrack(vector<int>& nums, vector<int>&path, int start) {
        res.push_back(path);
        for(int i = start; i < nums.size(); ++i) {
            if(i > start && nums[i]== nums[i-1]) {
                continue;
            }
            path.push_back(nums[i]);
            backtrack(nums,path,i+1);
            path.pop_back();
        }
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<int> path = vector<int>();
        sort(nums.begin(),nums.end());
        backtrack(nums,path,0);
        return res;
    }
};

 

 

 

 

全排列 全排列、全排列 II、字符串的全排列、字母大小写全排列

再次总结:“排列”类型问题和“子集、组合”问题不同在于:“排列”问题使用used数组来标识选择列表,而“子集、组合”问题则使用start参数。另外还需注意两种问题的判重剪枝!

 

46. Permutations (全排列)

 

class Solution {
public:
    vector<vector<int>> res;
    void backtrack(vector<int>& nums, vector<int>& path, vector<bool>& used) {
        if (nums.size() == path.size()) {
            res.push_back(path);
            return;
        }
        for(int i = 0;i < nums.size(); ++i) {
            if(!used[i]) {
                path.push_back(nums[i]);
                used[i] = true;
                backtrack(nums,path,used);
                path.pop_back();
                used[i] = false;
            }
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<int> path;
        vector<bool> used(nums.size(),false);
        backtrack(nums,path, used);
        return res;
    }
};

 

 

47. Permutations II (全排列有重复的元素)

 

class Solution {
public:
    vector<vector<int>> res;
    void backtrack(vector<int>& nums,vector<int>& path, vector<bool>& used) {
        if(nums.size() == path.size()) {
            res.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); ++i) {
            if(!used[i]) {
                if(i >0 && nums[i]==nums[i-1]&&used[i-1]) {
                continue;
            }
                path.push_back(nums[i]);
                used[i] = true;
                backtrack(nums,path,used);
                path.pop_back();
                used[i] = false;
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<int> path;
        sort(nums.begin(),nums.end());
        vector<bool> used(nums.size(),false);
        backtrack(nums,path,used);
        return res;
    }
};

 

 

131. Palindrome Partitioning(回文子串划分 深度优先)

 

 搜索 解数独、单词搜索、N皇后、分割回文串、二进制手表

 

51. N-Queens(回溯-搜索)  

 

class Solution {
public:
    vector<vector<string>> res;
    void backtrack(vector<string>& board,int level,int n) {
        if(level == n) {
            res.push_back(board);
        }
        for(int i = 0; i < n; ++i) {
            if (valid(board, level, i,n)) {
                board[level][i] = 'Q';
                backtrack(board,level+1,n);
                board[level][i] = '.';
            }
        }
    }
    bool valid(vector<string>& board, int level, int index,int n) {
        // 检查列
        for (int i = level-1; i >= 0; --i) {
            if (board[i][index] == 'Q') {
                return false;
            }
        }
        // 检查45度角 
        for (int li = level -1 , ii = index -1 ;ii >= 0 && li >= 0;--li,--ii) {
            if (board[li][ii]=='Q') {
                return false;
            }
        }
        // 检查135度角
        for (int li = level - 1, ii = index + 1 ; li >=0 && ii < n;--li,++ii) {
            if (board[li][ii] == 'Q') {
                return false;
            }
        }
        return true;
    }
    vector<vector<string>> solveNQueens(int n) {
        vector<string> board = vector<string>(n,string(n,'.'));
        backtrack(board,0,n);
        return res;
    }
};

 

37. Sudoku Solver

 

class Solution {
public:
    bool backtrack(vector<vector<char>>& board) {
        for(int level = 0; level < board.size(); ++level) {
            for (int index = 0; index < board[0].size();++index) {
                if (board[level][index] != '.') continue;
                for (char val = '1';val <='9';val++) {
                    if(valid(board,level,index,val)) {
                        board[level][index] = val;
                        if(backtrack(board)) return true;
                        board[level][index] = '.';
                    }
                }
                return false;
            }
        }
        return true;
    }

    bool valid(vector<vector<char>>& board, int level, int index, char val) {
        // 检查列
        for(int i = 0; i < 9 ;++i) {
            if (board[i][index] == val ) {
                return false;
            }
        }
        // 检查行
        for (int i = 0;i < 9; ++i) {
            if (board[level][i] == val) {
                return false;
            }
        }
        // 检查小方格
        int start_level = (level /3) *3;
        int start_index = (index /3) *3;
        for(int i = start_level; i < start_level+3;++i ) {
            for(int j = start_index; j <start_index+3;++j) {
                if (board[i][j] == val) {
                    return false;
                }
            }
        }
        return true;
    }


    void solveSudoku(vector<vector<char>>& board) {
        backtrack(board);
    }
};

 

作者:show-me-the-code-2

链接:https://leetcode-cn.com/problems/subsets/solution/c-zong-jie-liao-hui-su-wen-ti-lei-xing-dai-ni-gao-/

posted @ 2018-04-21 20:15  乐乐章  阅读(150)  评论(0编辑  收藏  举报