递归|全排列

news/2024/7/20 20:04:51 标签: 深度优先, 算法

全排列一

题目描述

396b208af9768.png)

算法原理

  • 我们先把决策树画出来,根据决策树写代码,然后设计函数头

  • dfs函数用途就是从nums数组选数填入横线
    在这里插入图片描述
    就是有三个位置,我们把1 2 3填进这三个位置,而且保证不重复。
    比如我们第一冷选了1之后第二轮就不能选1了,打个红色的×。

  • 我们人的智慧一眼就知道前面选了1之后就不能选1了但是机器要怎么实现这一点呢?我们可以通过一个visited 数组实现这一点。

  • 如我们把visted数组全设为false 当 添加一个之后再设置为true

  • 我们还需要 path这个vector数组用来保存遍历的路径,ret 数组用来保证path每次遍历的结果

class Solution {
public:
    vector<int>path;
    vector<vector<int>>ret;
    int visted[7];
    void dfs(vector<int>& nums)
    {
        if (path.size() == nums.size())
        {
            ret.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++)
        {
            if (visted[i] != true)
            {
                path.push_back(nums[i]);
                visted[i] = true; 
                dfs(nums);
                visted[i] = false;
                path.pop_back(); 
            }
            // else
            // {
            //     return ;
            // }
           
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
      
        dfs(nums);
        return ret;
    }
};

魔鬼细节一:dfs(nums)后面的内容可以写在if外吗?

比如说下面这样

class Solution {
public:
    vector<int>path;
    vector<vector<int>>ret;
    int visted[7];
    void dfs(vector<int>& nums)
    {
        if (path.size() == nums.size())
        {
            ret.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++)
        {
            if (visted[i] != true)
            {
                path.push_back(nums[i]);
                visted[i] = true; 
               
            }
            dfs(nums);
            visted[i] = false;
            path.pop_back(); 
           
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
      
        dfs(nums);
        return ret;
    }
};

不可以因为这样会死递归
我们第二层还是从1开始的,1已经被遍历过了不会被if击中,就走下一层,下一次也是从1开始的,又走下一层。所以会死递归
在这里插入图片描述
从逻辑上解释只有我们上一层选择了一个数,下一层才开始选数

魔鬼细节二:我们剪枝的时候 可以用return吗?

比如下面这样

class Solution {
public:
    vector<int>path;
    vector<vector<int>>ret;
    int visted[7];
    void dfs(vector<int>& nums)
    {
        if (path.size() == nums.size())
        {
            ret.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++)
        {
            if (visted[i] != true)
            {
                path.push_back(nums[i]);
                visted[i] = true; 
                dfs(nums);
                visted[i] = false;
                path.pop_back(); 
            }
             else
             {
              return ;
             }
           
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
      
        dfs(nums);
        return ret;
    }
};

不可以,从代码执行的角度:我们从第二层返回到一层时,没有把所用情况遍历完,就把visted【i】,path恢复了。从逻辑上是希望第一层,最到最后一层才返回,而不是第二层有不符合条件的就返回第一层
#全排列二

题目描述

这道题和上一题唯一的区别就时nums数组元素可以重复了
比如 【1,1,2】 情况就没有 6种了
在这里插入图片描述

算法原理:

  • 和第一题差不多只是剪枝不一样
  • 当第一数选择 1 剩下 的数 112 和从第二位数选择1 剩下的数选择112 情况是一样的。
  • 下图蓝色的×表示 同一层相同两个数一样时应该跳过
  • 紫色的×表示一个数不能重复的选
    在这里插入图片描述

代码实现

class Solution {
public:
     vector<int> path;
    vector<vector<int>> ret;
    int visted[20];
    void dfs(vector<int>&nums)
    {
        if(path.size() == nums.size())
        {
            ret.push_back(path); 
            return ;
        }
        for(int i = 0; i < nums.size(); i++)
        {
            if(visted[i] == false && ( i == 0|| nums[i] != nums[i-1]  || visted[i-1] == true))
            {
                path.push_back(nums[i]);
                visted[i] = true;
                dfs(nums);
                path.pop_back();
                visted[i] = false;
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        dfs(nums);
        return ret;
    }
   
};

http://www.niftyadmin.cn/n/5472833.html

相关文章

【LeetCode热题100】【动态规划】杨辉三角

题目链接&#xff1a;118. 杨辉三角 - 力扣&#xff08;LeetCode&#xff09; 弄个二维数组&#xff0c;每个数是它左上方和右上方的数的和 class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>> ans(numRows);…

VMware虚拟机(Rocky9.3)硬盘扩容详细图文教程

参考<<鸟哥的Linux>>以及VMware虚拟机硬盘扩容详细图文教程 原因: 用户空间不足,且系统是用LVM&#xff08;logical volume manager&#xff09;进行分区 df -h #查看/home目录下磁盘容量不足磁盘扩容步骤 关闭虚拟机,选择编辑虚拟机, 点击硬盘,再点击扩容 这个…

MySQL 中datetime和timestamp

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 MySQL 中常用的两种…

大语言模型RAG项目实战

学习完大语言模型落地的关键技术&#xff1a;RAG的相关概念&#xff0c;我们今天来用代码实现一下RAG。 项目实战&#xff1a;基于百度ERNIE SDK 和 LangChain 搭建个人知识库。 1、安装ERNIE Bot !pip install --upgrade erniebot测试embedding import erniebot erniebot.…

四、Jenkins+SonarQube代码审查

JenkinsSonarQube代码审查 一、SonarQube简介二、Docker部署SonarQube1.下载镜像2.创建挂载目录3.运行容器4.访问 三、JenkinsSonarQube整合1.安装Sonar Scanner插件2.安装Sonar Scanner软件3.获取SonarQube的token4.在jenkins创建凭证5.配置SonarQube服务器6.非流水线项目整合…

【算法】有序数组的两数之和

题目 在一个有序数组中找到两个数&#xff0c;两个数之和为给定的一个数&#xff0c;返回两个数在数组中的下标。 原理 二分法 以第一个数为基准数&#xff0c;采用二分法寻找数组中与之相加等于给定数的数字&#xff0c;找到则返回下标&#xff0c;否则以第二个数为基准数…

Linux多进程通信(4)——消息队列从入门到实战!

Linux多进程通信总结——进程间通信看这一篇足够啦&#xff01; 1.基本介绍 1&#xff09;消息队列的本质其实是一个内核提供的链表&#xff0c;内核基于这个链表&#xff0c;实现了一个数据结构&#xff0c;向消息队列中写数据&#xff0c;实际上是向这个数据结构中插入一个…

Java集合详解(二)-- Map集合

Java集合详解&#xff08;一&#xff09;-- List集合 一、HashMap集合 1.HashMap示意图 2.HashMap的特点 3.HashMap的常用方法 ①.put(K key, V value) 将键&#xff08;key&#xff09;/值&#xff08;value&#xff09;映射存放到Map集合中 public class Test {public st…