LeetCode Hot100---回溯

LeetCode-46. 全排列

1、题目描述

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

2、测试用例


输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

3、代码

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        int n = nums.size();
        vector<vector<int>> ans;
        vector<int> res;
        vector<bool> st(n);
        // 枚举到第 u 个数了
        auto dfs = [&](this auto &&dfs,int u){
            if(u == n) // 枚举到n个数字后,返回结果
            {
                ans.push_back(res);
                return ;
            }   
            for(int i = 0;i < n;i ++)
            {
                if(!st[i]) // 这个数字没有被访问过
                {
                    st[i] = true; // 标记访问过
                    res.push_back(nums[i]);// 记录答案
                    dfs(u+1); // 继续枚举下一个数
                    res.pop_back(); // 恢复现场
                    st[i] = false; // 恢复现场
                }
            }
        };
        dfs(0);
        return ans;
    }
};

LeetCode-78. 子集

1、题目描述

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

2、测试用例


输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

3、代码

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> ans;
        vector<int> res;
        int n = nums.size();
        auto dfs = [&](this auto && dfs,int u){
            if(u == n)
            {
                ans.push_back(res);
                return ;
            }
            // 不选第u个数字,直接枚举下一个
            dfs(u+1);
            
            // 选第u个数字,记录答案,并枚举下一个
            res.push_back(nums[u]);
            dfs(u+1);
            res.pop_back();
        };
        dfs(0);
        return ans;
    }
};

LeetCode-17. 电话号码的字母组合

1、题目描述

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

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

LeetCode Hot100---回溯_第1张图片

2、测试用例


输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]

3、代码

class Solution {
public:
    vector<string> letterCombinations(string digits) {
        // 每个数字对应的字母组合
        vector<string> h{"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        vector<string> ans;
        int n = digits.size();
        if(!n) return ans; // 边界条件
        string res;
        auto dfs = [&](this auto && dfs,int u){
            // 映射完成,返回答案
            if(u == n)
            {
                ans.push_back(res);
                return ;
            }
            for(int i = 0;i < h[digits[u] - '0'].size();i ++)
            {
                res += h[digits[u] - '0'][i]; // 记录答案
                dfs(u+1); // 枚举下一个数字
                res = res.substr(0,res.size() - 1); // 恢复现场
            }
        };
        dfs(0);
        return ans;
    }
};

LeetCode-39. 组合总和

1、题目描述

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

2、测试用例

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

3、代码

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> ans;
        vector<int> res;
        int n = candidates.size();
        auto dfs = [&](this auto && dfs,int u,int sum){
            // 边界条件,sum超过target 或者 n个数都枚举完了,记录答案          
            if(sum >= target || u == n)
            {
                if(sum == target)   
                    ans.push_back(res);
                return ;
            }
            // 不选第 u 个数,直接枚举下一个
            dfs(u+1, sum);

            // 选第u个数,选完还能继续选
            res.push_back(candidates[u]);
            dfs(u, sum + candidates[u]);
            res.pop_back();
        };
        dfs(0,0);
        return ans;
    }
};

LeetCode-22. 括号生成

1、题目描述

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

2、测试用例

输入:n = 3
输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]

3、代码

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        // 从任意位置截断,左括号的 数量必须大于等于右括号
        // 最终的左右括号数量必须相等
        vector<string> ans;
        string res;
        auto dfs = [&](this auto && dfs,int u,int s){
            if(u == 2 * n)
            {
                // s表示当前未匹配的左括号数量,如果枚举了2n个括号之后,s=0,说明满足条件,记录答案
                if(s == 0)  ans.push_back(res);
                return ;
            }
            // 选左括号
            if(s < n) // 总的左括号数量不能超过n个
            {
                res += '(';
                dfs(u + 1,s + 1);
                res = res.substr(0,res.size() - 1);
            }
            // 选右括号
            if(s > 0) // 如果前面没有左括号,不能加右括号
            {
                res += ')';
                dfs(u + 1,s - 1);
                res = res.substr(0,res.size() - 1);
            }
        };
        dfs(0,0);
        return ans;
    }
};

