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

算法妙妙屋-------1.递归的深邃回响:全排列的奇妙组合

全排列的简要总结

全排列(Permutation)是数学中一个经典的问题,指的是从一组元素中,将所有元素按任意顺序排列形成的所有可能序列。


特点

  1. 输入条件

    • 给定一组互异的元素(通常为数组或字符串)。
    • 例如:[1, 2, 3] 的全排列。
  2. 输出结果

    • 输出所有元素的排列组合。
    • 例如:[1, 2, 3] 的全排列是:
      [1, 2, 3]
      [1, 3, 2]
      [2, 1, 3]
      [2, 3, 1]
      [3, 1, 2]
      [3, 2, 1]
      
  3. 数量公式

    • 对于 n 个互异元素,其全排列数量为 n ! n! n!(阶乘)。
    • 例如:n = 3 时,全排列数量为 3 ! = 6 3! = 6 3!=6

实现方式

1. 递归法

通过递归交换或回溯实现:

#include <iostream>
#include <vector>
using namespace std;void backtrack(vector<int>& nums, int start, vector<vector<int>>& result) {if (start == nums.size()) {result.push_back(nums);return;}for (int i = start; i < nums.size(); i++) {swap(nums[start], nums[i]);           // 交换当前元素backtrack(nums, start + 1, result);  // 递归处理子问题swap(nums[start], nums[i]);           // 撤销交换(回溯)}
}int main() {vector<int> nums = {1, 2, 3};vector<vector<int>> result;backtrack(nums, 0, result);for (const auto& perm : result) {for (int num : perm) {cout << num << " ";}cout << endl;}return 0;
}
2. STL 函数

C++ 提供了 std::next_permutation,可以简单地生成字典序全排列:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;int main() {vector<int> nums = {1, 2, 3};do {for (int num : nums) {cout << num << " ";}cout << endl;} while (next_permutation(nums.begin(), nums.end()));  // 调用 STL 函数return 0;
}

应用场景

  1. 组合数学

    • 求解排列问题、旅行商问题等。
  2. 字符串操作

    • 对字符串生成不同排列,用于密码学、模式匹配等。
  3. 游戏与搜索

    • 如数独解法、八皇后问题等,依赖全排列进行搜索。
  4. 算法优化

    • 通过排列测试不同的输入顺序,寻找最优解。

优化与注意事项

  1. 剪枝优化

    • 在递归中排除不合法或重复的排列,提高效率。
  2. 重复元素

    • 如果输入包含重复元素,需要特殊处理以避免重复结果。
  3. 大规模问题

    • 对于规模较大的输入,因 n ! n! n! 增长较快,可能需要改用启发式算法。

全排列是基础的数学与算法问题,其思想在递归、动态规划和搜索算法中广泛应用!​

1.全排列

题目链接:全排列
题目概述:
在这里插入图片描述
解题思路:递归流程如下:

  1. ⾸先定义⼀个⼆维数组res⽤来存放所有可能的排列,⼀个⼀维数组ans⽤来存放每个状态的排
    列,⼀个⼀维数组visited标记元素,然后从第⼀个位置开始进⾏递归;
  2. 在每个递归的状态中,我们维护⼀个步数step,表⽰当前已经处理了⼏个数字;
  3. 递归结束条件:当step等于nums数组的⻓度时,说明我们已经处理完了所有数字,将当前数组
    存⼊结果中;
  4. 在每个递归状态中,枚举所有下标i,若这个下标未被标记,则使⽤nums数组中当前下标的元
    素:
    a. 将visited[i]标记为1;
    b. ans数组中第step个元素被nums[i]覆盖;
    c. 对第step+1个位置进⾏递归;
    d. 将visited[i]重新赋值为0,表⽰回溯;
  5. 最后,返回res。
    • 特别地,我们可以不使⽤标记数组,直接遍历step之后的元素(未被使⽤),然后将其与需要递
    归的位置进⾏交换即可。
class Solution {vector<vector<int>> it;vector<int> path;bool check[7];//check用来存储是否被使用过public:void dfs(vector<int>& nums, vector<int>& path) {if (path.size() == nums.size()) {it.push_back(path);}else {for (int a = 0; a < nums.size(); a++) {if (!check[a]) {path.push_back(nums[a]);check[a] = true;//标记,下次不能再选dfs(nums, path);check[a] = false;//回溯复原path.pop_back();}}}}vector<vector<int>> permute(vector<int>& nums) {dfs(nums, path);return it;}
};

2.子集

题目链接:子集
题目介绍:

在这里插入图片描述
解题思路:

  1. 递归结束条件:如果当前需要处理的元素下标越界,则记录当前状态并直接返回;
  2. 在递归过程中,对于每个元素,我们有两种选择:
    ◦ 不选择当前元素,直接递归到下⼀个元素;
    ◦ 选择当前元素,将其添加到数组末尾后递归到下⼀个元素,然后在递归结束时撤回添加操作;
  3. 所有符合条件的状态都被记录下来,返回即可。
class Solution {
public:vector<vector<int>> ret;vector<int> path;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);}vector<vector<int>> subsets(vector<int>& nums) {dfs(nums, 0);return ret;}
};

