Leecode Hot100 刷题笔记本-回溯(C++版)

93 阅读1分钟
  1. 17. 电话号码的字母组合
  2. 39. 组合总和
  3. 46. 全排列
  4. 78. 子集

mp.weixin.qq.com/s/gjSgJbNbd…

回溯三部曲:

  1. 确定回溯参数
  2. 确定终止条件
  3. 确定单层遍历逻辑

17. 电话号码的字母组合

Screen Shot 2023-08-16 at 8.27.45 AM.png

解法1: 回溯
class Solution {
public:
    string tmp;
    vector<string> board = {"", "", "abc", "def", "ghi","jkl","mno","pqrs","tuv","wxyz"};
    vector<string> ans;
    
    void dfs(int pos, string digits){
        if(pos == digits.size()){
            ans.push_back(tmp);
            return;
        }
        int num = digits[pos] - '0'; //表示按到了键盘上的第几个键
        for(int i = 0; i < board[num].size(); i ++){
            tmp.push_back(board[num][i]);  
            dfs(pos + 1, digits);  //递归下一层
            tmp.pop_back();      //回溯
        }
    }
   
    vector<string> letterCombinations(string digits) {
        if(digits.size() == 0) return {};
        dfs(0, digits);
        return ans;
    }
};

Screen Shot 2023-08-16 at 9.38.54 AM.png

39. 组合总和

Screen Shot 2023-08-16 at 9.40.33 AM.png

解法1: 回溯

Screen Shot 2023-08-16 at 9.53.24 AM.png

class Solution {
public:
    void dfs(vector<int>& candidates, int target, vector<vector<int>>& ans, vector<int>& combine, int idx) {
        if (idx == candidates.size()) {
            return;
        }
        if (target == 0) {
            ans.emplace_back(combine);
            return;
        }
        // 直接跳过
        dfs(candidates, target, ans, combine, idx + 1);
        // 选择当前数
        if (target - candidates[idx] >= 0) {
            combine.emplace_back(candidates[idx]);
            dfs(candidates, target - candidates[idx], ans, combine, idx);
            combine.pop_back();
        }
    }

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> ans;
        vector<int> combine;
        dfs(candidates, target, ans, combine, 0);
        return ans;
    }
};

Screen Shot 2023-08-16 at 9.55.21 AM.png

46. 全排列

Screen Shot 2023-08-16 at 9.56.36 AM.png

解法1: 回溯

Screen Shot 2023-08-16 at 10.27.42 AM.png

class Solution {
public:
    void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len){
        // 所有数都填完了
        if (first == len) {
            res.emplace_back(output);
            return;
        }
        for (int i = first; i < len; ++i) {
            // 动态维护数组
            swap(output[i], output[first]);
            // 继续递归填下一个数
            backtrack(res, output, first + 1, len);
            // 撤销操作
            swap(output[i], output[first]);
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > res;
        backtrack(res, nums, 0, (int)nums.size());
        return res;
    }
};

Screen Shot 2023-08-16 at 10.25.33 AM.png

解法2: C++库函数
  • 直接调用C++库next_permutation
class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        do {
            result.emplace_back(nums);
        } while (next_permutation(nums.begin(), nums.end()));
        return result;
    }
};

78. 子集

Screen Shot 2023-08-16 at 10.28.50 AM.png Screen Shot 2023-08-16 at 10.47.05 AM.png

解法1: 回溯
class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& nums, int startIndex) {
        result.push_back(path); // 收集子集,要放在终止添加的上面,否则会漏掉自己
        if (startIndex >= nums.size()) { // 终止条件可以不加
            return;
        }
        for (int i = startIndex; i < nums.size(); i++) {
            path.push_back(nums[i]);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        result.clear();
        path.clear();
        backtracking(nums, 0);
        return result;
    }
};
  • 时间复杂度: O(n * 2^n)
  • 空间复杂度: O(n)