algorithm - 移动最大变量

标签 algorithm max moving-average

昨天,我在一次技术面试中被问到以下问题。

假设您在一家新闻机构工作。在每个离散的时间点 t,故事都会中断。有些故事比其他故事更有趣。这种“热度”用自然数 h 表示,数字越大代表新闻报道越热。

给定一个 Sn 故事流,你的工作是从最近的 k 个故事中找到 HitTest 门的故事,每一个 t >= k.

到目前为止,一切顺利:这是移动最大值问题(也称为滑动窗口最大值问题),并且有一个 linear-time algorithm就解决了。

现在问题变得更难了。当然,与新故事相比,旧故事通常不那么热门。令最近故事的年龄 a 为零,并让任何其他故事的年龄比其后续故事的年龄大 1。然后将故事的“改进的热度”定义为 max(0, min(h, k - a))

这是一个例子:

n = 13, k = 4

S indices:   0   1   2   3   4   5   6   7   8   9  10
S values:    1   3   1   7   1   3   9   3   1   3   1

mov max hot indices:     3   3   3   6   6   6   6   9
mov max hot values:      7   7   7   9   9   9   9   3

mov max imp-hot indices: 3   3   5   6   7   7   9   9
mov max imp-hot values:  4   3   3   4   3   3   3   3

这个问题让我一头雾水。我考虑过在计算最大值之前将索引添加到每个元素,但这给了你一个故事的热度何时每一步都减少 1 的答案,无论它是否达到热度界限。

你能为这个问题找到一个具有次二次(理想情况下:线性)运行时间的算法吗?

最佳答案

我将为涉及双端队列 (deque) 的原始问题绘制一个线性时间解决方案,然后将其扩展到改进的热度而不损失渐近效率。

原始问题:在窗口中保留一个双端队列,其中包含 (1) 比到目前为止 (2) 的所有其他故事更新或更热的故事。在任何给定时间,队列中 HitTest 门的故事都排在最前面。在从后面弹出每个故事直到找到更热门的故事之后,新故事被推到双端队列的后面。故事随着窗外的老化从前面弹出。

例如:

S indices:   0   1   2   3   4   5   6   7   8   9  10
S values:    1   3   1   7   1   3   9   3   1   3   1

deque: (front) [] (back)
push (0, 1)
deque: [(0, 1)]
pop (0, 1) because it's not hotter than (1, 3)
push (1, 3)
deque: [(1, 3)]
push (2, 1)
deque: [(1, 3), (2, 1)]
pop (2, 1) and then (1, 3) because they're not hotter than (3, 7)
push (3, 7)
deque: [(3, 7)]
push (4, 1)
deque: [(3, 7), (4, 1)]
pop (4, 1) because it's not hotter than (5, 3)
push (5, 3)
deque: [(3, 7), (5, 3)]
pop (5, 3) and then (3, 7) because they're not hotter than (6, 9)
push (6, 9)
deque: [(6, 9)]
push (7, 3)
deque: [(6, 9), (7, 3)]
push (8, 1)
deque: [(6, 9), (7, 3), (8, 1)]
pop (8, 1) and (7, 3) because they're not hotter than (9, 3)
push (9, 3)
deque: [(6, 9), (9, 3)]
push (10, 1)
pop (6, 9) because it exited the window
deque: [(9, 3), (10, 1)]

为了处理新问题,我们修改了处理老化故事的方式。我们不是在故事滑出窗口时弹出故事,而是在其改进的热度变得小于或等于它的热度时弹出头条故事。在确定头条新闻时,只需要考虑最近弹出的故事。

在 Python 中:

import collections

Elem = collections.namedtuple('Elem', ('hot', 't'))


def winmaximphot(hots, k):
    q = collections.deque()
    oldtop = 0
    for t, hot in enumerate(hots):
        while q and q[-1].hot <= hot:
            del q[-1]
        q.append(Elem(hot, t))
        while q and q[0].hot >= k - (t - q[0].t) > 0:
            oldtop = k - (t - q[0].t)
            del q[0]
        if t + 1 >= k:
            yield max(oldtop, q[0].hot) if q else oldtop
        oldtop = max(0, oldtop - 1)


print(list(winmaximphot([1, 3, 1, 7, 1, 3, 9, 3, 1, 3, 1], 4)))

关于algorithm - 移动最大变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41408954/

相关文章:

java - 无等待和无锁算法的示例/说明

algorithm - 如何计算对数系列的平方和

algorithm - 在不知道哪个是哪个的情况下打印来自 k 个不同树的排序数字

sql - ORACLE SQL 中的 MAX()

python - 这是计算移动平均线的有效方法吗?

algorithm - 查找数组中的范围

c++ - 最多 2 位数字

php - 在多维数组中查找最大值

按组滚动/移动平均

MySQL 移动平均线 - 4 周