LeetCode Hot 100:回溯

时间:2024-10-26 16:41:04

LeetCode Hot 100:回溯

46. 全排列

class Solution {
private:
    vector<vector<int>> ans;

public:
    vector<vector<int>> permute(vector<int>& nums) {
        if (nums.empty())
            return {};

        backtrace(nums, 0, (int)nums.size());
        return ans;
    }
    void backtrace(vector<int>& path, int level, int n) {
        if (level == n) {
            ans.push_back(path);
            return;
        }

        for (int i = level; i < n; i++) {
            swap(path[i], path[level]);
            backtrace(path, level + 1, n);
            swap(path[i], path[level]);
        }
    }
};

78. 子集

class Solution {
private:
    vector<vector<int>> ans;

public:
    vector<vector<int>> subsets(vector<int>& nums) {
        if (nums.empty())
            return {};

        vector<int> path;
        backtrace(nums, 0, (int)nums.size(), path);

        return ans;
    }
    void backtrace(vector<int>& nums, int level, int n, vector<int> path) {
        if (level == n) {
            ans.push_back(path);
            return;
        }

        path.push_back(nums[level]);
        backtrace(nums, level + 1, n, path);
        path.pop_back();
        backtrace(nums, level + 1, n, path);
    }
};

17. 电话号码的字母组合

class Solution {
private:
    unordered_map<char, string> dict{
        {'2', "abc"}, {'3', "def"},  {'4', "ghi"}, {'5', "jkl"},
        {'6', "mno"}, {'7', "pqrs"}, {'8', "tuv"}, {'9', "wxyz"}};

    vector<string> ans;

public:
    vector<string> letterCombinations(string digits) {
        if (digits.empty())
            return {};

        int n = digits.length();
        string path;
        backtrace(digits, 0, n, path);

        return ans;
    }
    void backtrace(string& digits, int level, int n, string path) {
        if (level == n) {
            ans.push_back(path);
            return;
        }

        char digit = digits[level];
        string s = dict[digit];

        for (char& c : s) {
            path.push_back(c);
            backtrace(digits, level + 1, n, path);
            path.pop_back();
        }
    }
};

39. 组合总和

class Solution {
private:
    vector<vector<int>> ans;

public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        if (candidates.empty())
            return {};

        int n = candidates.size();
        vector<int> path;
        backtrace(candidates, 0, n, target, path);

        return ans;
    }
    void backtrace(vector<int>& nums, int level, int n, int target,
                   vector<int> path) {
        if (level == n)
            return;
        if (accumulate(path.begin(), path.end(), 0) == target) {
            ans.push_back(path);
            return;
        }

        // 选 nums[level]
        if (accumulate(path.begin(), path.end(), 0) + nums[level] <= target) {
            path.push_back(nums[level]);
            backtrace(nums, level, n, target, path);
            path.pop_back();
        }
        // 不选 nums[level]
        backtrace(nums, level + 1, n, target, path);
    }
};

22. 括号生成

思路 1:回溯

class Solution {
private:
    vector<string> ans;

public:
    vector<string> generateParenthesis(int n) {
        if (n == 0)
            return {};

        string path;
        backtrace(0, 2 * n, path);

        return ans;
    }
    void backtrace(int level, int n, string path) {
        if (level == n) {
            if (isValid(path))
                ans.push_back(path);
            return;
        }

        path.push_back('(');
        backtrace(level + 1, n, path);
        path.pop_back();

        path.push_back(')');
        backtrace(level + 1, n, path);
        path.pop_back();
    }
    // 辅函数 - 判断字符串 s 是否有效
    bool isValid(const string& s) {
        int balance = 0;
        for (const char& c : s) {
            if (c == '(')
                balance++;
            else
                balance--;
            if (balance < 0)
                return false;
        }
        return balance == 0;
    }
};

思路 2:深度优先搜索

