Algorithm 查找一组值的所有唯一子集
我有一个算法问题。我试图从一组更大的值中找到所有唯一的值子集 例如,假设我有一个集合{1,3,7,9}。我可以使用什么算法来找到这些3的子集 {1,3,7} {1,3,9} {1,7,9} {3,7,9} 子集不应该重复,顺序也不重要,出于这些目的,集合{1,2,3}与集合{3,2,1}是相同的。鼓励使用Psudocode或常规类型 蛮力方法显然是可能的,但并不可取 例如,这种蛮力方法如下所示 for i = 0 to size for j = i + 1 to size for k = j + 1 to size subset[] = {set[i],set[j],set[k]}Algorithm 查找一组值的所有唯一子集,algorithm,set,unique,subset,Algorithm,Set,Unique,Subset,我有一个算法问题。我试图从一组更大的值中找到所有唯一的值子集 例如,假设我有一个集合{1,3,7,9}。我可以使用什么算法来找到这些3的子集 {1,3,7} {1,3,9} {1,7,9} {3,7,9} 子集不应该重复,顺序也不重要,出于这些目的,集合{1,2,3}与集合{3,2,1}是相同的。鼓励使用Psudocode或常规类型 蛮力方法显然是可能的,但并不可取 例如,这种蛮力方法如下所示 for i = 0 to size for j = i + 1 to size for k
不幸的是,对于子集中所需的每个元素,这需要一个额外的循环。例如,如果您想要8个元素的子集,这是不可取的。如果您只对大小为3的子集感兴趣,则可以使用三个简单的嵌套for循环来完成
for ( int i = 0; i < arr.size(); i++ )
for ( int j = i+1; j < arr.size(); j++ )
for ( int k = j+1; k < arr.size(); k++ )
std::cout << "{ " << arr[i] <<"," << arr[j] <<"," << arr[k] <<" }";
对于更一般的情况,必须使用递归
void recur( set<int> soFar, set<int> remaining, int subSetSize ) {
if (soFar.size() == subSetSize) {
print soFar;
return;
}
for ( int I = 0; I < remaining.size(); I++ ) {
//take out Ith element from remaining and push it in soFar.
// recur( newSofar, newRemaining, subSetSize);
}
}
如果您只对大小为3的子集感兴趣,那么可以使用三个简单的嵌套for循环来完成
for ( int i = 0; i < arr.size(); i++ )
for ( int j = i+1; j < arr.size(); j++ )
for ( int k = j+1; k < arr.size(); k++ )
std::cout << "{ " << arr[i] <<"," << arr[j] <<"," << arr[k] <<" }";
对于更一般的情况,必须使用递归
void recur( set<int> soFar, set<int> remaining, int subSetSize ) {
if (soFar.size() == subSetSize) {
print soFar;
return;
}
for ( int I = 0; I < remaining.size(); I++ ) {
//take out Ith element from remaining and push it in soFar.
// recur( newSofar, newRemaining, subSetSize);
}
}
一些使用递归的Java代码
void recur( set<int> soFar, set<int> remaining, int subSetSize ) {
if (soFar.size() == subSetSize) {
print soFar;
return;
}
for ( int I = 0; I < remaining.size(); I++ ) {
//take out Ith element from remaining and push it in soFar.
// recur( newSofar, newRemaining, subSetSize);
}
}
基本思想是尝试用当前位置交换每个元素,然后在下一个位置上递归,但我们也需要startPos在这里指示我们交换的最后一个位置是什么,否则我们将得到一个简单的置换生成器。一旦我们有足够的元素,我们打印所有这些元素并返回
静态无效子集[]arr、int pos、int深度、int startPos
{
如果pos==深度
{
对于int i=0;i1 3 7
1 3 9
1 7 9
3 7 9
通过示例进行更详细的解释:
首先,在上面的代码中,元素通过与自身进行交换而保持在相同的位置,它不做任何事情,只是使代码更简单
还要注意的是,在每一步中,我们都会恢复所做的所有掉期交易
假设我们有输入123445,我们想找到大小为3的子集
首先,我们只考虑前3个元素-1 2 3
然后我们分别用4和5交换3,
前3个元素给出了1 2 4和1 2 5
注意,我们刚刚完成了包含1和2的所有集合
现在我们需要的是13x形式的集合,所以我们交换2和3,得到12345。但是我们已经有了包含1和2的集合,所以这里我们想跳过2。所以我们分别用4和5交换2,前3个元素得到1 3 4和1 3 5
现在我们交换2和4得到1 4 3 2 5。但是我们想跳过3和2,所以我们从5开始。我们交换3和5,前3个元素得到1 4 5
等等
在这里跳过元素可能是最复杂的部分。请注意,每当我们跳过元素时,它只涉及从我们交换2和4时所用的位置之后继续,我们从交换4后继续。这是正确的,因为在没有经过处理的情况下,元素不可能到达我们正在交换的位置的左侧,也不可能到达该位置的右侧,因为我们从左到右处理所有元素
从for循环的角度考虑
从for循环的角度来考虑这个算法也许是最简单的
for i = 0 to size
for j = i + 1 to size
for k = j + 1 to size
subset[] = {set[i],set[j],set[k]}
每个递归步骤都代表一个for循环
startPos分别为0、i+1和j+1
深度是有多少个for循环
pos是我们目前使用的for循环
因为我们从不在更深的循环中倒退,所以使用数组的开头作为元素的存储是安全的,只要我们在完成迭代时还原更改。一些使用递归的Java代码
void recur( set<int> soFar, set<int> remaining, int subSetSize ) {
if (soFar.size() == subSetSize) {
print soFar;
return;
}
for ( int I = 0; I < remaining.size(); I++ ) {
//take out Ith element from remaining and push it in soFar.
// recur( newSofar, newRemaining, subSetSize);
}
}
基本思想是尝试用当前位置交换每个元素,然后在下一个位置上递归,但我们也需要startPos在这里指示我们交换的最后一个位置是什么,否则我们将得到一个简单的置换生成器。一旦我们有足够的元素,我们打印所有这些元素并返回
静态无效子集[]arr、int pos、int深度、int startPos
{
如果pos==深度
{
对于int i=0;i1 3 7
1 3 9
1 7 9
3 7 9
通过示例进行更详细的解释:
首先,在上面的代码中,元素通过与自身进行交换而保持在相同的位置,它不做任何事情,只是使代码更简单
还要注意的是,在每一步中,我们都会恢复所做的所有掉期交易
假设我们有输入123445,我们想找到大小为3的子集
首先,我们只考虑前3个元素-1 2 3
然后我们分别用4和5交换3,
前3个元素给出了1 2 4和1 2 5
注意,我们刚刚完成了包含1和2的所有集合
现在我们需要的是13x形式的集合,所以我们交换2和3,得到12345。但是我们已经有了包含1和2的集合,所以这里我们想跳过2。所以我们分别用4和5交换2,前3个元素得到1 3 4和1 3 5
现在我们交换2和4得到1 4 3 2 5。但是我们想跳过3和2,所以我们从5开始。我们交换3和5,前3个元素得到1 4 5
等等
在这里跳过元素可能是最复杂的部分。请注意,每当我们跳过元素时,它只涉及从我们交换2和4时所用的位置之后继续,我们从交换4后继续。这是正确的,因为在没有经过处理的情况下,元素不可能到达我们正在交换的位置的左侧,也不可能到达该位置的右侧,因为我们从左到右处理所有元素
从for循环的角度考虑
从for循环的角度来考虑这个算法也许是最简单的
for i = 0 to size
for j = i + 1 to size
for k = j + 1 to size
subset[] = {set[i],set[j],set[k]}
每个递归步骤都代表一个for循环
startPos分别为0、i+1和j+1
深度是有多少个for循环
pos是我们目前使用的for循环
由于我们从不在更深的循环中倒退,因此使用数组的开头作为元素的存储是安全的,只要我们在完成迭代时还原更改即可。很抱歉,我同时使用了这两个标记,我的错。可以从数学上证明唯一子集的数量等于父集合中给定的元素数量吗?我觉得这是真的,但我没有测试它。对于3的子集,它似乎遵循这个方程,唯一子集=1/6*x^3+x^2+11/6^x+1。其中x是集合大小与子集大小的差异。暴力到底是什么?我可能会调用任何方法来生成这些集合,而不是简单地计算它们。本质上,这是一个有大量答案的问题。很抱歉,我遵循了这两个标记,我的错误。可以从数学上证明唯一子集的数量等于父集合中给定的元素数量吗?我觉得这是真的,但我没有测试它。对于3的子集,它似乎遵循这个方程,唯一子集=1/6*x^3+x^2+11/6^x+1。其中x是集合大小与子集大小的差异。暴力到底是什么?我可能会调用任何方法来生成这些集合,而不是简单地用蛮力来计算它们。本质上,与有大量答案的问题相同,我只是发布嵌套循环是不可取的。在Dukeling在评论中询问了蛮力方法之后。哈哈,我只是发布了嵌套循环是不受欢迎的。在Dukeling在评论中询问了蛮力方法之后。在数组中交换数字是聪明的。你能更详细地解释一下这是如何工作的吗?@Chase试图解释得更详细一点-希望能有所帮助。哦,基本上是我做的,但递归地做得很好。递归有时还是会把我搞糊涂。在数组中交换数字是聪明的。你能更详细地解释一下这是如何工作的吗?@Chase试图解释得更详细一点-希望能有所帮助。哦,基本上是我做的,但递归地做得很好。递归有时还是会把我搞得一团糟。