一、题目
设整数x1,x2,...xn已存放在数组A中,编写一递归过程,输出从这n个数中取出所有k个数的所有组合(k<=n)。例如,若A中存放的数是1,2,3,4,5,且k为3,则输出结果为:543,542,541,532,531,521,432,431,421,321。
二、问题分析
从数组中选择 k
个元素的所有组合,要求组合元素按原数组的逆序排列(即从后往前选元素,形成降序组合)。例如数组 [1,2,3,4,5]
,选3个元素时,第一个组合为 543
(选最后一个元素5,倒数第二个4,倒数第三个3)。
三、递归策略:
-
逆向选择:从数组末尾开始逐个选择元素,确保组合降序。
-
分步决策:
-
每一步选择一个元素加入临时组合。
-
递归选择剩余元素中的前部分(即更小的元素)。
-
-
终止条件:已选满
k
个元素时,输出当前组合。
四、时间复杂度:
组合数为 C(n, k)
,时间复杂度为 O(C(n, k) * k)
。
五、代码实现
#include <iostream>
using namespace std;
/**
* 递归生成所有k个元素的组合(按逆序选择)
* @param A 输入数组(必须升序排列)
* @param start 当前可选的起始索引(从右向左选)
* @param n 数组长度
* @param k 需要选择的元素个数
* @param currentCount 已选元素数量
* @param temp 临时存储当前组合的数组
*/
void combine(int A[], int start, int k, int currentCount, int temp[]) {
if (currentCount == k) {
// 输出当前组合
for (int i = 0; i < k; i++) {
cout << temp[i];
}
cout << endl;
return;
}
// 从start到0逆向选择元素
for (int i = start; i >= 0; i--) {
temp[currentCount] = A[i]; // 选择当前元素
combine(A, i - 1, k, currentCount + 1, temp); // 递归选剩余元素
}
}
int main() {
int n, k;
cout << "输入数组长度n: ";
cin >> n;
int A[n];
cout << "输入" << n << "个升序整数: ";
for (int i = 0; i < n; i++) {
cin >> A[i];
}
cout << "输入k值: ";
cin >> k;
int temp[k]; // 临时存储组合
combine(A, n - 1, k, 0, temp); // 从最后一个元素开始选
return 0;
}
测试用例
输入1:
输入数组长度n: 5
输入5个升序整数: 1 2 3 4 5
输入k值: 3
输出1:
输入2:
输入数组长度n: 4
输入4个升序整数: 2 5 7 9
输入k值: 2
输出2:
六、题目关键点
-
数组必须升序:
代码假设输入数组是升序的,这样从后往前选元素才能得到降序组合。若数组无序,需先排序。 -
递归终止条件:
当已选元素数量currentCount
等于k
时,输出临时数组temp
中的组合。 -
逆向遍历保证顺序:
通过for (int i = start; i >= 0; i--)
从右向左遍历,确保组合按逆序生成。