class Solution {
private:
    vector<string> ans;

public:
    vector<string> generateParenthesis(int n) {
        if (n == 0)
            return {};

        function<void(int, int, string)> dfs = [&](int left, int right, string str) {
            if (left < 0 || right < 0 || left > right)
                return;
            if (left == 0 && right == 0) {
                ans.push_back(str);
                return;
            }

            dfs(left - 1, right, str + '(');
            dfs(left, right - 1, str + ')');
        };

        dfs(n, n, "");

        return ans;
    }
};

79. 单词搜索

/*
 * @lc app=leetcode.cn id=79 lang=cpp
 *
 * [79] 单词搜索
 */

// @lc code=start
class Solution {
private:
    const int dx[4] = {0, 0, 1, -1};
    const int dy[4] = {1, -1, 0, 0};

public:
    // 主函数
    bool exist(vector<vector<char>>& board, string word) {
        if (board.empty())
            return false;

        int m = board.size(), n = m ? board[0].size() : 0;
        vector<vector<bool>> visited(m, vector<bool>(n, false));
        bool find = false;
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
                backtrack(i, j, 0, board, word, find, visited);

        return find;
    }
    // 辅函数(注意传引用,否则TLE)
    void backtrack(int i, int j, int level, vector<vector<char>>& board,
                   string& word, bool& find, vector<vector<bool>>& visited) {
        if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size())
            return;
        if (visited[i][j] || find || board[i][j] != word[level])
            return;
        if (level == word.size() - 1) {
            find = true;
            return;
        }

        visited[i][j] = true; // 修改当前节点状态
        // 递归子节点
        for (int k = 0; k < 4; k++) {
            int r = i + dx[k];
            int c = j + dy[k];
            backtrack(r, c, level + 1, board, word, find, visited);
        }
        visited[i][j] = false; // 回改当前节点状态
    }
};
// @lc code=end

131. 分割回文串

/*
 * @lc app=leetcode.cn id=131 lang=cpp
 *
 * [131] 分割回文串
 */

// @lc code=start

// 回溯

class Solution {
private:
    vector<vector<string>> ans;

public:
    vector<vector<string>> partition(string s) {
        int n = s.length();

        vector<string> path;
        backtrack(s, 0, n, 0, path);

        return ans;
    }
    void backtrack(string s, int level, int n, int start, vector<string> path) {
        if (level == n) {
            ans.push_back(path);
            return;
        }

        if (level < n - 1) {
            // 跳过当前字符 s[level]
            backtrack(s, level + 1, n, start, path);
        }

        if (isPalindrome(s, start, level)) {
            // s[start, level] 是一个回文串
            string tmp = s.substr(start, level - start + 1);
            path.push_back(tmp);
            // 下一个回文串从 level+1 开始
            backtrack(s, level + 1, n, level + 1, path);
            // 回溯
            path.pop_back();
        }
    }
    // 辅函数 - 判断字符串 s 的 [left, right] 部分是否回文
    bool isPalindrome(const string& s, int left, int right) {
        while (left < right) {
            if (s[left] != s[right])
                return false;
            left++;
            right--;
        }
        return true;
    }
};
// @lc code=end

51. N 皇后

class Solution {
private:
    vector<vector<string>> ans;

public:
    vector<vector<string>> solveNQueens(int n) {
        if (n == 0)
            return {};

        // 初始化棋局
        vector<string> board(n, string(n, '.'));
        // 每行每行放置皇后
        backtrack(board, 0, n);

        return ans;
    }
    void backtrack(vector<string> board, int row, int n) {
        if (row == n) {
            ans.push_back(board);
            return;
        }

        for (int col = 0; col < n; col++) {
            if (check(board, row, col, n) == false)
                continue;
            board[row][col] = 'Q';
            backtrack(board, row + 1, n);
            board[row][col] = '.';
        }
    }
    bool check(const vector<string>& board, int row, int col, int n) {
        // 同一列
        for (int i = 0; i < row; i++)
            if (board[i][col] == 'Q')
                return false;

        // 斜上方
        for (int i = row, j = col; i >= 0 && j >= 0; i--, j--)
            if (board[i]