几天前,我在一次系统设计访谈中遇到了这个问题。我省去了多余的部分,专注于问题的核心部分。它像这样。
假设我们有一组k,v对,键是字符串,值是整数。我们可以假设存在一组固定的键(例如k1,k2,...,kn)。有一些代理将这些k,v对连续推入系统,就像流一样。我们要做的就是将所有传入对的当前值添加到旧值。
让我们举个例子。假设在时间t0
,我们有以下k-v对。
k1: 100
k3: 200
在时间t1
,有两个传入对。 k2: 50
,k3: 150
。因此,在t1
,系统状态为:
k1: 100
k2: 50
k3: 350
目标是定期发出具有最大值的密钥。我无法想到任何算法,比max-heapify可以提供更好的运行时间。我想到建立一个最大堆,然后在每个新数据到来时对其进行更新。对于每次更新,heapify()
最多需要log(n)
时间。然后,在每次调用时,我们都可以返回堆的根。但是,有没有比这个更好的解决方案了?
答案 0 :(得分:0)
这取决于(1)是否所有更新都是单调的(2)您的计算模型。
如果值仅增加(单调更新),那么显然您可以在恒定时间内保持内存中到目前为止存在的所有值中的最大值。
否则,如果值是小整数,则可以使用Y-fast trie将运行时间缩短到O(log log M)
,其中M
是最大值。
如果仅允许比较,那么Theta(log n)
是您最好的选择,因为可以自适应地使用此结构进行排序,对n
元素进行排序需要进行O(n log n)
比较。给定一个未排序的数组,将每个元素插入不同的键下。查询最大,设置其以负无穷大键(或一些值小于最小元件),重复在降序排序以读出的元素。
答案 1 :(得分:0)
保留最大值和关联的密钥在内存中。每次处理传入的键/值对时,请将已处理键的新值与最大值进行比较,如果有新的最大值,则进行更新。
答案 2 :(得分:0)
Perl概念验证的实现。显然,调试语句不应该计入时间!
#!/usr/bin/perl -T
$maxv = undef;
%maxk = ();
%pairs = ();
sub updatekeys {
my %newpairs = @_;
warn "updating\n";
while ( my ($k,$v) = each %newpairs ) {
warn "testing $k:$v\n";
my $newmax = $pairs{$k} += $v;
if ( $newmax == $maxv ) {
warn "appending $k\n";
$maxk{$k}++;
}
elsif ( $newmax > $maxv ) {
warn "new max ($newmax); overwriting $k\n";
$maxv = $newmax;
%maxk = ( $k=>1 );
}
}
warn sprintf "max=$maxv; k=( %s ); pairs=( %s )\n",
( join ',', sort keys %maxk ),
( join " ", map {"${_}:$pairs{$_}"} sort keys %pairs );
}
updatekeys ( k1=>100, k2=>200 );
updatekeys ( k2=>50, k3=>150 );
如果v可以为负,这将不起作用。