面试题精选(64):元素可重复组合算法
2009-05-23 15:01
489 查看
可重复组合问题是指,在计算(生成)组合时可以允许元素重复的一类组合问题。例如,对于有四个元素的集合{a, b, c, d},其可重复组合C(4, 3)有20个:aaa, aab, aac, aad, abb, abc, abd, acc, acd, add, bbb, bbc, bbd, bcc, bcd, bdd, ccc, ccd, cdd, ddd。
用P(n, k)表示从n个元素中选出k个元素(允许重复)的组合问题,那么此问题可以分解为两个子问题:P(n, k-1)和P(n-1, k),
解释如下:
P(n, k)中n个元素的所有k元素组合可以分成两部分。
第一部分的每个组合均以第一个元素开始,再连接上k-1个元素的组合,即再连接上P(n,k-1)的每一个组合;
第二部分的每个组合不含有第一个元素,即P(n-1, k)中的每一个组合(此时元素为后n-1个元素)。
因此,P(n, k)分解为P(n, k-1)和P(n-1, k)。
如果用f(n, k)表示P(n, k)中的组合数,那么有:
(1)当k = 1时,f(n, k) = n
(2)当n = 1时,f(n, k) = 1
(3)当k > 1且n > 1时,f(n, k) = f(n, k -1) + f(n-1, k)
此外,有公式f(n, k) = C(n + k -1, k)(表示n+k-1选k的组合数,没有重复元素),这可以用归纳法证明,这里就不啰嗦了。
C++实现如下:
F:/tmp>type ttt.cpp
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cassert>
using namespace std;
template <typename ElemType>
void CalcRepeatableCombination(const ElemType elements[], int num, int k,
vector<ElemType> &pre)
{
if (k == 1) {
for (int i = 0; i < num; ++i) {
copy(pre.begin(), pre.end(), ostream_iterator<ElemType>(cout));
cout << elements[i];
cout << endl;
}
return;
}
if (num == 1) {
ostream_iterator<ElemType> outIter(cout);
outIter = copy(pre.begin(), pre.end(), outIter);
fill_n(outIter, k, elements[0]);
cout << endl;
return;
}
pre.push_back(elements[0]);
CalcRepeatableCombination(elements, num, k - 1, pre);
pre.pop_back();
CalcRepeatableCombination(elements + 1, num - 1, k, pre);
}
template <typename ElemType>
void CalcRepeatableCombination(const ElemType elements[], int num, int k)
{
assert(num >= k && k >= 1);
vector<ElemType> one;
CalcRepeatableCombination(elements, num, k, one);
}
int main()
{
char elements[] = {'a', 'b', 'c', 'd'};
CalcRepeatableCombination(elements, 4, 3);
}
F:/tmp>g++ ttt.cpp
F:/tmp>a.exe
aaa
aab
aac
aad
abb
abc
abd
acc
acd
add
bbb
bbc
bbd
bcc
bcd
bdd
ccc
ccd
cdd
ddd
用P(n, k)表示从n个元素中选出k个元素(允许重复)的组合问题,那么此问题可以分解为两个子问题:P(n, k-1)和P(n-1, k),
解释如下:
P(n, k)中n个元素的所有k元素组合可以分成两部分。
第一部分的每个组合均以第一个元素开始,再连接上k-1个元素的组合,即再连接上P(n,k-1)的每一个组合;
第二部分的每个组合不含有第一个元素,即P(n-1, k)中的每一个组合(此时元素为后n-1个元素)。
因此,P(n, k)分解为P(n, k-1)和P(n-1, k)。
如果用f(n, k)表示P(n, k)中的组合数,那么有:
(1)当k = 1时,f(n, k) = n
(2)当n = 1时,f(n, k) = 1
(3)当k > 1且n > 1时,f(n, k) = f(n, k -1) + f(n-1, k)
此外,有公式f(n, k) = C(n + k -1, k)(表示n+k-1选k的组合数,没有重复元素),这可以用归纳法证明,这里就不啰嗦了。
C++实现如下:
F:/tmp>type ttt.cpp
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cassert>
using namespace std;
template <typename ElemType>
void CalcRepeatableCombination(const ElemType elements[], int num, int k,
vector<ElemType> &pre)
{
if (k == 1) {
for (int i = 0; i < num; ++i) {
copy(pre.begin(), pre.end(), ostream_iterator<ElemType>(cout));
cout << elements[i];
cout << endl;
}
return;
}
if (num == 1) {
ostream_iterator<ElemType> outIter(cout);
outIter = copy(pre.begin(), pre.end(), outIter);
fill_n(outIter, k, elements[0]);
cout << endl;
return;
}
pre.push_back(elements[0]);
CalcRepeatableCombination(elements, num, k - 1, pre);
pre.pop_back();
CalcRepeatableCombination(elements + 1, num - 1, k, pre);
}
template <typename ElemType>
void CalcRepeatableCombination(const ElemType elements[], int num, int k)
{
assert(num >= k && k >= 1);
vector<ElemType> one;
CalcRepeatableCombination(elements, num, k, one);
}
int main()
{
char elements[] = {'a', 'b', 'c', 'd'};
CalcRepeatableCombination(elements, 4, 3);
}
F:/tmp>g++ ttt.cpp
F:/tmp>a.exe
aaa
aab
aac
aad
abb
abc
abd
acc
acd
add
bbb
bbc
bbd
bcc
bcd
bdd
ccc
ccd
cdd
ddd
相关文章推荐
- 程序员面试题精选100题(05)-查找最小的k个元素[算法]
- [面试题]设计一个算法找到数组中两个元素相加等于指定数的所有组合
- 程序员面试题精选100题(05)-查找最小的k个元素[算法]
- 面试题精选(62):组合算法
- [面试题]设计一个算法找到数组中两个元素相加等于指定数的所有组合
- 面试题精选(79):取值为【1,n-1】含n个元素的整数数组至少存在一个重复数,O(n)时间内找出其中任意一个重复数
- 面试题精选(84):使序列有序的最少交换次数(minimum swaps) + 删除序列中所有重复的元素
- 九章算法面试题54 带重复元素的全排列
- 程序员面试题精选-翻转句子中单词的顺序[算法]
- 程序员面试题精选100题(25)-在从1到n的正数中1出现的次数[算法]
- 面试题:统计一个数组中不重复出现的元素个数
- 谷歌面试题--一个大小为n的数组,里面的数都属于范围[0, n-1],有不确定的重复元素,找到至少一个重复元素,要求O(1)空间和O(n)时间
- 程序员面试题精选100题(29)-调整数组顺序使奇数位于偶数前面[算法]
- 算法设计周记(十一)--寻找重复元素
- 算法12:删除数组中的重复元素
- 九章算法面试题64 找第k大的特殊数
- 一道有趣的GOOGLE面试题——找出至少一个重复元素
- 算法实现(2)有重复元素的排列问题
- JavaScript删除数组重复元素的5个高效算法
- 面试题: 已知一个含有n个不同元素的集合,要求打印其所有具有k个元素的子集(不允许有重复的)