首页 > 其他分享 >DFS:深搜+回溯+剪枝解决排列、子集问题

DFS:深搜+回溯+剪枝解决排列、子集问题

时间:2024-04-04 17:33:35浏览次数:23  
标签:剪枝 dfs nums int ret vector DFS 回溯 path

                                    创作不易,感谢三连支持!! 

一、全排列I

. - 力扣(LeetCode)

class Solution {
public:
    //全局变量
    vector<vector<int>> ret;
    vector<int> path;
    bool check[6];
    vector<vector<int>> permute(vector<int>& nums) 
    {
        dfs(nums);
        return ret;
    }

    void dfs(vector<int>& nums)
    {
        if(nums.size()==path.size()) {ret.push_back(path); return;}
        for(int i=0;i<nums.size();++i)
        {
            if(check[i]==false) //说明没选过
            {
                path.push_back(nums[i]);
                check[i]=true;//减枝
                dfs(nums);//继续去下一个找
                //回溯
                path.pop_back();
                check[i]=false;
            }
        }
    }
};

二、全排列II

. - 力扣(LeetCode)

 方案1:不合法就continue

class Solution {
public:
    vector<vector<int>> ret;
    vector<int> path;
    bool check[8];
    vector<vector<int>> permuteUnique(vector<int>& nums) 
    {
       sort(nums.begin(),nums.end());
       dfs(nums);
       return ret;
    }

    void dfs(vector<int>& nums)
    {
        if(nums.size()==path.size()) {ret.push_back(path);return;}
        //思路1:考虑不合法的选择 continue   思路2:考虑合法的才进dfs
        for(int i=0;i<nums.size();++i)
        {
        if(check[i]==true||(i!=0&&nums[i]==nums[i-1]&&check[i-1]==false))  continue;
        path.push_back(nums[i]);
        check[i]=true;
        dfs(nums);//去下一层找
        path.pop_back();
        check[i]=false;
        }
    }
};

方案2:合法才能进循环

class Solution {
public:
    vector<vector<int>> ret;
    vector<int> path;
    bool check[8];
    vector<vector<int>> permuteUnique(vector<int>& nums) 
    {
       sort(nums.begin(),nums.end());
       dfs(nums);
       return ret;
    }

    void dfs(vector<int>& nums)
    {
        if(nums.size()==path.size()) {ret.push_back(path);return;}
        //思路1:考虑不合法的选择 continue   思路2:考虑合法的才进dfs
        for(int i=0;i<nums.size();++i)
        {
        if(check[i]==false&&(i==0||nums[i]!=nums[i-1]||check[i-1]==true))  
        {
        path.push_back(nums[i]);
        check[i]=true;
        dfs(nums);//去下一层找
        path.pop_back();
        check[i]=false;
        }
        }
    }
};

三、优美的排列

. - 力扣(LeetCode)

class Solution {
public:  
    //类似全排列,可以交换位置但是不能重复
    int ret=0;
    bool check[16];
    int countArrangement(int n)
    {
       dfs(1,n);
       return ret;
    }

    void dfs(int pos,int n)
    {
        if(pos==n+1) {++ret;return;}
        for(int i=1;i<=n;++i)
        {
            if(check[i]==false&&(i%pos==0||pos%i==0))
            {
                 check[i]=true;
                 dfs(pos+1,n);
                 check[i]=false;
            }
        }
    }
};

四、子集I

. - 力扣(LeetCode)

 策略1:决策树以选不选作为参考,结果为叶子节点

class Solution {
public:
    //设置全局变量
    vector<vector<int>> ret;
    vector<int> path;//记录路径
public:
    vector<vector<int>> subsets(vector<int>& nums) 
    {
        dfs(nums,0);
        return ret;
    }
    void dfs(vector<int>& nums,int pos)
    {
        if(pos==nums.size()) { ret.push_back(path);  return;}
        //选 
        path.push_back(nums[pos]);
        dfs(nums,pos+1);
        path.pop_back();//回溯
        //不选
        dfs(nums,pos+1);
    }
};

策略2:决策树以选几个为参考,结果为全部节点 