3.全排列||(!!!)

题目链接:全排列
题目介绍:
在这里插入图片描述
解题思路:
因此,我们需
要对相同元素定义⼀种规则,使得其组成的排列不会形成重复的情况:

  1. 我们可以将相同的元素按照排序后的下标顺序出现在排列中,通俗来讲,若元素s出现x次,则排序后的第2个元素s⼀定出现在第1个元素s后⾯,排序后的第3个元素s⼀定出现在第2个元素s后⾯,以此类推,此时的全排列⼀定不会出现重复结果。
  2. 例如:a1=1,a2=1,a3=2,排列结果为[1,1,2]的情况只有⼀次,即a1在a2前⾯,因为a2不会出现在a1前⾯从⽽避免了重复排列。
  3. 我们在每⼀个位置上考虑所有的可能情况并且不出现重复;
  4. 注意:若当前元素的前⼀个相同元素未出现在当前状态中,则当前元素也不能直接放⼊当前状态的数组,此做法可以保证相同元素的排列顺序与排序后的相同元素的顺序相同,即避免了重复排列出现。
  5. 通过深度优先搜索的⽅式,不断地枚举每个数在当前位置的可能性,并在递归结束时回溯到上⼀个状态,直到枚举完所有可能性,得到正确的结果。
class Solution {vector<int> path;vector<vector<int>> ret;bool check[9];public:vector<vector<int>> permuteUnique(vector<int>& nums) {sort(nums.begin(), nums.end());//先进行排序dfs(nums);return ret;}void dfs(vector<int>& nums) {if (path.size() == nums.size()) {ret.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {// 剪枝if (check[i] == false &&(i == 0 || nums[i] != nums[i - 1] || check[i - 1] != false))//非常的巧妙,想要插入必须满足以下要求   1.没有被插入过   2.第一位(没有前一项)||当前项和其前一项不一样||前一项已经被插入过了{path.push_back(nums[i]);check[i] = true;dfs(nums);path.pop_back(); // 恢复现场check[i] = false;}}}
};

4.括号生成(!!!)

题目链接:括号生成
题目介绍:在这里插入图片描述

解题思路:
从左往右进⾏递归,在每个位置判断放置左右括号的可能性,若此时放置左括号合理,则放置左括号
继续进⾏递归,右括号同理。
⼀种判断括号是否合法的⽅法:从左往右遍历,左括号的数量始终⼤于等于右括号的数量,并且左括
号的总数量与右括号的总数量相等。因此我们在递归时需要进⾏以下判断:

  1. 放⼊左括号时需判断此时左括号数量是否⼩于字符串总⻓度的⼀半(若左括号的数量⼤于等于字符
    串⻓度的⼀半时继续放置左括号,则左括号的总数量⼀定⼤于右括号的总数量);
  2. 放⼊右括号时需判断此时右括号数量是否⼩于左括号数量。
class Solution {
public:vector<string> str;void dfs(string it, int left,int right){if(left==0)//做括号全部用完{while(right){it.push_back(')');right--;}str.push_back(it);return;}it.push_back('(');//插入左括号dfs(it,left-1,right);it.pop_back();//回溯,回复现场if(right>left)//右括号剩余必须比左括号多{it.push_back(')');dfs(it,left,right-1);it.pop_back();//回溯}}vector<string> generateParenthesis(int n) {string it;int left=n;int right=n;it.push_back('(');//左边先插入一个(,避免第一个就是)的错误left--;dfs(it,left,right);return str;}
};

5.组合

题目链接:组合
题目介绍:
在这里插入图片描述
题⽬要求我们从1到n中选择k个数的所有组合,其中不考虑顺序。也就是说,[1,2]和[2,1]等价。我
们需要找出所有的组合,但不能重复计算相同元素的不同顺序的组合。对于选择组合,我们需要进⾏
如下流程:

  1. 所有元素分别作为⾸位元素进⾏处理;
  2. 在之后的位置上同理,选择所有元素分别作为当前位置元素进⾏处理;
  3. 为避免计算重复组合,规定选择之后位置的元素时必须⽐前⼀个元素⼤,这样就不会有重复的组合
    ([1,2]和[2,1]中[2,1]不会出现)。
class Solution {
public:bool check[20];vector<vector<int>> it;vector<int> flag;void dfs(int n, int k, int first) {if (k) {for (int i = first; i <= n; i++) {flag.push_back(i);dfs(n, k-1,i+1);flag.pop_back();}}else{it.push_back(flag);}}vector<vector<int>> combine(int n, int k) {dfs(n, k, 1);return it;}
};

相关文章:

算法妙妙屋-------1.递归的深邃回响:全排列的奇妙组合

全排列的简要总结 全排列&#xff08;Permutation&#xff09;是数学中一个经典的问题&#xff0c;指的是从一组元素中&#xff0c;将所有元素按任意顺序排列形成的所有可能序列。 特点 输入条件&#xff1a; 给定一组互异的元素&#xff08;通常为数组或字符串&#xff09;。…...

【maven-6】Maven 生命周期相关命令演示

Maven 是一个广泛使用的项目管理工具&#xff0c;尤其在 Java 项目中。它通过定义一系列的生命周期阶段&#xff08;Phases&#xff09;来管理项目的构建过程。理解这些生命周期阶段及其相关命令&#xff0c;对于高效地构建和管理项目至关重要。本文将通过实际演示&#xff0c;…...

黑马程序员Java笔记整理(day06)

1.继承的特点 2.继承的权限 3. 4.小结 5.方法重写 6.子类构造器 7.兄弟构造器 8.多态 9.小结...

LeetCode【代码随想录】刷题(动态规划篇)

509. 斐波那契数 力扣题目链接 题目&#xff1a;斐波那契数&#xff08;通常用F(n)表示&#xff09;形成的序列称为斐波那契数列 。该数列由0和1开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n…...

【看海的算法日记✨优选篇✨】第三回:二分之妙,寻径中道

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 一念既出&#xff0c;万山无阻 目录 &#x1f4d6;一、算法思想 细节问题 &#x1f4da;左右临界 &#x1f4da;中点选择 &#x1f4da;…...

基于yolov8、yolov5的铝材缺陷检测识别系统(含UI界面、训练好的模型、Python代码、数据集)

摘要&#xff1a;铝材缺陷检测在现代工业生产和质量管理中具有重要意义&#xff0c;不仅能帮助企业实时监控铝材质量&#xff0c;还为智能化生产系统提供了可靠的数据支撑。本文介绍了一款基于YOLOv8、YOLOv5等深度学习框架的铝材缺陷检测模型&#xff0c;该模型使用了大量包含…...

计算机光电成像理论基础

一、透过散射介质成像 1.1 光在散射介质中传输 光子携带物体信息并进行成像的过程是一个涉及光与物质相互作用的物理现象。这个过程可以分为几个步骤来理解&#xff1a; 1. **光的发射或反射**&#xff1a; - 自然界中的物体可以发射光&#xff08;如太阳&#xff09;&am…...

【QNX+Android虚拟化方案】125 - 如何创建android-spare镜像

【QNX+Android虚拟化方案】125 - 如何创建android-spare镜像 1. Android侧创建 (ext4 / sparse) test_img.img 镜像 方法一2. Android侧创建 (ext4 / sparse) test_img.img 镜像 方法二3. qnx 侧 分区透传Android 配置3.1 配置分区透传3.2 Android 侧分区 rename3.3 创建挂载目…...

深度学习基础小结_项目实战:手机价格预测

目录 库函数导入 一、构建数据集 二、构建分类网络模型 三、编写训练函数 四、编写评估函数 五、网络性能调优 鲍勃开了自己的手机公司。他想与苹果、三星等大公司展开硬仗。 他不知道如何估算自己公司生产的手机的价格。在这个竞争激烈的手机市场&#xff0c;你不能简单地…...

EMall实践DDD模拟电商系统总结

目录 一、事件风暴 二、系统用例 三、领域上下文 四、架构设计 &#xff08;一&#xff09;六边形架构 &#xff08;二&#xff09;系统分层 五、系统实现 &#xff08;一&#xff09;项目结构 &#xff08;二&#xff09;提交订单功能实现 &#xff08;三&#xff0…...

【随笔】AI技术在电商中的应用

这几年&#xff0c;伴随着ChatGPT开始的AI浪潮席卷全球&#xff0c;从聊天场景逐步向多场景扩散&#xff0c;形成了广泛开花的现象。至今&#xff0c;虽然在部分场景的进展已经略显疲态&#xff0c;但当前的这种趋势仍然还在不断的扩展。不少公司&#xff0c;甚至有不少大型电商…...

序列式容器详细攻略(vector、list)C++

vector std::vector 是 STL 提供的 内存连续的、可变长度 的数组(亦称列表)数据结构。能够提供线性复杂度的插入和删除,以及常数复杂度的随机访问。 为什么要使用 vector 作为 OIer,对程序效率的追求远比对工程级别的稳定性要高得多,而 vector 由于其对内存的动态处理,…...

快速启动项目

1 后端项目 https://gitee.com/liuyunkai666/gungun-boot.git 分支&#xff1a; mini 是 springboot3 jdk17 的基础版本&#xff0c;后续其他功能模块陆续在其基础上追加即可​。 1.1 必备环境 1.1.1 mysql 创建一个 自定义名称 数据库&#xff0c;【只要】 执行对应数据库…...

springboot347基于web的铁路订票管理系统(论文+源码)_kaic

摘 要 当今社会进入了科技进步、经济社会快速发展的新时代。计算机技术对经济社会发展和人民生活改善的影响也日益突出&#xff0c;人类的生存和思考方式也产生了变化。传统铁路订票管理采取了人工的管理方法&#xff0c;但这种管理方法存在着许多弊端&#xff0c;比如效率低…...

使用API管理Dynadot域名,在账户中添加域名服务器(Name Server)

前言 Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮箱&…...

【Linux | 计网】TCP协议深度解析:从连接管理到流量控制与滑动窗口

目录 前言&#xff1a; 1、三次握手和四次挥手的联系&#xff1a; 为什么挥手必须要将ACK和FIN分开呢&#xff1f; 2.理解 CLOSE_WAIT 状态 CLOSE_WAIT状态的特点 3.FIN_WAIT状态讲解 3.1、FIN_WAIT_1状态 3.2、FIN_WAIT_2状态 3.3、FIN_WAIT状态的作用与意义 4.理解…...

go语言的成神之路-筑基篇-对文件的操作

目录 一、对文件的读写 Reader 接口 Writer接口 copy接口 bufio的使用 ioutil库 二、cat命令 三、包 1. 包的声明 2. 导入包 3. 包的可见性 4. 包的初始化 5. 标准库包 6. 第三方包 7. 包的组织 8. 包的别名 9. 包的路径 10. 包的版本管理 四、go mod 1. 初始…...

两道数据结构编程题

1.写出在顺序存储结构下将线性表逆转的算法&#xff0c;要求使用最少的附加空间。 解&#xff1a;输入&#xff1a;长度为n的线性表数组A(1:n) 输出&#xff1a;逆转后的长度为n的线性表数组A(1:n)。 C语言描述如下&#xff08;其中ET为数据元素的类型&#xff09;&#xff1a;…...

【Qt】QDateTimeEdit控件实现清空(不保留默认时间/最小时间)

一、QDateTimeEdit控件 QDateTimeEdit 提供了一个用于编辑日期和时间的控件。用户可以通过键盘或使用上下箭头键来增加或减少日期和时间值。日期和时间的显示格式根据设置的格式显示&#xff0c;可以通过 setDisplayFormat() 方法来设置。 二、如何清空 我在使用的时候&#…...

12、字符串

1、字符串概念 字符串用来存储一组字符&#xff0c;因此需要字符数组来存。 C语言中字符串的表示 C语言里面字符串只能用字符数组来存 字符串要求这个数组的末尾必须至少有一个\0 char ch1[] {a,b,c}; // 不是字符串 char ch2[5] {h,e,l,l,o}; // 不是字符串 char…...

DPDK用户态协议栈-Tcp Posix API 1

和udp一样&#xff0c;我们需要实现和系统调用一样的接口来实现我们的tcp server。先来看看我们之前写的unix_tcp使用了哪些接口&#xff0c;这边我加上两个系统调用&#xff0c;分别是接收数据和发送数据。 #include <stdio.h> #include <arpa/inet.h> #include …...

【人工智能-科普】图神经网络(GNN):与传统神经网络的区别与优势

文章目录 图神经网络(GNN):与传统神经网络的区别与优势什么是图神经网络?图的基本概念GNN的工作原理GNN与传统神经网络的不同1. 数据结构的不同2. 信息传递方式的不同3. 模型的可扩展性4. 局部与全局信息的结合GNN的应用领域总结图神经网络(GNN):与传统神经网络的区别与…...

LabVIEW实现UDP通信

目录 1、UDP通信原理 2、硬件环境部署 3、云端环境部署 4、UDP通信函数 5、程序架构 6、前面板设计 7、程序框图设计 8、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利…...

[pdf,epub]228页《分析模式》漫谈合集01-45提供下载

《分析模式》漫谈合集01-45的pdf、epub文件提供下载。已上传至本号的CSDN资源。 如果CSDN资源下载有问题&#xff0c;可到umlchina.com/url/ap.html。 已排版成适合手机阅读&#xff0c;pdf的排版更好一些。 ★UMLChina为什么叒要翻译《分析模式》&#xff1f; ★[缝合故事]…...

Kafka的消费消息是如何传递的?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka的消费消息是如何传递的&#xff1f;】面试题。希望对大家有帮助&#xff1b; Kafka的消费消息是如何传递的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Kafka中&#xff0c;消息的消费是通过消费…...

二分查找(Java实现)(1)

二分查找&#xff08;Java实现&#xff09;&#xff08;1&#xff09; leetcode 34.排序数组中查找元素第一个和最后一个位置 题目描述: 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如…...

力扣103.二叉树的锯齿形层序遍历

题目描述 题目链接103. 二叉树的锯齿形层序遍历 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xff09;。 示例 1&#xff…...

Search with Orama

1.前言 在不久之前&#xff0c;我把 DevNow 的搜索组件通过 Lunr 进行了重构&#xff0c;从前端角度实现了对文章内容的搜索&#xff0c;但是在使用体验上&#xff0c;感觉不是特别好&#xff0c;大概有如下几个原因&#xff1a; 社区的文章数量比较少&#xff0c;项目的 Com…...

一万台服务器用saltstack还是ansible?

一万台服务器用saltstack还是ansible? 选择使用 SaltStack 还是 Ansible 来管理一万台服务器&#xff0c;取决于几个关键因素&#xff0c;如性能、扩展性、易用性、配置管理需求和团队的熟悉度。以下是两者的对比分析&#xff0c;帮助你做出决策&#xff1a; SaltStack&…...

计算机类大厂实习春招秋招开发算法面试问答练习题

计算机类大厂实习春招秋招开发算法面试问答练习题 下面有十个非常重要且常问,面试者却注意不到的问题,我们一个个来看,一个个来学。 线程创建到删除过程中,底层是怎么实现的 1.线程创建 线程创建是线程生命周期的起点。在操作系统中,线程可以通过多种方式创建,但无论哪…...

深圳网站建设行业新闻/福州百度开户多少钱

首先需要安装Vray渲染器 1.在场景中打一个自由摄像机 2.渲染设置尺寸设置&#xff0c;宽高比为2&#xff1a;1 3.在Vray设置页面&#xff0c;设置相机类型为球面&#xff0c;视角设置为360度 渲染结果...

日照网站建设全58长/seo的中文意思

牡丹灵通卡 &#xff08;中国工商银行&#xff09;异地ATM取款&#xff1a;异地本行ATM跨行取款每笔取款金额的1%&#xff0c;最低1元&#xff0c;最高50元&#xff1b;异地跨行ATM取款每笔手续费为2元取款金额的1%&#xff0c;1%部分最低1元&#xff0c;最高50元&#xff1b; …...

做方案收集图片的网站/创网站永久免费建站

使用 RDF 摘要图的基于关键字的语义搜索方法论文原文&#xff1a;Using RDF Summary Graph For Keyword-based Semantic Searches1 介绍该文提出一个基于关键字的语义搜索框架&#xff0c;使用摘要图用于探索 RDF 数据并提供相关结果。对于高效的图探索&#xff0c;一个摘要图结…...

陆丰网站建设/百度收录时间

查看当前在那哪个数据库中 select database()修改 Student 表 AGE属性为 INT类型 可以是NULL ALTER TABLE Student MODIFY COLUMN AGE INT NULL添加一个新列&#xff08;新字段&#xff09; ALTER TABLE Student ADD NEWCOLUMN CHAR(10) NULL删除一列 &#xff08;一个字段&…...

布吉附近公司做网站建设多少钱/百度指数电脑端查询

感谢“大神”的无私奉献&#xff1a;http://blog.csdn.net/leixiaohua1020/article/details/15811977 a) 通用选项-L license-h 帮助-fromats 显示可用的格式&#xff0c;编解码的&#xff0c;协议的...-f fmt 强迫采用格式fmt-I filename 输入文件-y 覆盖输出文件-t duration …...

做网站先做前台还是后台/百度指数是怎么计算的

前言 在使用 python 制作网页的过程中&#xff0c;我们往往需要先将站点的目录“虚拟化”。虚拟化其实就是将当前文件下程序的运行环境与整个系统的环境隔离。那么为什么我们要将一个项目虚拟化呢&#xff1f; 1.不进行虚拟化会产生的问题 在平时使用 python 时&#xff0c;有可…...