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

[递归] 子集 全排列和组合问题

1.1 子集I

思路可以简单概括为 二叉树,每一次分叉要么选择一个元素,要么选择空,总共有n次,因此到n+1进行保存结果,返回。像这样:

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
int n;
vector<int >temp;
vector<vector<int> > result;
void DFS(int m){if (m == n+1){result.push_back(temp);return ;}//选择元素mtemp.push_back(m);DFS(m+1);//继续递归temp.pop_back();//返回//选择空DFS(m+1);
}bool cmp(vector<int > &a,vector<int > &b){if (a.size()!=b.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d",&n);DFS(1);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;
}

最后自己编写比较函数,简单来说,vector大小相同时,可以直接按照< >这些比较符号进行比较。大小不同时,则按照vector大小进行排序,这里按照题目要求均是小于。

1.2 子集II

区别在于,自己给定一些元素,进行排序。

那么只需要用一个数组存储这些元素,在压栈/出栈时,换成对应的数组元素即可,思路一致。

代码几乎没有变化。

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> temp;
vector<vector<int> > result;
const int N =15;
int q[N];
int n;
void DFS(int m){if (m==n+1){result.push_back(temp);return ;}temp.push_back(q[m]);DFS(m+1);temp.pop_back();DFS(m+1);
}
bool cmp(vector<int> &a ,vector<int> &b){if (a.size()!= b.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d",&n);for (int i=1;i<=n;i++)scanf("%d",&q[i]);DFS(1);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;}

1.3 子集III

思路还是二叉树深搜递归,但是由于会出现重复的数,按照之前的输出会重复输出一些值,例如样例里的1的子集都会输出两边,因为代码并没有认为第一个1与第二个1是不同的。

首先输入的序列是升序的,因此我们可以连续地处理这些重复的元素。

例如 2 3 3 3 5 

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> temp;
vector<vector<int> > result;
const int N =15;
int q[N];
int n;
void DFS(int idx){if (idx==n+1){result.push_back(temp);return ;}int cnt=1;while (idx<n && q[idx]==q[idx+1]){cnt++;idx++;}//经过该循环,idx = 最后一个重复元素的序号,cnt为重复元素的个数// 选择空 DFS(idx+1);//选择重复元素for (int i=1;i<=cnt;i++){temp.push_back(q[idx]);DFS(idx+1);// 选择重复的元素为 1 2 3 ....cnt个}//在这个循环中,我们将之前添加到 temp 中的元素逐个移除,//以回溯到不添加这些重复元素的情况for (int i=1;i<=cnt;i++){temp.pop_back();}
}
bool cmp(vector<int> &a ,vector<int> &b){if (a.size()!= b.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d",&n);for (int i=1;i<=n;i++)scanf("%d",&q[i]);DFS(1);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;}

2.1 全排列I

思路很简单,给个图:

 

设置个q[]表示其是否被使用过,依次递归,返回时再赋值0;

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> temp;
vector<vector<int> > result;
int n;
const int N = 10;
int q[N]={0};
void DFS(int m){if (m == n+1){result.push_back(temp);}for (int i=1;i<=n;i++){if (!q[i]){temp.push_back(i);q[i]=1;DFS(m+1);q[i]=0;temp.pop_back();}}}
bool cmp(vector<int> &a ,vector<int> &b){if (a.size()!=a.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d",&n);DFS(1);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;}

2.2 全排列II

思路依旧简单,全排列I是用i作为正整数,这次是给定正整数压栈和出栈,q[]来储存输入的数,flag[]来表示其是否被使用过,代码相同

#include <cstdio>
#include <algorithm>
#include <vector>using namespace std;
int n;
const int N=10;
int q[N];
int flag[N] = {0};
vector<int> temp;
vector<vector<int> > result;
void DFS(int m){if (m==n+1){result.push_back(temp);}for (int i=1;i<=n;i++){if (!flag[i]){temp.push_back(q[i]);flag[i]=1;DFS(m+1);flag[i]=0;temp.pop_back();}}}
bool cmp(vector<int> &a,vector<int> &b){if (a.size()!=b.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d",&n);for (int i=1;i<=n;i++)scanf("%d",&q[i]);DFS(1);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;}

2.3 全排列III

如果按照之前的思路,那么样例1会出现大量重复,与子集的解决方法类似,不过是这里是记录每个数的个数,使用cnt[]进行计算,并且每个数只记录一次;

1 1 3 : 只取最后一个重复的id进行记录次数,像这样:cnt[1] = 0 cnt[2]=2 cnt[3] =1

那么全排列就很简单,每次的全排列对于q[i]的数只能用cnt[i]次数。

那么每次for循环

    for (int i=1;i<=n;i++){if (cnt[i]){temp.push_back(q[i]);cnt[i]--;DFS(m+1);cnt[i]++;temp.pop_back();}}

只能用一次重复的值 

#include <cstdio>
#include <algorithm>
#include <vector>using namespace std;
int n;
const int N = 10;
int q[N];
int cnt[N]={0};
vector<int> temp;
vector<vector<int> >result;
void DFS(int m){if (m==n+1){result.push_back(temp);return ;}for (int i=1;i<=n;i++){if (cnt[i]){temp.push_back(q[i]);cnt[i]--;DFS(m+1);cnt[i]++;temp.pop_back();}}
}
bool cmp(vector<int> &a,vector<int> &b){if (a.size()!=b.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d",&n);for (int i=1;i<=n;i++)scanf("%d",&q[i]);for (int i=1;i<=n;i++){int j=i;cnt[i]=1;while (j<=n && q[j]==q[j+1]){cnt[i]++;j++;}i = j;}DFS(1);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;}

3.1 组合I

 

和全排列很像,不过全排列是有顺序的(样例中3 4 和4 3在全排列均是有效的),而组合是无序的,因此我们在挑选的时候可以人为地进行有序限制,从而不会重复。

思路与这道递归题类似

[递归] 自然数分解之方案数_慕梅^的博客-CSDN博客

我们保证后一个数要大于前一个这样的要求,那么就可实现组合题。

样例2中 两个数x y 满足(x<y)

那我们的DFS(int m),m则是后面的数需要大于的序号

DFS(0)可以作为入口

#include <cstdio>
#include <algorithm>
#include <vector>using namespace std;
int n,k;
const int N = 15;vector<int> temp;
vector<vector<int> > result;void DFS(int m){if (temp.size()==k){//递归的出口则改为vector <int> temp的大小==kresult.push_back(temp);return ;}for (int i=m+1;i<=n;i++){//循环从 序号m+1开始temp.push_back(i);DFS(i);//将i作为参数进行下一次的递归temp.pop_back();}return ;}
bool cmp(vector<int> &a,vector<int> &b){if (a.size()!=b.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d%d",&n,&k);DFS(0);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;}

 3.2 组合II 

需要自己输入序列,思路不变

#include <cstdio>
#include <algorithm>
#include <vector>using namespace std;
int n,k;
const int N = 15;
int q[N];
vector<int> temp;
vector<vector<int> > result;void DFS(int m){if (temp.size()==k){result.push_back(temp);return ;}for (int i=m+1;i<=n;i++){temp.push_back(q[i]);DFS(i);temp.pop_back();}
}
bool cmp(vector<int> &a,vector<int> &b){if (a.size()!=b.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d%d",&n,&k);for (int i=1;i<=n;i++)scanf("%d",&q[i]);DFS(0);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;}

3.3 组合III

 可以借鉴全排列的思想,使用cnt来进行计数

#include <cstdio>
#include <algorithm>
#include <vector>using namespace std;
int n,k;
const int N = 15;
int q[N];
int cnt[N]={0};
vector<int> temp;
vector<vector<int> > result;void DFS(int m){if (temp.size()==k){result.push_back(temp);return ;}for (int i=m;i<=n;i++){//i从m开始,因为有重复的元素。if (cnt[i]){cnt[i]--;temp.push_back(q[i]);DFS(i);cnt[i]++;temp.pop_back();}}
}
bool cmp(vector<int> &a,vector<int> &b){if (a.size()!=b.size())return a.size()<b.size();return a<b;
}
int main(){scanf("%d%d",&n,&k);for (int i=1;i<=n;i++)scanf("%d",&q[i]);for (int i=1;i<=n;i++){int j = i;cnt[i] = 1;while ((j+1)<=n&&q[j]==q[j+1]){cnt[i]++;j++;}i = j;}DFS(0);sort(result.begin(),result.end(),cmp);for (int i=0;i<result.size();i++){for (int j=0;j<result[i].size();j++){if (j==result[i].size()-1)printf("%d",result[i][j]);else printf("%d ",result[i][j]);}printf("\n");}return 0;}

不过与前两个组合不同的是

for (int i=m+1;i<=n;i++){

条件因改为

for (int i=m;i<=n;i++){

 如果不该与,之前的序列都是没有重复的元素,因此可以下一次的序号需要+1以保证大于前面的数,然而这里有重复的元素,因此从m开始。

相关文章:

[递归] 子集 全排列和组合问题

1.1 子集I 思路可以简单概括为 二叉树&#xff0c;每一次分叉要么选择一个元素&#xff0c;要么选择空&#xff0c;总共有n次&#xff0c;因此到n1进行保存结果&#xff0c;返回。像这样&#xff1a; #include <cstdio> #include <vector> #include <algorithm&…...

ELK安装、部署、调试(四)KAFKA消息队列的安装和部署

1.简介 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。 这种动作&#xff08;网页浏览&#xff0c;搜索和其他用户的行动&#xff09;是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通…...

半导体晶片机器视觉测量及MARK点视觉定位

半导体晶片机器视觉测量及MARK点视觉定位 客户的需求: 检测内容&#xff1a; SMT行业晶片位置角度与PCB板Mark点位置的测试测量 检测要求&#xff1a; 精度0.04mm&#xff0c;移动速度100mm/s 视觉可行性分析: 对样品进行了光学实验&#xff0c;并进行图像处理&#xff0c…...

ranger无法同步用户问题解决

1.首先就是定位日志,日志目录 cd /var/log/ranger/usersync 定位到问题报错如下: LdapDeltaUserGroupBuilder.getUsers() failed with exception:java.naming.AuthticationExceptiom :[LDAP:error code 49 - Invalid Credentials]:remaing name ‘ouPeople,dc*.dccom’ 解决办法…...

使用通信顺序进程(CSP)模型的 Go 语言通道

在并发编程中&#xff0c;许多编程语言采用共享内存/状态模型。然而&#xff0c;Go 通过实现 通信顺序进程&#xff08;CSP&#xff09;模型来区别于众多。在CSP中&#xff0c;程序由不共享状态的并行进程组成&#xff1b;相反&#xff0c;它们通过通道进行通信和同步操作。因此…...

VPN网关

阿里云VPN网关(VPN Gateway&#xff0c;简称VPN)是一款基于Internet&#xff0c;通过加密通道将企业数据中心、办公网或终端与专有网络(VPC) 安全可靠连接起来的服务。 VPN网关提供IPsec-VPN和SSL-VPN两种。 网络连接方式应用场景IPsec-VPN支持在企业本地数据中心、企业办公网…...

产品展示视频制作的要点

制作产品展示视频时通过精心策划的视频剧本和拍摄手法&#xff0c;可以准确地呈现活动的目的、主题和特点&#xff0c;让观众更好地理解和认同活动的意义。深圳产品活动视频制作公司老友记小编还为您整理了以下一些重要的制作要点&#xff1a; 1.明确目标受众&#xff1a;了解你…...

appium+python自动化测试

获取APP的包名 1、aapt即Android Asset Packaging Tool&#xff0c;在SDK的build-tools目录下。该工具可以查看apk包名和launcherActivity 2、在android-sdk里面双击SDK-manager,下载buidl-tools 3、勾选build-tools&#xff0c;随便选一个版本&#xff0c;我这里选的是24的版…...

【AI辅助办公】PDF转PPT,移除水印

PDF转PPT 将PDF上传链接即可转换成PPT。​​​​​​ ​​​​​​​ https://www.camscanner.com/pdftoppthttps://www.camscanner.com/pdftoppt​​​​​​​​​​​​​​移除水印 第一步&#xff1a;打开视图-宏 第二步&#xff1a;输入宏名&#xff08;可以是人以文字…...

ssm农业视频实时发布管理系统源码

ssm农业视频实时发布管理系统源码108 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm package com.controller;import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; impo…...

【100天精通python】Day48:python Web开发_WSGI接口与使用

目录 1 WSGI接口 1.1 CGI 简介 1.2 WSGI 简介 1.3 定义 WSGI 接口 1.3.1 应用程序&#xff08;Application&#xff09; 1.3.2 服务器&#xff08;Server&#xff09; 1.4 WSGI 接口的使用示例 1.5 WSGI接口的优势 1 WSGI接口 上一节实现了静态服务器&#xff0c;但是当…...

Understanding Lockup Cells

工具会分析扫描链和EDT逻辑之间的控制时序元素的时钟的时序关系,当必须要同步时钟并保持数据完整性时插入边沿触发寄存器(lockup cells)。 可以使用report_edt_lockup_cells命令来展示工具已经插入的lockup cells的详细报告。 Lockup Cell Insertion 工具会分析控制时序元…...

javaCV实现java图片ocr提取文字效果

引入依赖&#xff1a; <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.5</version></dependency> 引入中文语言训练数据集&#xff1a;chi_sim GitHub - tesseract-ocr…...

七牛云OSS存储

前言: 七牛云的存储项目的附件,需要开发一套七牛云的工具类,可以使用该工具类进行七牛云服务器进行文件的上传与下载操作; 七牛云的文档学习: 相关的依赖项的配置: <dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3…...

11.物联网lwip,网卡原理

一。LWIP协议栈内存管理 1.LWIP内存管理方案 &#xff08;1&#xff09;堆heap 1.灰色为已使用内存 2.黑色为未使用内存 3.紫色为使用后内存 按照某种算法&#xff0c;把数据放在内存块中 &#xff08;2&#xff09;池pool 设置内存池&#xff0c;设置成大小相同的内存块。 2…...

视频监控/视频汇聚/视频云存储EasyCVR平台接入华为ivs3800平台提示400报错,该如何解决?

开源EasyDarwin视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频云存储/安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频…...

WordPress主题Zing V2.2.1/模块化WordPress响应式通用企业商城主题

WordPress主题Zing V2.2.1&#xff0c;模块化WordPress响应式通用企业商城主题。 功能介绍 百度熊掌号文章实时推送、原创保护 多设备支持自适应布局&#xff0c;支持电脑、Pad、手机以及各种浏览器 SEO优化首页、文章、页面、分类均支持自定义标题、关键字和描述 速度优化…...

【无需公网IP】在树莓派上搭建Web站点

目录 1.概述 2.使用 Raspberry Pi Imager 安装 Raspberry Pi OS 3.设置 Apache Web 服务器 3.1测试 web 站点 3.2安装静态样例站点 3.3将web站点发布到公网 3.4安装 Cpolar 3.5cpolar进行token认证 3.6生成cpolar随机域名网址 3.7生成cpolar二级子域名 3.8将参数保存…...

出差在外,远程访问企业局域网象过河ERP系统「内网穿透」

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…...

Vue2-replace属性、编程式路由导航、缓存路由组件、两个新的生命周期钩子、路由守卫、路由器工作模式

&#x1f954;&#xff1a;如果事与愿违&#xff0c;那一定是上天另有安排 更多Vue知识请点击——Vue.js VUE2-Day13 router-link的replace属性编程式路由导航1、什么是编程式路由导航2、如何编码3、使用案例示例说明 缓存路由组件两个新的生命周期钩子路由守卫1、路由元信息2、…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...