我有记录日志。每条记录都有一个ID和时间戳。即使可以删除其间的记录,新记录也会以单调递增的ID附加到日志中。
问题是 - 如果给你一个时间戳T1,提供一个有效的算法来确定时间戳= Ceil(T1)的日志记录。
注意事项。数百万条记录的日志可能非常大。由于记录删除,可能会丢失记录。
示例:如果log record =(ID,Timestamp),则log可以显示如下:
(1,10),(2,11),(5,15),(8,18),(9,19),(10,20)
查找最小时间戳大于或等于17的记录的ID。
答案是8。
查找最小时间戳大于或等于11的记录的ID。
答案是2。
查找最小时间戳大于或等于22的记录的ID。
答案是Nil
查找最小时间戳大于或等于5的记录的ID。
答案是1
我已经提出了简单的数据结构来解决这个问题。
/* index: 0 1 2 3 4 5 6 7 8 9 10 11 12 */
int ids[]= {1, 2, 6, 7, 10, 11, 12};
int map[]= {0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1};
int time[]= {0, 10, 20, 0, 0, 0, 60, 70, 0, 0, 100, 110, 120};
int start= 1, end = 12; // this is known to us.
ids []是所有ID的列表。鉴于此列表可能是数百万,我们无法将此列表编入索引。因此在上面的示例中,缺少ID 3,4,5,8,9。但是这份名单正在增加。
map []是位图,可以告诉您是否存在给定的ID。这是一个廉价的操作。
time []是存在的每个ID的时间戳数组。记得假设获取时间戳实际上是昂贵的操作。
ID和时间戳值之间也没有相关关系。而不是10,20,等等,它可能像1133,2987 ......等等。但是按顺序递增。
您需要填写此功能:
int
find_ceil_id(int timestamp)
{
.....
....
return(id)
}
答案 0 :(得分:0)
如果此功能在搜索之间保留在内存中,我们可以利用之前的搜索来缩小未来的搜索范围。如果到达时间戳是昂贵的,那么这可能是一个非常显着的改进。但是如果它们已经在你的帖子中的数组中已经存在,那么这主要是一个没有实际意义的点。 假设时间戳是唯一的,我将从此开始寻求解决方案:
int FindFirstNonZero(int startIdx)
{
int myIdx=startIdx;
while (map[myIdx] == 0)
{
myIdx++;
}
return(myIdx);
}
int FindLastNonZero(int startIdx)
{
int myIdx=startIdx;
while (map[myIdx] == 0)
{
myIdx--;
}
return(myIdx);
}
int find_ceil_id(int timestamp)
{
int low=FindFirstNonZero(0);
int high=FindLastNonZero(map.count -1);
int checkIndex = FindLastNonZero((low + high)/2);
int checkTime;
while (low < FindLastNonZero(high - 1))
{
checkTime = time[checkIndex];
if (checkTime >= timestamp) {
high = checkIndex;
} else {
low = checkIndex;
}
checkIndex = FindLastNonZero((low+high) / 2);
if (checkIndex == low) {
checkIndex = FindFirstNonZero(low+1);
}
}
return (high);
}
从您的一些评论中,似乎时间戳可以重复。是这样吗?如果是这样,它将需要对上述内容进行微小改动......没关系,做出改变,甚至使代码更简单。
这是一个基本的二进制搜索,它将在log2(N)尝试中找到正确的元素,N是ID数组的大小。因此,对于ID数组中的超过一百万个条目,它只需要检查其中的20个以获得正确的条目。对于超过十亿的条目,它只需要检查30。
我没有编译和测试代码,这取决于你。但它应该有用。