我需要生成所有组合而不重复数组,我读了一些关于它的建议使用递归
我有一个数组
arr = [["A"], ["B"], ["C"], ["D"], ["E"], ["F"]]
我读到我可以使用像
这样的递归来解决这个问题function combinations(arr, n, k)
//do something
//then
return combinations(arr, n, k)
在我的情况下[A,B,C,D]相当于[A,B,D,C]。
我在C ++中找到了这个例子
http://www.martinbroadhurst.com/combinations.html
但我无法复制它。
有任何建议我该如何解决?
PD:我使用的是Python,但我对算法比对语言更感兴趣。答案 0 :(得分:1)
[哎呀...当我发布答案时,C++
标签消失了]
[编辑更多示例,包括使用char]
代码中的评论:
#include <vector>
// Function that recursively does the actual job
template <typename T, typename Function> void doCombinations(
size_t num, const std::vector<T>& values,
size_t start, std::vector<T>& combinationSoFar,
Function action
) {
if(0==num) { // the entire combination is complete
action(combinationSoFar);
}
else {
// walk through with the current position to the right,
// taking care to let enough walking room for the rest of the elements
for(size_t i=start; i<values.size()+1-num; i++) {
// push the current value there
combinationSoFar.push_back(values[i]);
// recursive call with one less element to enter combination
// and one position to the right for the next element to consider
doCombinations(num-1, values, i+1, combinationSoFar, action);
// pop the current value, we are going to move it to the right anyway
combinationSoFar.pop_back();
}
}
}
// function for the user to call. Prepares everything needed for the
// doCombinations
template <typename T, typename Function>
void for_each_combination(
size_t numInCombination,
const std::vector<T>& values,
Function action
) {
std::vector<T> combination;
doCombinations(numInCombination, values, 0, combination, action);
}
// dummy do-something with the vector
template <typename T> void cout_vector(const std::vector<T>& v) {
std::cout << '[';
for(size_t i=0; i<v.size(); i++) {
if(i) {
std::cout << ",";
}
std::cout << v[i];
}
std::cout << ']' << std::endl;
}
// Assumes the T type supports both addition and ostream <<
template <typename T> void adder(const std::vector<T>& vals) {
T sum=static_cast<T>(0);
for(T v : vals) {
sum+=v;
}
std::cout << "Sum: " << sum << " for ";
cout_vector(vals);
}
int main() {
std::cout << "Char combinations" << std::endl;
std::vector<char> char_vals{'A', 'B', 'C', 'D', 'E'};
for_each_combination(3, char_vals, cout_vector<char>);
std::cout << "\nInt combinations" << std::endl;
std::vector<int> int_vals{0, 1, 2, 3, 4};
for_each_combination(3, int_vals, cout_vector<int>);
std::cout <<"\nFloat combination adder" << std::endl;
std::vector<float> float_vals{0.0, 1.1, 2.2, 3.3, 4.4};
for_each_combination(3, float_vals, adder<float>);
return 0;
}
输出:
Char combinations
[A,B,C]
[A,B,D]
[A,B,E]
[A,C,D]
[A,C,E]
[A,D,E]
[B,C,D]
[B,C,E]
[B,D,E]
[C,D,E]
Int combinations
[0,1,2]
[0,1,3]
[0,1,4]
[0,2,3]
[0,2,4]
[0,3,4]
[1,2,3]
[1,2,4]
[1,3,4]
[2,3,4]
Float combination adder
Sum: 3.3 for [0,1.1,2.2]
Sum: 4.4 for [0,1.1,3.3]
Sum: 5.5 for [0,1.1,4.4]
Sum: 5.5 for [0,2.2,3.3]
Sum: 6.6 for [0,2.2,4.4]
Sum: 7.7 for [0,3.3,4.4]
Sum: 6.6 for [1.1,2.2,3.3]
Sum: 7.7 for [1.1,2.2,4.4]
Sum: 8.8 for [1.1,3.3,4.4]
Sum: 9.9 for [2.2,3.3,4.4]
答案 1 :(得分:1)
对于任何组合学问题,编程它的最佳方法是计算计数参数的递归关系。在组合的情况下,递归关系简单地是C(n,k)= C(n-1,k-1)+ C(n-1,k)。 但这究竟意味着什么呢?注意,C(n - 1,k - 1)意味着我们已经取得了数组的第一个元素,并且需要k - 1个来自其他n - 1个元素的元素。类似地,C(n - 1,k)意味着我们不会选择数组的第一个元素作为k个元素之一。但请记住,如果k为0,则C(n,k)= 1,否则如果n为0则C(n,k)= 0.在我们的问题中,k == 0将返回一个包含的 / em>空集,否则如果n == 0,我们将返回空集。考虑到这一点,代码结构如下所示:
>>> a
'wswwswwwswwwws'
>>> b
['ws', 'wws']
现在,可以通过执行记忆来优化此功能(但这可以作为练习留给您,读者)。作为一个额外的练习,你能否勾勒出排列函数从计数关系开始的样子?
提示: P(n,k)= C(n,k)k! = [C(n - 1,k - 1)+ C(n - 1,k)] k! = P(n-1,k-1)k + P(n-1,k)