LeetCode-79. 单词搜索

1、题目描述

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

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

2、测试用例

LeetCode Hot100---回溯_第2张图片

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCB”
输出:false

3、代码

class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        int m = board.size(), n = board[0].size();
        vector st(m,vector<bool>(n,false));
        bool ok = false;
        int dx[4] = {0,0,1,-1},dy[4] = {1,-1,0,0};
        // 深度优先搜索
        auto dfs = [&](this auto && dfs, int u, int x, int y){
            if(u == word.size() ) // 匹配成功
            {
                ok = true;
                return;
            }
            // 枚举可能的下一个位置,
            for(int k = 0;k < 4;k ++)
            {
                int tx = x + dx[k], ty = y + dy[k];
                if(tx >= 0 && ty >= 0 && tx < m && ty < n && !st[tx][ty] && board[tx][ty] == word[u])
                {
                    st[tx][ty] = true; // 标记访问
                    dfs(u+1,tx,ty); 
                    st[tx][ty] = false; // 恢复现场
                }
            }
        };     
        for(int i = 0;i < m; i ++)
            for(int j = 0;j < n; j++)
                if(board[i][j] == word[0] && !ok)
                {
                    st[i][j] = true;
                    dfs(1,i,j);
                    st[i][j] = false;
                }
        return ok;   
    }
};

LeetCode-131. 分割回文串

1、题目描述

给你一个字符串 s,请你将 s 分割成一些 子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

2、测试用例

输入:s = “aab”
输出:[[“a”,“a”,“b”],[“aa”,“b”]]

3、代码

class Solution {
public:
    vector<vector<string>> partition(string s) {
        vector<vector<string>> ans;
        vector<string> res;
        int n = s.size();
        // 判断是否都为回文串
        auto is_palindrome = [](vector<string> str)->bool {
            
            for(int i = 0;i < str.size();i++)
            {
                int l = 0, r = str[i].size() - 1;
                while( l < r)
                    if(str[i][l ++] != str[i][r -- ]) return false;
            }
            return true;
        };
        // start表示还没有分割的子串的第一个字符的下标
        auto dfs = [&](this auto && dfs,int u,int start){
            if(u == n)
            {
                if(is_palindrome(res))
                    ans.push_back(res);
                return ;
            }
            // 不分割,start不变,继续往下累计
            // 最后一个字符必须要选,所以最后一个字符必须要分割
            if(u < n - 1)   dfs(u+1,start);

            // 分割,并更新start的位置
            res.push_back(s.substr(start,u - start + 1));
            dfs(u+1,u+1);
            res.pop_back();
        };
        dfs(0,0);
        return ans;
    }
};

LeetCode-51. N 皇后

1、题目描述

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

2、测试用例

LeetCode Hot100---回溯_第3张图片

输入:n = 4
输出:[[“.Q…”,“…Q”,“Q…”,“…Q.”],[“…Q.”,“Q…”,“…Q”,“.Q…”]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

3、代码

class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<bool> col(n),dg(2 * n + 1), udg(2 * n + 1);
        vector<vector<string>> ans;
        vector<string> res;
        // 枚举第u行
        auto dfs = [&](this auto &&dfs,int u){
            if( u == n )
            {
                ans.push_back(res);
                return ;
            }
            // 枚举第i列Q可能的位置
            for(int i = 0;i < n;i ++)
            {
                string tmp(n, '.');
                // Q 在哪一列、主对角线、辅对角线的标记
                if(!col[i] && !dg[i + u] && !udg[i - u + n])
                {
                    col[i] = dg[i + u] = udg[i - u + n] = true;
                    tmp[i] = 'Q';
                    res.push_back(tmp);
                    dfs(u + 1);
                    res.pop_back();    
                    col[i] = dg[i + u] = udg[i - u + n] = false;
                }
            }

        };
        dfs(0);
        return ans;
    }
};

你可能感兴趣的:(LeetCode,Hot,100,leetcode,算法,c++,深度优先)