[问题] 给定两个有序的正整数数组A[n]和B[n], 我们定义如下集合: S = { (a, b} | a in A[n] and b in B[n]}, 很明显S总共有n^2个元素对. 元素对的值定义如下: value(a, b) = a + b.求集合S中值最大的n个元素对.
one possible way is to use a heap/priority_queue. pseudo^H^H^H^H^Hython
code:
#!/usr/bin/python
#
# for a quick & dirty demo, we just find the n biggest _values_.
# this makes test easy, since the actual pairs might not be unique.
#
# well, you get the idea, feel free to change it to suit your needs.
#
# Beer License -- CopyLeft (D) 1q84 All Wrongs Not Reserved
import heapq
import random
def bestn(A, B):
A.sort(reverse=True)
B.sort(reverse=True)
n = len(A)
score = [(-a - B[0], 0) for a in A]
heapq.heapify(score)
ret = []
for x in xrange(n):
v, k = heapq.heappop(score)
ret.append(-v)
if k < n - 1:
heapq.heappush(score, (v + B[k] - B[k+1], k+1))
return ret
def brute(A, B):
n = len(A)
score = [a + b for a in A for b in B]
score.sort(reverse=True)
return score[:n]
r = random.Random()
n = 1000
limit = 10000
A = [r.randint(1, limit) for x in xrange(n)]
B = [r.randint(1, limit) for x in xrange(n)]
print all(a == b for a,b in zip(bestn(A,B), brute(A,B)))
--
Alecs King
> 以此递推.
不知道有没有算法可以不用算出全部 n^2 个和的。
On Jul 21, 12:44 am, "Mikster.Z" <chinamix...@gmail.com> wrote:
> 你是认为a[n]跟b[n-2]不能是第三大的么....
>
不好意思,发重了
这个问题肯定有O (k )的算法的,
设两个指针从两个数组胃部向前扫描
,最多k 次就应该得到结果
在 2010-7-22 上午1:57,"freepro...@gmail.com" <freepro...@gmail.com>编写:
sigh, 这我都没想清楚
不知道有没有算法可以不用算出全部 n^2 个和的。
> 在 2010年7月21日 下午1:59,freeprogram...@gmail.com <freeprogram...@gmail.com>写道:
On Jul 21, 12:44 am, "Mikster.Z" <chinamix...@gmail.com> wrote:
> 你是认为a[n]跟b[n-2]不能是第三大的么....
>
>
> > 貌似O(n)就行了。
> > 最大的肯定是a[n]+b[n]
> > 第二大的是max{ a[n]+b[n-1], a[n-1]+b[n]}
> > 第三大的是min { a[n]+b[n...
设
A的元素为x1, x2, ..., xn
B的元素为y1, y2, ..., yn
下面这个矩阵:
x1 x2 ... xn
y1
y2
... Cij=xi+yj
yn
的特征十分明显:
每一行单调增
每一列单调增
我的算法描述为:
初始:
取上述矩阵的左上角C11放入一个priority queue;
初始化结果序列为空;
循环:
每次从队列中取出头元素Cij放入结果序列中;
检查下述两个候选元素:
C{i+1}j和Ci{j+1}
插入到priority queue中(如有重复则去除)
终止条件,结果序列的长度达到k(原题是n),或priority queue为空。
Python源代码和测试结果如下:
def orderred_insert_by(f, lst, p):
for i in range(len(lst)):
if p == lst[i]:
return
if f(lst[i])>f(p):
lst.insert(i, p)
return
lst.append(p)
def ksum(k, xs, ys):
c=lambda (i, j): xs[i]+ys[j]
res = []
q = [(0, 0)]
while len(res)<k and q!=[]:
(i, j)=q.pop(0)
res.append(c((i, j)))
if i+1<len(xs):
orderred_insert_by(c, q, (i+1, j))
if j+1<len(ys):
orderred_insert_by(c, q, (i, j+1))
return res[:k]
简单的测试代码:
def brute_force(k, xs, ys):
res= [x+y for x in xs for y in ys]
res.sort()
return res[:k]
def test():
for i in range(10):
n= random.randint(1, 1000)
k = random.randint(1, n)
a = random.sample(range(10000), n)
a.sort()
b = random.sample(range(10000), n)
b.sort()
if ksum(k, a, b) != brute_force(k, a, b):
print "fail!"
print "a=", a
print "b=", b
print "k=", k
print "brute-force:", brute_force(k, a, b)
print "ksum:", ksum(k, a, b)
return
print "OK"
if __name__ == "__main__":
test()
运行结果:
# ./ksum.py
OK
难道就非得heapify不可?
On Jul 29, 3:16 pm, "Mikster.Z" <chinamix...@gmail.com> wrote:
> 比朴素的算法还烂
>
我举一个有代表性的例子:
A=[5, 100, 200]
B=[1, 2, 3]
还是列成矩阵看着方便:
5 100 200
================
1 | 6 101 201
2 | 7 102 202
3 | 8 103 203
这个矩阵的大小顺序是
1, 4, 7
2, 5, 8
3, 6, 9
也就是a[1]+b[1], a[1]+b[2], a[1]+b[3], ...
而不是通常我们想象的:
小,次小,较大,更大,...
次小,较大,更大,...
较大,更大,...
更大,...
....
On Jul 29, 5:32 pm, yang yang <cyal...@gmail.com> wrote:
> 先排序A,B
> 再从A,B中逐渐取小值相加 保留在a,b
>
> 疯了蓝莓
>
把矩阵转45度就看清楚了。
c11
c21,c12
c31,c22,c13
..., ..., ..., ...
每次节点展开的宽度为2,然后push回队列。
如果不做重复检测,队列增加的速度为1, 2, 4, ...2^i
总次数为2^(i+1)-1,其中i是弹出元素的次数。
队列不会无限增加,最长达到n^2-n
终止条件是队列弹出k个元素。
以下是一个队列变化的例子:
raw q= [(0, 1), (1, 0)]
raw q= [(1, 0), (1, 1), (0, 2)]
raw q= [(2, 0), (1, 1), (0, 2)]
raw q= [(3, 0), (1, 1), (2, 1), (0, 2)]
raw q= [(1, 1), (2, 1), (3, 1), (0, 2), (4, 0)]
raw q= [(2, 1), (3, 1), (0, 2), (1, 2), (4, 0)]
raw q= [(3, 1), (0, 2), (1, 2), (2, 2), (4, 0)]
raw q= [(0, 2), (1, 2), (2, 2), (3, 2), (4, 0), (4, 1)]
raw q= [(1, 2), (2, 2), (3, 2), (4, 0), (4, 1), (0, 3)]
On Jul 29, 5:36 pm, "Mikster.Z" <chinamix...@gmail.com> wrote:
> 1:线性查找
> 2:重复检测
> 3:你知道你的复杂度是多少么...
>
http://lyle.smu.edu/~saad/courses/cse3358/ps5/problemset5sol.pdf
解释下,还是延续前面的矩阵思路,这个矩阵其实组成了一个Young Tableau。
不用一开始把全部的Young Tableau全部生成,需要哪个cell Cij时用a[i]+b[j]计算即可。
算法描述如下:
1. 取Young Tableau的C11元素,作为min
2. 然后Youngify
3. 重复1,2 k次即得前k小的元素。
另:Young Tableau在CLRS的习题
Problems 6-3: Young tableaus
On Aug 3, 10:03 am, tom sun <vince.s....@gmail.com> wrote:
> 这个问题显然可以看成是归并排序最后一步对两个字串的整合。
> O(K)
自己试了一下,新宇的BFS+priority queue的确能得到正解
On Jul 29, 3:32 pm, Devymex <devy...@gmail.com> wrote:
> 前提:数组已按降序排序,n不超过两数组元素数量之积。
>
> 算法思路
>
> 将所有数据按矩阵排列,然后按常规坐标轴的比例进行展部,可以形成如下图形:
> [image: sum1.PNG]
>
> 每一个红点所代表的数,为纵坐标值和横坐标值相加得到的和。显然,最右上角的数最大。将所有数分为两个部分,一是占领区,二是敌区,在两个区之间构造一条战线, 每次攻占战线中最薄弱的一环(最大值),然后顺势将战线推进至下方元素,以此类推。整个战局由最右上角开始向左下角推。
>
> 开始先将最大的<7,5>拿下,战线往下推,攻占<7,3>。这时发现左边的一列还没有任何元素被占领。迅速将<6,5>拿下后,此时战线的最薄弱点就是<6, 5>
>
> [image: sum2.PNG]
>
> 将<6,5>吃掉后战线下推,并发现左边的列3仍没有任何元素被占。将<3,5>纳入战线,此时,最薄弱点是<7,3>
> [image: sum3.PNG]
> 以下过程和上面类似
> [image: sum4.PNG][image: sum5.PNG][image: sum6.PNG]
> [image: sum7.PNG][image: sum8.PNG][image: sum9.PNG]
>
> =========签名档=========
> 待到土共灭亡日,家祭无忘告乃翁!
> 欢迎 Follow @devymex <https://twitter.com/devymex>
>
> 2010/7/30 Devymex <devy...@gmail.com>
> > 欢迎 Follow @devymex <https://twitter.com/devymex>
>
> > 2010/7/29 Mikster.Z <chinamix...@gmail.com>
>
> > 你是对的~~
> sum3.PNG
> 1KViewDownload
>
> sum4.PNG
> 1KViewDownload
>
> sum2.PNG
> 1KViewDownload
>
> sum7.PNG
> 1KViewDownload
>
> sum8.PNG
> 1KViewDownload
>
> sum6.PNG
> 1KViewDownload
>
> sum5.PNG
> 1KViewDownload
>
> sum1.PNG
> 1KViewDownload
>
> sum9.PNG
> 1KViewDownload