class Solution {
public:
    //设置全局变量
    vector<vector<int>> ret;
    vector<int> path;
public:
    vector<vector<int>> subsets(vector<int>& nums) 
    {
        dfs(nums,0);
        return ret;
    }
    void dfs(vector<int>& nums,int pos)
    {
        ret.push_back(path);//每一个决策都是结果
        for(int i=pos;i<nums.size();++i)
        {
            path.push_back(nums[i]);
            dfs(nums,i+1);   
            path.pop_back();         
        }
    }
};

五、子集II

. - 力扣(LeetCode)

 

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

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

六、找出所有子集的异或总和再求和

. - 力扣(LeetCode)

class Solution {
    int sum=0;//记录总和
    int path=0;//记录路径
public:
    
    int subsetXORSum(vector<int>& nums) 
    {
      dfs(nums,0);
      return sum;
    }

    void dfs(vector<int>& nums,int pos)
    {
        sum+=path;
        for(int i=pos;i<nums.size();++i)
        {
            path^=nums[i];
            dfs(nums,i+1);
            path^=nums[i];//利用消消乐的性质恢复现场
        }
    }
};

七、字母大小写全排列

. - 力扣(LeetCode)

class Solution {
public:
    vector<string> ret; //找返回值
    vector<string> letterCasePermutation(string s) 
    {
       dfs(s,0);
       return ret;
    }

    void dfs(string s,int pos)//用传值s 可以直接在原来的s上进行修改
    {
        while(pos<s.size()&&isdigit(s[pos])) ++pos;
        if(pos==s.size()) {ret.push_back(s); return;}
        //变
        s[pos]^=32;  //^=32(空格)可以完成大小写转化!!
        dfs(s,pos+1);
        s[pos]^=32;
        //不变
        dfs(s,pos+1);
    }
};

八、下一个排列

. - 力扣(LeetCode)

class Solution {
public:
    void nextPermutation(vector<int>& nums) 
    {
        if(nums.size()==1) return;//如果只有一个数,就没有必要去修改了
      //思路,找尽可能靠右的低位,与一个尽可能小的大数交换 然后再升序后面的剩余元素
      for(int i=nums.size()-2;i>=0;--i)
      {
        if(nums[i]<nums[i+1]) 
        {
           for(int j=nums.size()-1;j>i;--j)
           {
            if(nums[i]<nums[j]) //找到第一个比i大,
            {
                swap(nums[i],nums[j]);
                sort(nums.begin()+i+1,nums.end());//i位置后面的数升序
                return;//此时返回结果
            }
           }
          }
      }
      //如果循环结束都没有找到第一个升序的,说明是全逆序,此时的结果应该是把你直接变成升序
      sort(nums.begin(),nums.end());
    }
};

九、排列序列

. - 力扣(LeetCode)​​​​​​

class Solution {
public:
    string getPermutation(int n, int k) 
    {
      vector<int> factorial(n);//用来统计各个阶乘
      factorial[0]=1;
      for(int i=1;i<n;++i)//统计1——(n-1)!的阶乘
      {
        factorial[i]= factorial[i-1]*i;
      }
      --k;//康托展开 
      vector<int> check(n+1,1);//可选数
      string ret;
      ret.reserve(n);
      for(int i=1;i<=n;++i)
      {
        int order=k/factorial[n-i]+1;//确定了康拖的首位
          for(int j=1;j<=n;++j)//告诉check数组,该位置得是0 不能再选
             {
                order-=check[j];
                if(order==0)
                {
                    ret.push_back(j+'0');
                    check[j]=0;//说明此数被选过
                    break;
                }
             }
             k%=factorial[n-i];//去找下一个数
      }
          return ret;
    }
};

     排列和子集问题就总结到这啦!!回溯有关的题关键就是画树状图,然后根据树状图去思考怎么进行深搜、回溯和剪枝!!

标签:剪枝,dfs,nums,int,ret,vector,DFS,回溯,path
From: https://blog.csdn.net/weixin_51142926/article/details/137202778

