一个算法的问题,请教

sxxiaozi 2008-11-13 05:31:46
例如,有一组数据,每个数据都是集合的形式如何以最小的时间复杂度找出这些数据里面的极大元(极大元也就是说没有其他数据包含它),比较绕口,举个例子
假设有A={1,2,3,4,5};
B={1,2,3,4,6};
C={2,3,4,7};
D={1,2,3,4};
E={2,3,4,5};
F={3,4,6};
最后结果就是要得到A,B,C.
几个假设:1、每个集合都有序
2、不会有重复的情况,即一个集合只会出现一次
3、这一批数据的数据量比较大,在几十万个以上,每个集合的元素最大为1万个,所以要求时间复杂度要低

请教各位
...全文
139 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
sxxiaozi 2008-11-14
  • 打赏
  • 举报
回复
而且每次与操作都是10W与10W的与操作


这句话写错了,应该是1W与1W的与操作,我先试一试,再次感谢
  • 打赏
  • 举报
回复
10W个集合,还是10W个数据?
因为前面你说过有几十万的数据,如果光集合数量就有十万,那么平均下来每个集合里只有几个元素而已。

前面所说的方法对于集合数目相对较少、同时集合中元素数量比较多的时候处理起来很有优势。
如果是十万个小集合,那么方法要改一下了:
flag[min:max]中的元素不是0-1序列,而是用“集合”(可以简单用链表来实现),记录的是包含这个值的集合有哪些;
同样,后面的“按位与”运算,就编程求“集合”的交集,也就是链表的公告节点。
这样节省了大量的空间,也去掉了很多不必要的运算。

上面说的办法还可以进一步优化,比方说:flag[]中可以只记录“极大元”,对于哪些已经判断出来不是极大元的集合,不需要在这个数组元素的链表中出现。
绿色夹克衫 2008-11-14
  • 打赏
  • 举报
回复
有另外一个思路,大家可以讨论一下,每个集合有10000个元素,共10万个集合,按照现在的方法,计算量还是太大了

其实大王所说的类似hash的方法已经很高效了。但这是基于精密比对的,我觉得应该先用一种模糊的方式处理筛选一下,

然后再进行精密比对,就好像元素个数最多的集合一定是极大元一样,有很多不同的统计方法,可以记录一个集合的特性,

这样就可以将特性类似的集合分组,只在组间进行比对,这样要处理的数据量就可以下降很多了。

具体分组方法我也没想好,但应当确保不同分组之间的集合,不存在子集。

除了分组之外,也可以用一些统计的方法,很快的筛选出一部分极大元。
sxxiaozi 2008-11-13
  • 打赏
  • 举报
回复
谢谢dlyme,您的意思就是用flag来表示当前元素所在的集合,如果第i个集合包含第j个集合,那么r值的第i列和第j列必然都为1,可以判断出包含关系,这样做的确非常巧妙,但是也是您提到的问题,这个空间有点夸张,有10W个集合,每个集合的最小值为1,最大值为1W,这样就flag就需要10w*1w的大小,而且每次与操作都是10W与10W的与操作,这个有点恐怖,不知道有没有其他的办法啊?
  • 打赏
  • 举报
回复
还没写对,应该这样:
for(t=1; t<=m; t++)
{
r="1111...111"; //所有位置上全为1
for(j=1; j<=S(t).size; j++)
{
flag[S(t)的第j个元素]=flag[S(t)的第j个元素]的第t位置为1、其它位不变;
r = r ^ flag[S(t)的第j个元素]; //按位“与”运算
}
if(r只有第t位上有1)
集合S(t)为极大元;
else
集合S(t)不是极大元;
}
  • 打赏
  • 举报
回复
更正一下:
for(t=1; t <=m; t++)
{
r="1111...111"; //所有位置上全为1
for(j=1; t<=S(t).size; t++)
{
flag[S(t)的第j个元素]=flag[S(t)的第j个元素]的第t位置为1、其它位不变;
r = r ^ flag[S(t)的第j个元素]; //按位“与”运算
}
if(r只有第t位上有1)
集合S(t)为极大元;
else
集合S(t)不是极大元;
}

对于任一集合S,能包含它的集合元素个数肯定要比它多,所以一定在S之前就遍历过。这就保证了这样字能过滤出所有“被包含”的集合。
  • 打赏
  • 举报
回复
首先,由于集合不重复,所以元素个数最多的那(几)个集合一定是极大元。

假设集合个数为m,所有集合中最小元素为min、最大元素max,
开一个flag[min~max]大小的数组,里面的元素全是长度为 m 的0-1序列。
比方说falg[i]=“1000...000”,它的意思就是说只有第一个集合中含有i这个值,其它集合中都不包含i
初始化的时候每个序列全都是0

接下来就按照元素个数由多到少的顺序来处理各个集合。对于每个集合S(t),遍历其中的元素。
具体过程:
for(t=1; t<=m; t++)
{
r="1111...111"; //所有位置上全为1
for(j=0; t<=S(t).size; t++)
{
flag[S(t)的第j个元素]=flag[S(t)的第j个元素]的第j位置为1、其它位不变;
r = r ^ flag[S(t)的第j个元素]; //按位“与”运算
}
if(r只有第j位上有1)
集合S(t)为极大元;
else
集合S(t)不是极大元;
}

这样处理完之后,所有集合的每个元素都只读过一遍,时间上来说应该是比较省的了。
缺点是空间耗费可能很大。

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