图解力扣回溯及剪枝问题的模板应用

文章目录

选哪个的问题

17. 电话号码的字母组合

题目描述

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

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

示例 1:

复制代码
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例 2:

复制代码
输入:digits = ""
输出:[]

示例 3:

复制代码
输入:digits = "2"
输出:["a","b","c"]

提示:

  • 0 <= digits.length <= 4
  • digits[i] 是范围 ['2', '9'] 的一个数字。

解题代码

cpp 复制代码
class Solution {
    string MAPPING[10]= {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
public:
    vector<string> letterCombinations(string digits) {
        int n = digits.size();
        if(n == 0){
            return {};
        }
        vector<string> ans;
        string path(n, 0);
        auto dfs = [&](this auto&& dfs, int i){
            if(i == n){
                ans.push_back(path);
                return;
            }
            for(char c: MAPPING[digits[i] - '0']){
                path[i] = c;//元素覆盖
                dfs(i+1);
            }
        };
        dfs(0);
        return ans;

    }
};

图解

path存储每次得到的序列

核心代码:

cpp 复制代码
for(char c: MAPPING[digits[i] - '0']){
	path[i] = c;
    dfs(i+1);
}

复杂度

时间复杂度:O(N*4^N)

注意,每次ans.push_back(path);也需要N的时间,所以前面乘N

空间复杂度:O(N*4^N)

ans 存储所有字母组合,共有 O(4^n) 个组合,递归存了n个点

选不选的问题

78. 子集

题目描述

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

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

示例 1:

复制代码
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

复制代码
输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同

解题代码

cpp 复制代码
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        int n = nums.size();
        if(n == 0){
            return {};
        }
        vector<int> path;
        vector<vector<int>> ans;
        auto dfs = [&](this auto&& dfs, int i){
            if(i == n){
                ans.push_back(path);
                return;
            }
            dfs(i+1);//不选

            path.push_back(nums[i]);//选
            dfs(i+1);
            path.pop_back();//恢复现场
        };
        dfs(0);
        return ans;
    }
};

图解

选不选和排列问题有个区别是,如果某个数不被选择,空元素不能直接覆盖掉上一次递归中放在这个位置的元素,所以如果元素被选择,必须在递归结束后将该位置恢复到什么都没有的状态,也就是恢复现场,保证下一次递归不被影响。

复杂度

时间复杂度:O(N2^N)
空间复杂度:O(N
2^N)

两相转化

77. 组合

题目描述

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

复制代码
输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

示例 2:

复制代码
输入:n = 1, k = 1
输出:[[1]]

提示:

  • 1 <= n <= 20
  • 1 <= k <= n

解题代码

法一:按选哪个的思路
cpp 复制代码
class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<int> path;
        vector<vector<int>> ans;
        auto dfs = [&](this auto&& dfs, int i){
            int d = k - path.size();
            if(d == 0){ //取path长度合适的数组加入ans
                ans.push_back(path);
                return;
            }

            for(int j=i; j>=d; j--){
                path.push_back(j);
                dfs(j-1);
                path.pop_back();
            }
        };
        dfs(n);
        return ans;
    }
};
法二:按选不选的思路
cpp 复制代码
class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<int> path;
        vector<vector<int>> ans;
        auto dfs = [&](this auto&& dfs, int i){
            int d = k - path.size();
            if(d == 0){ //取path长度合适的数组加入ans
                ans.push_back(path);
                return;
            }

            if(i < d){
                return;
            }
            dfs(i-1);
            
            path.push_back(i);
            dfs(i-1);
            path.pop_back();
        };
        dfs(n);
        return ans;
    }
};

图解

选哪个:

这是剪枝后的情况,下面画一个正序、不引入d的没有剪枝的情况:

显然会冗余很多,代码也贴在这供大家参考:

cpp 复制代码
class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<int> path;
        vector<vector<int>> ans;
        auto dfs = [&](this auto&& dfs, int i){
        
            if(path.size() == k){ //取path长度合适的数组加入ans
                ans.push_back(path);
                return;
            }

            for(int j=i; j<=n; j++){
                path.push_back(j);
                dfs(j+1);
                path.pop_back();
            }
        };
        dfs(1);
        return ans;
    }
};
选不选

这种方法注意一点:只要不选,d就不会变,也就意味着两个节点如果是兄弟节点(父节点一样),那么他们的d相等,而一旦i < d,意味着这条线不可能出答案了,因为数字不够用,这个不只是剪枝,而且是必要的,不写会越界

复杂度

两个都是

时间复杂度:O(C(N,K)) (是排列组合的那个符号)

空间复杂度:O(N)


......可算画完了,好悬没给我累死

相关推荐
一只鱼^_8 分钟前
第十六届蓝桥杯大赛软件赛省赛 C/C++ 大学B组
c语言·c++·算法·贪心算法·蓝桥杯·深度优先·图搜索算法
Lounger6613 分钟前
107.二叉树的层序遍历II- 力扣(LeetCode)
python·算法·leetcode
竹下为生17 分钟前
LeetCode --- 444 周赛
算法·leetcode·职场和发展
freyazzr1 小时前
Leedcode刷题 | Day30_贪心算法04
数据结构·c++·算法·leetcode·贪心算法
callJJ6 小时前
从零开始的图论讲解(1)——图的概念,图的存储,图的遍历与图的拓扑排序
java·数据结构·算法·深度优先·图论·广度优先·图搜索算法
小美爱刷题12 小时前
力扣DAY46-50 | 热100 | 二叉树:展开为链表、pre+inorder构建、路径总和、最近公共祖先、最大路径和
算法·leetcode·链表
rigidwill66615 小时前
LeetCode hot 100—子集
数据结构·c++·算法·leetcode·职场和发展
阳洞洞15 小时前
leetcode 322. Coin Change
算法·leetcode·动态规划·完全背包问题
不要小瞧我啊八嘎o.0?16 小时前
图论整理复习
算法·深度优先·图论
不吃洋葱.18 小时前
力扣448.找到数组中所有消失的元素
数据结构·算法·leetcode