相关文章

  • dfs 序求 LCA!
    前言为什么用dfs序求LCA而不用欧拉序?帅常数小,也就一半好玩反正没什么正经理由。正文定义dfs序是指对树进行深度优先遍历后得到的节点序列。\(\mathit{dfn}_i\)是节点\(i\)在dfs序中的位置(从\(0\)或\(1\)开始无影响)。LCA是最近公共祖先。深度\(\ma......
  • dfs 序求 LCA!
    前言为什么用dfs序求LCA而不用欧拉序?帅常数小,也就一半好玩反正没什么正经理由。正文定义dfs序是指对树进行深度优先遍历后得到的节点序列。\(\mathit{dfn}_i\)是节点\(i\)在dfs序中的位置(从\(0\)或\(1\)开始无影响)。LCA是最近公共祖先。深度\(\ma......
  • 代码随想录 Day29 回溯算法 491.递增子序列 46.全排列 47.全排列 II
    491.递增子序列classSolution{private:vector<vector<int>>result;vector<int>path;voidbacktracking(vector<int>&nums,intstartIndex){if(path.size()>1){result.push_back(path);......
  • 剑指Offer题目笔记25(使用回溯法解决其他类型问题)
    面试题85:问题:​输入一个正整数n,输出所有包含n个左括号和n个右括号的组合,要求每个组合的左括号和右括号匹配。解决方案:​使用回溯法。因为要生成n个左括号和n个右括号,故需要走2n步,每一步生成一个括号,每一步都面临两个选项,既可能生成左括号也可能生成右括号。有限制条......
  • 大数据实验统计-1、Hadoop安装及使用;2、HDFS编程实践;3、HBase编程实践;4、MapReduce编
    大数据实验统计1、Hadoop安装及使用;一.实验内容Hadoop安装使用:1)在PC机上以伪分布式模式安装Hadoop;2)访问Web界面查看Hadoop信息。二.实验目的1、熟悉Hadoop的安装流程。2、熟悉Hadoop访问Web界等基本操作。大数据实验一,Hadoop安装及使用-CSDN博客文章浏览阅读149次,点赞3......
  • DFS算法
    DFS,即深度优先搜索(Depth-FirstSearch),是一种用于遍历或搜索树或图的算法。它从起始节点开始,沿着树的深度尽可能远的路径探索,直到达到最深的节点,然后回溯到上一个节点,继续探索其他分支。DFS通常使用递归或栈来实现。以下是一些常见的DFS算法和应用:二叉树的DFS:在二叉树中,DF......
  • Hadoop——HDFS文件系统的Java API操作
    2.7.4org.apache.hadoophadoop-hdfs2.7.4org.apache.hadoophadoop-client2.7.4junitjunit4.12IDEA会自动保存文件并且导入依赖包,点击右侧的Maven,展开Dependencies,可以看到四个依赖包以及导入进来了三、初始化我们通过junit来进行测试,首先创建一个类,添加如下内......
  • 代码随想录算法训练营第二十五天(回溯2)|216. 组合总和 III、17. 电话号码的字母组合(JA
    文章目录216.组合总和III解题思路源码17.电话号码的字母组合解题思路源码216.组合总和III找出所有相加之和为n的k个数的组合,且满足下列条件:只使用数字1到9每个数字最多使用一次返回所有可能的有效组合的列表。该列表不能包含相同的组合两次,组合可......
  • 代码随想录算法训练营第二十七天(回溯3)|39. 组合总和、40. 组合总和 II、131. 分割回文
    文章目录39.组合总和解题思路源码40.组合总和II解题思路源码131.分割回文串解题思路源码39.组合总和给你一个无重复元素的整数数组candidates和一个目标整数target,找出candidates中可以使数字和为目标数target的所有不同组合,并以列表形式返回......
  • DFS(基础,回溯,剪枝,记忆化)搜索
    DFS基础DFS(深度优先搜索)基于递归求解问题,而针对搜索的过程对于问题的介入状态叫初始状态,要求的状态叫目标状态这里的搜索就是对实时产生的状态进行分析检测,直到得到一个目标状态或符合要求的最佳状态为止。对于实时产生新的状态的过程叫扩展搜索的要点:1.选定初始状态,......