一个很简单的问题,却没有想出一个好的解法

绿色夹克衫 2010-08-07 04:32:59
集合A包含n个正整数,其中最大的数为m。集合B是从A中任选2个元素相加去掉重复后所组成的集合。
有没有什么快速的方法求集合B?难道只能是n^2?有没有复杂度是关于m的方法?

用线段树也许可以好一点,不过只是我想的土方法,听听大家说的吧!
...全文
1389 点赞 收藏 41
写回复
41 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
菠萝先生 2010-09-10
你们这些疯子!!!!!!!!强烈鄙视!
回复
chenchangxiong 2010-09-08
汗 发错了
回复
chenchangxiong 2010-09-08
咋可能是klogk
光为了找到这个数,在最糟情况下要计算的加法就要k(k+1)/2次
这是因为
a[x] + b[y] 并不一定比 a[x-i] + b[y+j]要来的大,反之亦然

个人认为复杂度应当为k2logk

因为对斜上矩阵,从左到右推,每列据对角线为i的数的最大比较为log(i+1)
每列复杂度为ilogi
最后复杂度为k2logk
回复
huangying1201 2010-09-08
提供一个算法,大家看看可不可行:
举例a ={8 ,6, 1 }
b= {7,4,3,2}
可以构成求和距阵(这里只是便于表示,并不需要在内存中建立该距阵方正大小为max{m,n},行或列不够的在末尾补充0或最小值)
8 6 1 0
7 15 13 8 0
4 12 10 5 0
3 11 9 4 0
2 10 8 3 0
由这个方阵规律可以观察到(i为行标,j为列标):
1. 最大的1个:15((i=1&&j<=1)||(j=1&&i<=1))
2. 最大的[2,4]个:13, 12 10((i=2&&j<=2)||(j=2&&i<=2))
3. 最大的[5,9]个:8,5,4,9,11((i=3&&j<=3)||(j=3&&i<=3))
  令S(0)=1,s(n)=n*n-s(n-1)-s(n-2)-...-s(1)(注:n=i*i)可以求得S(n)用n来表示的表达式
对于任意i=t,
最大的[t*t-s(t),t*t]个:一定满足((i=t&&j<=t)||(j=t&&i<=t))
所以要求第k大的,可以由k求得t使得k属于区间[[t*t-s(t),t*t]] 复杂度O(1)
只需要求((i=t&&j<=t)||(j=t&&i<=t))区间间第k-(S(t-1)+S(t-2)+S(t-3)...+S(1))大的数目复杂度O(t)
区间数据数目为2*t-1(大大小于m*n).此时可以采用楼上的算法求得
算法复杂度小于O(K)
回复
超级大笨狼 2010-08-11
FancyMouse

集合B是从A中任选2个元素相加去掉重复后所组成的集合
去掉重复后所组成的集合
去掉重复

你不查,怎么去掉?

让我说你啥好呢?
回复
绿色夹克衫 2010-08-09
这是一个查找的复杂度吧,并没有包括生成数据部分

[Quote=引用 33 楼 superdullwolf 的回复:]

最小n,最大10n的话

那就在[n,10n]内做桶,要存放n个数字,每个桶大小最多是9,就是需要最多4层的二叉就可以装下。
4层的二叉1+2+4+8=15
桶的数量是(10n-n)/15个=9n/15=3n/5个。
这样复杂度大概是O(4层×桶数3n/5)=O(12/5n)=O(2.4 * n)=O(C*n)
[/Quote]
回复
超级大笨狼 2010-08-09
最小n,最大10n的话

那就在[n,10n]内做桶,要存放n个数字,每个桶大小最多是9,就是需要最多4层的二叉就可以装下。
4层的二叉1+2+4+8=15
桶的数量是(10n-n)/15个=9n/15=3n/5个。
这样复杂度大概是O(4层×桶数3n/5)=O(12/5n)=O(2.4 * n)=O(C*n)
回复
perfecttt 2010-08-08
上面的计算有点错误,最后的那个n*logn有问题,肯定是小于等于n*logn的。
回复
FancyMouse 2010-08-08
>在根,左,右这样两层的容器里查存在,我们可以认为是O(1)=C,C是层数,就算十层,也是常数的,秒杀。
完全不知所云。查存在,查什么的存在?
回复
perfecttt 2010-08-08
对A集合做一个排序,然后将重复的去除,比如 A = {1,2,3,3,3,4,4,5},去除重复的就是A={1,2,3,4,5}
O(n)
那B集合就是 B = {1+2,1+3,1+4,2+3,1+5,2+4,2+5,3+4,3+5,4+5}={3,4,5,5,6,6,7,7,8,9}
O(n*logn)
最后是B={3,4,5,6,7,8,9}
n = 8; m = 5; 最后算法复杂度是 n+nlogn+x;最后复杂度是 n*logn ,好像和m没什么太大的关系,就算有m级别的算法,肯定也不准~
回复
michael122 2010-08-08
学习了
回复
绿色夹克衫 2010-08-08
嗯,也研究一下笨狼兄的思路。可以认为m > n,m < 10 * n,细说一下桶怎么处理!
或者以20以内的奇数为例吧!
回复
超级大笨狼 2010-08-08
换句话来说,离散情况如果提前知道,那么我们完全可以规划出不一样大小的桶。

如果数据恰好是按照均匀分布的,那么做均匀的桶没问题。
如果数据是接近指数分布的,我们把数据排序O(n*lgn)
后分成k份,每份做大小不一致的桶,这样还是可以接近C*n+n*lgn=n*lgn复杂度的.

