查找数组中的所有唯一子集

时间:2014-12-12 19:20:21

标签: c algorithm subset

我有一个包含n个整数的数组,我需要打印每个唯一的子集。 例如,如果我的数组{1,1,1,2},输出应为

1,  
1,1,  
1,1,1,  
2,  
1,2,  
1,1,2,  
1,1,1,2, 

我已经能够使用二进制移位打印所有可能的子集,但我仍然坚持删除重复项。我试图将打印的子集保存到另一个数组并进行比较,但这会浪费大量内存。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
int main ( int argc, char * argv [] ) {
int numbers[4] = {1,1,1,2};
int n = 4;
int np = 1<<n;
int i;
int bitv;
int pos;
for (i=1; i<np; i++){
bitv = i;
pos = 0;
while (bitv > 0){
    if ((bitv & 1) == 1) printf("%d,",numbers[pos]);
    bitv >>= 1;
    pos++;
   }
  printf ("\n");
 }
return 0;
}

和输出:

1,  
1,  
1,1,  
1,  
1,1,  
1,1,  
1,1,1,  
2,  
1,2,  
1,2,  
1,1,2,  
1,2,  
1,1,2,  
1,1,2,  
1,1,1,2,

3 个答案:

答案 0 :(得分:2)

您可以使用可能更容易解决的其他方式重新构建此问题。不要将其视为查找主集的子集,而是假设您具有每个元素出现次数的频率直方图。例如,集合{1,1,1,2}将表示为{1→3,2→1}。您可以通过列出对

列出所有子集
  • (0,0),意思是“零1和零2”
  • (1,0),意思是“一1和零2”
  • (2,0),意思是“两个1和零2”
  • (3,0),意思是“三个1和零2”
  • (0,1),表示“零1和1”
  • (1,1),意思是“一个1和一个2”
  • (2,1),意思是“两个1和一个2”
  • (3,1),意思是“三个1和一个2”

这提供了一种简单而优雅的方式来列出所有子集而不列出任何重复项。那么整个算法就是

  • 构建频率直方图,可能是通过对数组进行排序并获取数组中所有元素的总数。
  • 列出与原始数组中每个元素的副本数相对应的所有n元组。

希望这有帮助!

答案 1 :(得分:0)

计算每个数字的数量,即:&#34;直方图&#34;输入数组。 然后使用嵌套循环(或变量基数计数器)迭代选项。

如果您的输入不受约束,首先使用qsort对数组进行排序可能有所帮助。

答案 2 :(得分:0)

输出顺序是否重要?如果没有,我有一个dfs解决方案。

如果输入数组未排序,请先对其进行排序。在每一层中,处理一个元素(从0到n次,n是数组中该元素的出现次数)。

initial                    []
               /      /         \                 \
have 1?    []      [1]         [1 1]            [1 1 1]
          /  \     /  \         /  \            /     \
have 2?  []  [2] [1]  [1 2] [1 1] [1 1 2]  [1 1 1] [1 1 1 2] 


vector<vector<int> > subsetsWithDup(vector<int> &S) {
    vector<vector<int>> result;
    vector<int> path;
    sort(S.begin(),S.end());
    dfs(result,S,path,0);
    return result;
}

void dfs(vector<vector<int>> &result, const vector<int> &S, vector<int> &path, int idx) {
    if(idx == S.size()) {
        result.push_back(path);
        return;
    }
    int next = idx+1;
    while(next < S.size() && S[next] == S[next-1])
        next++;
    dfs(result,S,path,next);
    for(int i = 1; i <= next-idx; i++) {
        path.push_back(S[idx]);
        dfs(result,S,path,next);
    }
    path.erase(path.end()-(next-idx),path.end());
}