回溯法常见题目总结

1.电话号码的字母组合

题目描述:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例:

输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
实现代码:

class Solution {
public:
    vector<string> letterCombinations(string digits) {
        if(digits == ""){
            return res;
        }
        letter(digits,0,"");
        return res;
    }
private:
    string lett[10] = {
        " ",
        "",
        "abc",
        "def",
        "ghi",
        "jkl",
        "mno",
        "pqrs",
        "tuv",
        "wxyz"
    };
    vector<string>res;
    void letter(string digits,int index,string s){
    if(index == digits.size()){
        res.push_back(s);
        return;
    }
    char c = digits[index];
    string letters = lett[c - '0'];
    for(int i = 0;i < letters.size();i++){
        letter(digits,index + 1,s + letters[i]);
    }
    return;

}
};

2.括号生成

题目描述:

给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

例如,给出 n = 3,生成结果为:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]
实现代码:

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

3.组合总数

题目描述:

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

    所有数字(包括 target)都是正整数。
    解集不能包含重复的组合。

示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]

示例 2:

输入: 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) {
        vector<vector<int>>res;
        vector<int>tmp;
        int start = 0;
        combination(candidates,target,0,tmp,res);
        return res;
    }
private:
    void combination(vector<int>& candidates,int target,int start,vector<int>& tmp,vector<vector<int>>& res){
        if(target == 0){
            res.push_back(tmp);
            return;
        }
        for(int i = start;i < candidates.size();i++){
            if(target > 0){
                tmp.push_back(candidates[i]);
                combination(candidates,target - candidates[i],i,tmp,res);
                tmp.pop_back();
            }
            if(target < 0){
                return;
            }
        }
    }
};

4.组合总数Ⅱ

题目描述:

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

说明:

    所有数字(包括目标数)都是正整数。
    解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
  [1,2,2],
  [5]
]
实现代码:

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

     item.pop_back();
        }
    }
};

5.全排列

题目描述:

给定一个没有重复数字的序列,返回其所有可能的全排列。

示例:

输入: [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) {
        if(nums.size() == 0){
            return res;
        }
        stat = vector<bool>(nums.size(),false);
        generatePermute(nums,0,p);
        return res;
    }
private:
    vector<vector<int>> res;
    vector<int>p;
    vector<bool>stat;
    void generatePermute(vector<int> &nums,int index,vector<int> p){
        if(index == nums.size()){
            res.push_back(p);
            return;
        }
        for(int i = 0;i < nums.size();i++){
            if(!stat[i]){
                p.push_back(nums[i]);
                stat[i] = true;
                generatePermute(nums,index + 1,p);
                p.pop_back();
                stat[i] = false;
            }
        }
        return;
    }
};

6.全排列Ⅱ

题目描述:

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例:

输入: [1,1,2]
输出:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

实现代码:

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>>res1;
        if(nums.size() < 0){
            return res1;
        }
        visited = vector<bool>(nums.size(),false);
        vector<int>tmp;
        int k = 0;
        permute(nums,k,tmp);
        res1.assign(res.begin(),res.end());
        return res1;
    }
private:
    set<vector<int>>res;
    vector<bool>visited;
    void permute(vector<int>&nums,int k,vector<int>& tmp){
        if(k == nums.size()){
            res.insert(tmp);
            return;
        }
        for(int i = 0;i < nums.size();i++){
            if(!visited[i]){
                visited[i] = true;
                tmp.push_back(nums[i]);
                permute(nums,k + 1,tmp);
                tmp.pop_back();
                visited[i] = false;
            }
        }
        return;
    }
};

7.组合

题目描述:

给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。

示例:

输入: n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

实现代码:

class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        if(n == 0||k == 0||k > n){
            return res;
        }
        vector<int>p;
        generateCombine(n,k,1,p);
        return res;
    }
private:
    vector<vector<int>> res;
    void generateCombine(int n,int k,int start,vector<int> p){
        if(k == p.size()){
            res.push_back(p);
            return;
        }
        for(int i = start;i <= n;i++){
            p.push_back(i);
            generateCombine(n,k,i + 1,p);
            p.pop_back();
        }
        return;
    }
};

8.子集

题目描述:

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: 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) {
        if(nums.size() == 0){
            return res;
        }
        res.push_back(tmp);
        subset(nums,0,tmp);
        return res;
    }
private:
    vector<vector<int>> res;
    vector<int> tmp;
    void subset(vector<int> &nums,int start,vector<int> tmp){
        if(start == nums.size()){
            return;
        }
        for(int i = start;i < nums.size();i++){
            tmp.push_back(nums[i]);
            res.push_back(tmp);
            subset(nums,i + 1,tmp);
            tmp.pop_back();
        }
    }
};

9.子集Ⅱ

题目描述:

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

示例:

输入: [1,2,2]
输出:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

实现代码:

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

10单词搜索

题目描述:

给定一个二维网格和一个单词,找出该单词是否存在于网格中。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例:

board =
[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]

给定 word = "ABCCED", 返回 true.
给定 word = "SEE", 返回 true.
给定 word = "ABCB", 返回 false.

实现代码:

class Solution {
private:
    int d[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
    int m,n;
    bool inArea(int x,int y){
        return x >= 0 && x < m && y >= 0 && y < n;
    }
    vector<vector<bool>> tmp;
    bool isExist(vector<vector<char>>& board,string word,int index,int startx,int starty){
        if(index == word.size() - 1){
            return board[startx][starty] == word[index];
        }
        if(board[startx][starty] == word[index]){
            tmp[startx][starty] = true;
            for(int i = 0;i < 4;i++){
                int newx = startx + d[i][0];
                int newy = starty + d[i][1];
                if(inArea(newx,newy) && tmp[newx][newy] == false){
                    if(isExist(board,word,index + 1,newx,newy)){
                        return true;
                    }
                }
            }
            tmp[startx][starty] = false;
        }
        return false;
    }
public:
    bool exist(vector<vector<char>>& board, string word) {
        m = board.size();
        n = board[0].size();
        tmp = vector<vector<bool>>(m,vector<bool>(n,false));
        for(int i = 0;i < board.size();i++){
            for(int j = 0;j < board[i].size();j++){
                if(isExist(board,word,0,i,j)){
                    return true;
                }
            }
        }
        return false;
    }
};

11.岛屿数量

题目描述:

给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000

输出: 1

示例 2:

输入:
11000
11000
00100
00011

输出: 3
实现代码:

class Solution {
private:
    int d[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
    vector<vector<bool>>visited;
    int m,n;
    bool inArea(int x,int y){
        return x >= 0 && x < m && y >= 0 && y < n;
    }
    void dfs(vector<vector<char>> &grid,int startx,int starty){
        visited[startx][starty] = true;
        for(int i = 0;i < 4;i++){
            int newx = startx + d[i][0];
            int newy = starty + d[i][1];
            if(inArea(newx,newy) && !visited[newx][newy] && grid[newx][newy] == '1'){
                dfs(grid,newx,newy);
            }
        }
        return;
    }
public:
    int numIslands(vector<vector<char>>& grid) {
        m = grid.size();
        if(m == 0){
            return 0;
        }
        n = grid[0].size();
        int res = 0;
        visited = vector<vector<bool>>(m,vector<bool>(n,false));
        for(int i = 0;i < grid.size();i++){
            for(int j = 0;j < grid[i].size();j++){
                if(grid[i][j] == '1' && !visited[i][j]){
                    res++;
                    dfs(grid,i,j);
                }
            }
        }
        return res;
    }
};

posted @ 2019-08-16 20:25  小菜鸡的刨坑路  阅读(1549)  评论(0编辑  收藏  举报