问题的关键还是桶怎么做的问题,是概率问题。
回复
超级大笨狼 2010-08-08
如果离散情况分布是均匀的,类似,A = {1,3,5,7,9,11} B应该是{2,4,6,8,10,12,14,16,18,20,22}
就可以O(C*n)

如果A = {1,3,5,7,9,110000000}跨度巨大。
B应该是{2,4,6,。。。。,220000000}

那容积率过大,做桶的办法就接近最坏的情况了,最坏复杂度n*∑2^C=n*(2M-2m)/n=n^2
就是2M-2m>n^2的情况是个死界限,超过这个就是被鄙视的。

所以,我的结论:
2M-2m<n^2的情况下,复杂度可以是O(C*n)的。

至于楼上几个同学n*logn的算法,我没仔细研究,基于平时对这几位同学的了解,他们肯定是厉害的。
不过和O(n*logn)比较,要想证明其适用界限,同理
2M-2m<n*logn的情况下,复杂度可以是O(C*n)的。

如果满足上面的条件,就可以用我罗嗦的O(C*n)算法。
回复
超级大笨狼 2010-08-08
集合A包含n个正整数,其中最大的数为m。

这个和分布情况也有关系。

B中最大的是2*Max(A)取名叫xxxx,最小的是2*Min(A)取名叫xx
那么在[xx,xxxx]内牺牲空间做桶的话,如果桶数小于n^2,就是一个小于n^2的算法。

至于做桶,还是要看分布情况。比如可以规划∑2^n个数字一桶
(桶里用二叉或者最大/小堆之类的存储,便于检索,所以是∑2^n,
因为二叉每层是1,2,4,8个,那么桶大小就可能是1,3,7,15。。。)

桶内数字越大,需要空间越小,但是复杂度会稍微受影响。

比如:
A = {1,3,5,7,9,11} B应该是{2,4,6,8,10,12,14,16,18,20,22}
可以在O(n)内同时找到最大最小值2和22
那么规划一个2到22的桶,每个桶咱放3个数字(根,左,右),那么需要22-2/3=20/3=7个桶。
在根,左,右这样两层的容器里查存在,我们可以认为是O(1)=C,C是层数,就算十层,也是常数的,秒杀。
不过层数多会牺牲空间,可以根据实际分布情况来决定。

这样就是得到了一个O(C*n)的算法。复杂度大小取决与层数的设计。
而层数的设计就和你的"其中最大的数为M"和"其中最小的数为m"有关系。

集合A包含n个正整数,其中最大的数为M,最小的数为m。

(2M-2m)/n为容积率μ ,在∑2^n就是1,3,7,15。。。中选择一个数字恰好放下该容积率的数字,就是解题的关键。假设μ =4,那么选7比较合适;假设μ =8,那么选15比较合适;层数C=1+log(μ)取上整ceiling

所以我认为,复杂度是O(C*n)的。
回复
FancyMouse 2010-08-08
mlogm的FFT那是标准的FFT习题。去年学校算法课还考到这题结果基本崩掉全班。
回复
绿色夹克衫 2010-08-07
再说一下那个帖子里的问题,大概就是说,有2000个整数,从中选3000个,使他们的和是100000,可以重复选。
直接DP的话空间要求太高了。时间也比较慢。

这个问题搞定了的话,应该可以有100000 * log(100000) * lg(3000)的解法,并且空间为100000 * log(3000)
回复
绿色夹克衫 2010-08-07
嘿嘿,模型转化之后大家就都明白了。其实是今天看一个哥们的需求,想到这个问题的。
就是一个背包程序。但弄不好要开很大的空间才能解。有了这个方法,就简单多了。

http://topic.csdn.net/u/20100807/09/18a5d6a7-5201-4251-bcef-7d2b5009dc42.html

[Quote=引用 21 楼 fanster28_ 的回复:]

哎呀 就是生成函数
a1 a2 ...am都是不超过m的
( .. x^a1 + ... x^am .. ) ^ 2
所以减去了最小数
展开就是靠的fft,浮点运算加高常数,理论复杂度低,实际的话我就不敢说了

当m很大的时候有用
[/Quote]
回复
fanster28_ 2010-08-07
哎呀 就是生成函数
a1 a2 ...am都是不超过m的
( .. x^a1 + ... x^am .. ) ^ 2
所以减去了最小数
展开就是靠的fft,浮点运算加高常数,理论复杂度低,实际的话我就不敢说了

当m很大的时候有用
回复
绿色夹克衫 2010-08-07
嗯,确实是这个思路,豁然开朗了,一直感觉得靠分治,看来还真是,嘿嘿。
对FFT理解还是不深呀,学习了!sbwwkmyd同志等着接分吧!

参与讨论的几个都有份,明天再加100分。

[Quote=引用 19 楼 sbwwkmyd 的回复:]

引用 15 楼 sbwwkmyd 的回复:
设最小数为min,最大数为max,对于max-min=x,有大约x*log(x)的算法,即不带进位的大数平方算法FFT可以解决,不过FFT算法的常数项比较高。

比如:{1,3,5,7,8,9,11}
减去最小数x=1,得集合{0,2,4,6,7,8,10}
化二进制为0000010111010101
FFT平方后得0 0 0 0 0 0 ……
[/Quote]
回复
发动态
发帖子
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
社区公告
暂无公告