回溯专题

回溯专题

1.DFS 和回溯算法区别
DFS 是一个劲的往某一个方向搜索,而回溯算法建立在 DFS 基础之上的,但不同的是在搜索过程中,达到结束条件后,恢复状态,回溯上一层,再次搜索。因此回溯算法与 DFS 的区别就是有无状态重置

2.何时使用回溯算法
当问题需要 “回头”,以此来查找出所有的解的时候,使用回溯算法。即满足结束条件或者发现不是正确路径的时候(走不通),要撤销选择,回退到上一个状态,继续尝试,直到找出所有解为止

3.怎么样写回溯算法(从上而下,※代表难点,根据题目而变化)
①画出递归树,找到状态变量(回溯函数的参数),这一步非常重要※
②根据题意,确立结束条件
③找准选择列表(与函数参数相关),与第一步紧密关联※
④判断是否需要剪枝
⑤作出选择,递归调用,进入下一层
⑥撤销选择

4.回溯问题的类型
这里先给出,我总结的回溯问题类型,并给出相应的 leetcode题目(一直更新),然后再说如何去编写。特别关注搜索类型的,搜索类的搞懂,你就真的搞懂回溯算法了,,是前面两类是基础,帮助你培养思维

类型 题目链接
子集、组合 子集、子集 II、组合、组合总和、组合总和 II
全排列 全排列、全排列 II、字符串的全排列、字母大小写全排列
搜索 解数独、单词搜索、N皇后、分割回文串、二进制手表
注意:子集、组合与排列是不同性质的概念。子集、组合是无关顺序的,而排列是和元素顺序有关的,如 [1,2] 和 [2,1] 是同一个组合(子集),但 [1,2] 和 [2,1] 是两种不一样的排列!!!!因此被分为两类问题

【LeetCode 90】

采用回溯法,要先排序必须,防止重复,另外还需要判重

class Solution {
public:

    vector<vector<int>> ret;
    
    void dfs(vector<int> nums,vector<int> path,int start)
    {
        ret.push_back(path);
        for(int i=start;i<nums.size();i++)
        {
            cout<<i<<endl;
            if(i>start&&nums[i]==nums[i-1])
            {
                continue;
            }

            path.push_back(nums[i]);
            dfs(nums,path,i+1);
            path.pop_back();

        }
    }

    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<int> path;
        dfs(nums,path,0);
        return ret;
    }
};

子集!=排列

子集是没有顺序的,排列是有顺序的

如果我们固定了(选择了)某个数,那么他的下一层的选择列表就是——除去这个数以外的其他数!!\比如,第一次选择了2,那么他的下一层的选择列表只有1和3;如果选择了3,那么他的下一层的选择列表只有1和2,那么这个时候就要引入一个used数组来记录使用过的数字

【LeetCode 46】

class Solution {
public:
    vector<vector<int>> ret;
    vector<int> path;
    
    void dfs(vector<int> nums,vector<int> path,int used[])
    {
        if(path.size()==nums.size())
        {
            ret.push_back(path);
            return;
        }

        for(int i=0;i<nums.size();i++)
        {

            if(used[i]==0)
            {
                path.push_back(nums[i]);
                used[i]=1;
                dfs(nums,path,used);
                used[i]=0;
                path.pop_back();
            }

        }
    }

    vector<vector<int>> permute(vector<int>& nums) {
        int used[nums.size()];
        memset(used,0,sizeof(used));
        dfs(nums,path,used);
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值