我有一个TrackDay对象列表,供跑步者在不同的日子里绕着田径跑。每对开始/结束时间表示跑步者单圈运行。我们保证有匹配的开始/结束日期(按照它们出现在相应列表中的顺序):
TrackDay() {
List<DateTime> startTimes
List<DateTime> finishTimes
}
我想找到跑步者跑得最多的前N天(比方说3)。这转化为找到每个TrackDay对象的N个最长的总开始/结束时间。天真的方式是做以下事情:
for (TrackDay td : listOftrackDays) {
// loop through each start/finish lists and find out the finish-start time for each pair.
// Add the delta times (finish-start) up for each pair of start/finish objects.
// Create a map to store the time for each TrackDay
// sort the map and get the first N entries
}
是否有更好,更干净/更有效的方法来完成上述工作?
答案 0 :(得分:1)
您尝试解决的问题众所周知为Selection algorithm,尤其是Quick select。虽然排序通常很好,但对于大型集合,最好考虑这种方法,因为它会给你线性时间而不是N * log(N)。
答案 1 :(得分:0)
此解决方案应为线性时间。我假设startTimes和finishTimes支持随机访问。我不知道你的DateTime是什么API,所以使用了java.time.LocalDateTime。
public List<TrackDay> findTop(List<TrackDay> trackDays, int limit) {
limit = Math.min(limit, trackDays.size());
List<Duration> durations = new ArrayList<>(Collections.nCopies(limit, Duration.ZERO));
List<TrackDay> result = new ArrayList<>(Collections.nCopies(limit, null));
int lastIndex = limit - 1;
for (TrackDay trackDay : trackDays) {
Duration duration = Duration.ZERO;
for (int i = 0, n = trackDay.startTimes.size(); i < n; i++) {
duration = duration.plus(Duration.between(trackDay.startTimes.get(i), trackDay.finishTimes.get(i)));
}
Integer destinationIndex = null;
for (int i = lastIndex; i >= 0; i--) {
if (durations.get(i).compareTo(duration) >= 0) {
break;
}
destinationIndex = i;
}
if (destinationIndex != null) {
durations.remove(lastIndex);
result.remove(lastIndex);
durations.add(destinationIndex, duration);
result.add(destinationIndex, trackDay);
}
}
return result;
}