【发布时间】:2017-06-16 12:56:13
【问题描述】:
这是一个关于一个有点复杂的问题的算法问题。基础是这样的:
一个基于可用槽和预留槽的调度系统。插槽有一定的标准,我们称之为标签。如果可用槽的标记集是保留槽的超集,则保留通过这些标记与可用槽匹配。
作为一个具体的例子,以这个场景为例:
11:00 12:00 13:00
+--------+
| A, B |
+--------+
+--------+
| C, D |
+--------+
在 11:00 到 12:30 之间可以预订标签 A 和 B,从 12:00 到 13:30 C 和 D 可以预订,并且有一个从大约 12:00 到 12:30 重叠。
11:00 12:00 13:00
+--------+
| A, B |
+--------+
+--------+
| C, D |
+--------+
xxxxxx
x A x
xxxxxx
这里已经预订了A,因此在11:15-ish 和12:00-ish 之间无法预订A 或B。
简而言之就是这个想法。可用插槽没有具体限制:
- 一个可用的插槽可以包含任意数量的标签
- 任意数量的时隙可以随时重叠
- 槽的长度是任意的
- 保留可以包含任意数量的标签
系统中唯一需要遵守的规则是:
- 添加预留时,至少有一个剩余的可用插槽必须与预留中的所有标签匹配
澄清一下:如果同时有两个可用的插槽,例如标签A,那么此时可以为A 进行两个预留,但不能再预留了。
我正在使用 interval tree 的修改实现;快速概览:
- 所有可用槽都添加到区间树中(保留重复/重叠)
- 所有保留槽都被迭代并且:
- 从树中查询与预订时间匹配的所有可用时隙
- 与预订标签匹配的第一个被切片,并从树中移除切片
当这个过程完成后,剩下的就是剩余的可用槽片,我可以查询是否可以为特定时间进行新的预订并添加它。
数据结构看起来像这样:
{
type: 'available',
begin: 1497857244,
end: 1497858244,
tags: [{ foo: 'bar' }, { baz: 42 }]
}
{
type: 'reserved',
begin: 1497857345,
end: 1497857210,
tags: [{ foo: 'bar' }]
}
标签本身就是键值对象,它们的列表就是一个“标签集”。如果有帮助,可以将它们序列化;到目前为止,我使用的是 Python set 类型,这使得比较很容易。时隙开始/结束时间是树中的 UNIX 时间戳。我并不是特别喜欢这些特定的数据结构,如果有用,我可以重构它们。
我面临的问题是这不是没有错误的;每隔一段时间,预订就会潜入与其他预订发生冲突的系统中,我还不知道这到底是怎么发生的。当标签以复杂的方式重叠时,它也不是很聪明,需要计算最佳分布,以便所有预留可以尽可能地适合可用的插槽;事实上,目前在重叠场景中如何将预订与可用时隙进行匹配是不确定的。
我想知道的是:区间树主要用于此目的,但我当前的系统将标签集匹配作为附加维度添加到此系统是笨重且固定的; 是否有可以优雅地处理此问题的数据结构或算法?
必须支持的操作:
- 向系统查询与特定标签集匹配的可用插槽(考虑可能会降低可用性但它们本身不属于所述标签集的保留;例如,在上面的示例中查询
B的可用性)。李> - 确保不能将没有匹配的可用插槽的预留添加到系统中。
【问题讨论】:
-
您没有很清楚地解释输入。只要标签正确匹配,是否可以将给定预留分配给任何插槽?或者预订是否附有时间间隔?
-
我已经阐明了使用的数据结构。是的,预订只需与可用空档的标签和时间相匹配即可。
-
不是在树中拥有所有可用的插槽然后从中删除它们,而是从一棵空树开始然后尝试用保留填充它是否有意义,这样就不会有冲突?
-
@Florian 我对任何方法都完全开放。根据我发布的数据结构(甚至是可延展的),我只有一堆值,并且需要能够 1)获得可按标签集过滤的仍然可用的插槽,以及 2)检查是否可以添加新的预订。
-
@Florian 以 Apple Store Genius Bar 预订之类的方式为例:您只是在预订一个与 某人 谈论您的 iPhone 的时间,比如说,哪个特别你得到的插槽或人。届时只有有知识的人可以与您讨论您的 iPhone,但会有多个人,您将在那时和那里弄清楚您究竟得到了哪一个。跨度>
标签: algorithm language-agnostic interval-tree