问题描述
我必须用Java设计一个REST API:-
-
使用以下
json
接受POST请求:-{ “仪器”:“ ABC”, “ price”:“ 200.90”, “时间戳”:“ 2018-09-25T12:00:00” }
这些记录将保存在内存中,而不是任何类型的数据库中。
-
将有一个GET API,该API返回最近60秒内收到的特定仪器记录的统计信息。 GET请求应为:-/ statistics / {instrumentName},例如:-/ statistics / ABC。响应如下所示:-
{ “ count”:“ 3” “ min”:“ 100.00” “ max”:“ 200.00” “ sum”:“ 450.00” “ avg”:“ 150.00” }
该算法实现起来很复杂的原因是应该执行GET调用-O(1)时间和空间复杂度。
我为3#想到的方法是有一个将具有60个存储桶的集合(因为我们必须计算过去60秒的时间,因此每1秒进行一次采样)。每次交易进入时,都会根据密钥(即时分秒)进入特定的存储桶(这将是具有该密钥和该秒的统计信息的映射)。
但是我无法理解的是如何解决2#问题,我们必须在O(1)的时间和空间复杂度中获取特定仪器/ statistics / ABC的最近60秒的统计信息。
清除60秒以上的记录的最佳策略是什么?
任何对算法的帮助将不胜感激。
解决方法
将数据存储在Map<String,Instrument>
中,并让类看起来像这样:
class Instrument {
private String name;
private SortedMap<LocalDateTime,BigDecimal> prices;
private BigDecimal minPrice;
private BigDecimal maxPrice;
private BigDecimal sumPrice;
// Internal helper method
private void cleanup() {
LocalDateTime expireTime = LocalDateTime.now().minusSeconds(60);
Map<LocalDateTime,BigDecimal> expiredPrices = this.prices.headMap(expireTime);
for (BigDecimal expiredPrice : expiredPrices.values()) {
if (this.minPrice.compareTo(expiredPrice) == 0)
this.minPrice = null;
if (this.maxPrice.compareTo(expiredPrice) == 0)
this.maxPrice = null;
this.sumPrice = this.sumPrice.subtract(expiredPrice);
}
expiredPrices.clear(); // Removes expired prices from this.prices
if (this.minPrice == null && ! this.prices.isEmpty())
this.minPrice = this.prices.values().stream().min(Comparator.naturalOrder()).get();
if (this.maxPrice == null && ! this.prices.isEmpty())
this.maxPrice = this.prices.values().stream().max(Comparator.naturalOrder()).get();
}
// other code
}
Instrument
的所有公共方法都必须为synchronized
,并且必须从对cleanup()
的调用开始,因为自从上一次调用以来已经过去了一段时间。 addPrice(LocalDateTime,BigDecimal)
方法当然必须更新3个统计信息字段。
要确保统计信息同步,最好有一个Statistics
类可用作返回值,因此所有4个主要统计值(包括从{{1 }})代表同一组价格。