用于查找一组数组的最大子集(内核)的算法

时间:2013-11-06 14:24:03

标签: arrays algorithm data-structures

S成为一组数组,我们希望找到S中每个数组中出现的最大值子集。值可能会出现多次,如果某个值在每个数组中出现至少x次,则它应在输出集中出现x次。

这个问题可以看作是找到S的内核。

为了复杂性计算,假设S包含n个数组,所有数组的大小都为m

示例:

A = {4, 3, 8, 12, 5, 4, 4, 4}
B = {5, 4, 12, 1, 1, 4, 1, 1}
C = {2, 11, 4, 8, 4, 5, 2, 8}

Answer = {4, 4, 5} // order doesn't matter

几句话:

  • 如果值在每个数组中都是唯一的,我们可以使用哈希表来存储所有值,然后计算每个值的出现次数,如果它的出现次数等于数组的数量S,它会输入答案。
  • 如果我们想要设置唯一值(即在示例中答案可能是{4, 5}),我们可以使用每个数组的哈希表来检查是否已将值添加到&#34 ;大" hashtable(来自上一个项目符号),以防止在数组中出现多次的值的双重插入(或任何其他防止重复插入)。

有效(时间和内存)算法执行此任务的任何建议吗?

2 个答案:

答案 0 :(得分:3)

基于哈希的方法

为第一个数组的count创建一个值的哈希表。

对于哈希表中的每个条目,还要存储total,该值应设置为与计数相同。

对于每个下一个数组:

  • 重置哈希表中每个元素的计数。

  • 浏览数组,在哈希表中设置计数。

  • 对于哈希表中的每个条目,设置total = min(count, total)
    (删除total = 0

  • 的条目

<强>复杂度:

O(n)空格和(预期)时间复杂度n是元素总数。

基于排序的方法

将每个数组(到a min-heap)重新绑定(也可以使用排序,但这种解释有点令人困惑)。

  • max =每个堆的最小值,maxIndex =该堆的索引。
  • maxIndex + 1开始循环遍历堆栈,直到我们耗尽值。
    • 如果我们一直回到maxIndex,这意味着所有值都相同,因此输出最后一个弹出值。
    • 如果当前堆的最小值为> max,请正确设置maxmaxIndex (但不要删除最低限度)。
    • 否则从当前堆中删除最小值。

或(效率稍低):

对所有数组进行排序。

  • 保留所有当前元素的binary search tree(BST)(初始化为包含每个数组的第一个元素)。
  • 反复删除BST中的最小值,并从删除的元素来自的任何数组中添加下一个元素。
  • 每当BST的最小值和最大值相同时,所有节点都相等,因此我们输出该值。
  • 要处理重复项,我们需要记录自上次输出值以来添加了多少元素。仅当该计数大于或等于数组数时才输出值。

<强>复杂度:

O(m)空格和O(m n log n)时间复杂度,其中m是数组的数量,n是每个数组的平均元素数。

答案 1 :(得分:0)

  • 将这些集编码为素数产品
  • 将公共子集计算为结果数字的GCD
  • 将由此产生的GCD分解为揭示共同项目。
  • 这当然受限于物品的数量和集合的大小(否则素数的产品可能会溢出)

#include <stdio.h>
#include <string.h>

unsigned primes [] = { 2,3,5,7,11,13,17, 19, 23, 29,31,37,41,43,47};
unsigned value(unsigned array[], unsigned count);
unsigned gcd(unsigned a, unsigned b);
unsigned factorise(unsigned result[], unsigned val);


unsigned value(unsigned array[], unsigned count)
{
unsigned val, idx;

val = 1;
for (idx = 0; idx < count; idx++) {
        val *= primes [ array[idx]];
        }

return val;
}

unsigned gcd(unsigned a, unsigned b)
{
if (b > a) return gcd (b, a);
if (b <= 1) return a;
if (b == a) return a;
return gcd (b, a-b);
}

unsigned factorise(unsigned result[], unsigned val)
{
unsigned idx, count;

for (count=idx=0; val > 1; ) { 
        if ( val % primes[idx] ) idx++;
        else {
                result[count++] = idx;
                val /= primes[idx];
                }
        }
return count;
}

int main(void)
{
unsigned one[]  = {4, 3, 8, 12, 5, 4, 4, 4};
unsigned two[]  = {5, 4, 12, 1, 1, 4, 1, 1};
unsigned three[]  = {2, 11, 4, 8, 4, 5, 2, 8};
unsigned result[12]  , count, idx;;

unsigned val1, val2,val3
        , gcd12 , gcd23 , gcd13, gcd123;

val1 = value(one, 8);
val2 = value(two, 8);
val3 = value(three, 8);

gcd12 = gcd(val1,val2);
gcd23 = gcd(val2,val3);
gcd13 = gcd(val1,val3);
gcd123 = gcd(gcd12,gcd23);

fprintf(stdout, "Val1=%u, Val2=%u Val3=%u gcd= [%u %u %u]: %u\n"
        , val1, val2, val3
        , gcd12 , gcd23 , gcd13, gcd123);

count = factorise( result, gcd123);

for (idx=0; idx < count; idx++) {
        fprintf(stdout, "%c %u", idx? ',' : '{', result[idx] );
        }
fprintf(stdout, "}\n" );

return 0;
}

这是基于我的my answer here