1、问题
1.1 袋中取球
袋子里有4个球,分别编号为{1, 2, 3, 4},依次取出,按照取出的先后从左至右排列,会得到一个不同的数字(如 1 2 3 4,有点像双色球开奖),求输出所有的数字组合。
1.2 不重复的数
有4个数字{0, 1, 2, 3},问用这4个数字能组成多少种不能的4位数(0123也算,因为我们也可以用{1, 2, 3, 4})?
2、排列组合
上述2个问题实际都是一个排列组合的问题,首先我们来计算一共有多少种组合
取第1个球 |
取第2个球 |
取第3个球 |
取第4个球 |
|
能取球的次数 |
4 |
3 |
2 |
1 |
组合数 = 4 * 3 * 2 * 1 = 4!
即n个球的组合总数 = n!
我们可以验证下:
1个球的组合:{0} = 1
2个球的组合:{0, 1}, {1, 0} = 2
3个球的组合:{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0} = 6
3、如何输出线型排列组合
根据我们刚才验证组合的过程,我们发现我们在取第n个球时,我们总是从最小的数字0开始,如果该球已被取过了,则跳过继续遍历下一个数字,不管是取第0个球还是第n个,都是如此,因此我们只要知道第n个球的数字,那么下一个球
的数字都可以用相同的方法求出来,直到只剩一个球为止。
算法公式f(x):
1> 当取第x个球时,假设前x - 1个球已取{a, b, c, ...}个数字,放在容器S中(当然,开始时,容器S是空的)
2> 从{0, ..., n-1}循环
判断第i个数是否已被取过,即是否在S中
如果在,则跳过这个数
如果不在,则取出这个球,并添加到容器S中,表示该球已被占用
这时,该输出下一个球(x+1)个球了,我们用同样的算法f(x+1)
当x之后所有的球都被取出后,这时我们要继续循环下一个不在容器中的数字,但要注意,因为第x个球下次循环的数字将要改变了(i→i+1),球i将不再被占用,以供取后续的球之用,所以,我们要讲i这个球从占用容器S中取出
3> 很明显,这是一个递归过程,算法是有有限性的,那么什么时候这个递归停止呢
我们知道,当取出后一个球(n-1)时,袋子里就没有球了,再取下一个时,本次递归就可以结束了
4. 算法
注意:根据编程习惯,第一个球的编号和首次取球都是以0开始
//每个递归,都遍历一遍 vectorBall 中的空值,然后下次递归,递归完后,将原来设定的值设为0 //nIndex = 取第x个球 void CPermutation::SetBallNum(int nIndex, std::vector<int>& vectorBall, std::vector<int> vectorBallSet, std::vector<std::vector<int>>& vectorPermutation) { int nEmptyBallNum = 0; int nBallNum = vectorBall.size(); if (nBallNum == nIndex) { vectorPermutation.push_back(vectorBallSet); return; } for (int i = 0; i < nBallNum; i++) { //第x个球,最多有 nBallNum - x 个空位 if (nEmptyBallNum >= (nBallNum - nIndex)) { break; } //如果找到空值 if (0 == vectorBall[i]) { vectorBall[i] = 1; nEmptyBallNum++; vectorBallSet[nIndex] = i; SetBallNum(nIndex + 1, vectorBall, vectorBallSet, vectorPermutation); vectorBall[i] = 0; //将尝试完的值设为0,再尝试下一个 } } } //有n个编号为{0, n-1}的小球,依次取出,按照取出的先后从左至右排列,会得到一个不同的数字,打出所有的数字组合 //类似问题,用{0, n-1}个数,能组成多个数字不重复的n位数 bool CPermutation::PermutationBall(int nBallNum /* = 4 */) { printf("Ball num = %d\n", nBallNum); std::vector<int> vectorBallSet(nBallNum, 0); std::vector<int> vectorBall(nBallNum, 0); std::vector<std::vector<int>> vectorPermutation; SetBallNum(0, vectorBall, vectorBallSet, vectorPermutation); PrintPermutation(vectorPermutation); return true; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架