当前位置: 首页 > news >正文

DFS:带重复项的全排列,程序运行全流程解析

1. 问题描述

给出一组可能包含重复项的数字,返回该组数字的所有排列,结果以字典序升序排列。

示例:

输入:[1,1,2]

返回值:[[1,1,2],[1,2,1],[2,1,1]]

2. 核心逻辑

在处理[1, 1, 2]时,由于含有两个 1,如果套用最基础的 DFS 模板,就会产生大量冗余的重复排列。

例如:

  • 当我们以第一个 1 为开头,可以得到[1, 1, 2][1, 2, 1]
  • 当我们以第二个 1 为开头,又会得到[1, 1, 2][1, 2, 1]

这样得到的结果就含有重复项。

要想去除掉重复项,需要按照下面的逻辑进行处理:

  • 首先将数组升序排列,让相同的数字放在一起。
  • 然后,在递归树的同一层,如果当前的数字和上一个数字相同且上一个数字已经尝试过了,那么当前这个数字就不应该再作为开头去尝试。

3. 完整C++代码实现

classSolution{public:/** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param num int整型vector * @return int整型vector<vector<>> */vector<vector<int>>res;boolused[8]={false};vector<int>path;voiddfs(vector<int>&num){if(path.size()==num.size()){res.push_back(path);return;}for(inti=0;i<num.size();i++){if(used[i])continue;//注意这里i>0很关键,我们肯定不会在第一次循环就进行剪枝if(i>0&&num[i]==num[i-1]&&!used[i-1])continue;used[i]=true;path.push_back(num[i]);dfs(num);path.pop_back();used[i]=false;}}vector<vector<int>>permuteUnique(vector<int>&num){//排序是剪枝的前提sort(num.begin(),num.end());dfs(num);returnres;}};

4. 程序运行全过程

假设输入数组已排序为nums = [1, 1, 2],我们来分析一下 DFS 的完整流程,大家可以对照上面的代码看下面的流程分析:

从根节点出发:

  1. 选择nums[0],此时used = [T, F, F]push_back之后path = [1]
  2. 进入第二层递归:
    • 由于used[0]true,所以会直接跳过第一轮for循环,选择第二轮for循环的nums[1],此时used = [T, T, F]push_back之后path = [1, 1]
    • 然后进入第三层递归:
      • 前两个used都为true,选择nums[2],此时used = [T, T, T]push_back之后path = [1, 1, 2]这是第一个结果
      • 在尝试进行第四次递归时,此时已经满足path.size() == num.size(),于是进行回溯
      • 回到第三层递归,执行pop_back并把used[2]置位false,当前used = [T, T, F]path = [1, 1]
      • 此时,for循环达到边界,跳出循环,本次dfs调用结束,进行回溯。
    • 回溯到第二层,执行pop_back并把used[1]置位false,当前used = [T, F, F]path = [1]
    • 然后进行第二层的下一轮for循环,此时选择nums[2]path = [1, 2]
      • 然后再进入第三次递归,选择nums[1],此时,path = [1, 2, 1]
      • 得到了第二个结果[1, 2, 1],然后进行回溯。
      • 此时,回溯到第二层之后,第二层递归的for循环也结束了,继续回溯。

程序又回到了根节点:

  • 撤销了num[0],此时used = [F, F, F]path = [],进入根节点的第二轮for循环。
  • 准备选择第二个 1 时,触发判断条件nums[1] == nums[0]used[0] == false,这意味着nums[0]刚刚作为开头已经完整试过了所有可能性,并退回了。
  • 这时执行剪枝,用continue直接跳过第二个 1 。

收尾:

  • 循环进入i = 2,选择 2 作为开头,此时path = [2]
  • 后续逻辑同上,最终得到[2, 1, 1]
http://www.jsqmd.com/news/603650/

相关文章:

  • 【研报287】小马智行深度报告:Robotaxi赛道的竞争格局
  • 212_视觉处理的基石:深入浅出卷积层(Convolutional Layer)
  • IBM V3700控制器更换实战:从503错误到系统恢复的全过程解析
  • 原木全屋定制工厂:优质厂商选择标准深度解析
  • 从LevelDB到自研PoolEngine:金融C++内存池测试演进史(2003–2024,12次重大架构迭代中的3次致命教训)
  • Venera开源漫画管理工具:从环境搭建到高级功能应用全指南
  • 关于对RNN,LSTM,BiLSTM算法的初步认识
  • XUnity.AutoTranslator:高性能Unity游戏实时翻译架构解析
  • 原型与原型链、原型属性学习笔记
  • STM32定时器级联功能实战:如何构建64位定时器
  • python boto3
  • Win11Debloat:轻松打造极速、纯净Windows 11的终极指南
  • 4大维度掌握AI音乐源分离:Demucs的技术突破与实践指南
  • 告别理论推导!用《有源滤波器的快速实用设计》手把手搞定1kHz带通滤波器(附Multisim仿真)
  • Kubernetes网络入门003篇【20260407】
  • 2026执医考试备考优质机构最新推荐_零基础、在职高效通过首选 - 医考机构品牌测评专家
  • npm国内镜像加速之使用 nrm 工具(灵活切换,适合多环境)
  • Linux新手必看:fdisk磁盘分区从入门到精通(含常见问题解决)
  • 19米LS型螺旋输送机设计【说明书+CAD图纸+开题报告+外文翻译】
  • 为什么92%的Python MCP项目在CI/CD阶段突然报错?揭秘被官方文档隐藏的4个环境依赖雷区
  • BallonsTranslator:基于深度学习的智能漫画翻译与排版解决方案
  • 2026执业药师考试机构全景测评:零基础、在职、二战考生高效备考优选 - 医考机构品牌测评专家
  • 云原生环境中的AI推理服务部署
  • 蓝桥杯单片机第12届省赛2满分(西风)
  • AI辅助开发新思路:让快马AI智能分析你的谷歌浏览器下载习惯
  • 探索 Z 源逆变器的多种 SPWM 仿真模型
  • ESP32智能股票监控系统:实时价格触发电话提醒(附完整代码)
  • 2026执业药师网课测评:零基础、在职、二战考生如何选择备考方案 - 医考机构品牌测评专家
  • 四旋翼姿态解算实战:MahonyAHRS算法中的初始姿态角优化策略
  • 3步实现OpenCore EFI智能生成:黑苹果配置效率提升96%的实战指南