【问题标题】:Java: Implement Hit() and getNumHits() in last minuteJava:在最后一分钟实现 Hit() 和 getNumHits()
【发布时间】:2016-02-10 15:24:23
【问题描述】:

这更像是一个设计问题,但我只是想知道是否有人对这个问题有任何想法。

在一次采访中,我被要求设计 2 种方法。

hit();
getNumHits();

每次用户向服务器发出请求时都会调用hit()getNumHits() 返回最后一分钟的点击次数。

有什么想法吗?

更新:

我知道这是重复的

Implementation of a "hits in last [second/minute/hour]" data structure

但我在理解 C++ 代码时遇到了一些困难,想知道我们是否可以得到 Java 版本的答案!

【问题讨论】:

    标签: java algorithm data-structures


    【解决方案1】:

    您正在寻找的核心是保留最后一分钟内所有命中的列表。使用LinkedList 可以快速获得removeFirst()

    class HitCounter {
    
        // My most recent list - only the last minute is retained.
        LinkedList<Long> hitList = new LinkedList<>();
        private static final long OneMinute = 1000L * 60L;
    
        public void hit() {
            // Track the hit.
            hitList.add(System.currentTimeMillis());
            // Always clean up.
            cleanup();
        }
    
        public int hitCount() {
            // Make sure we are clean.
            cleanup();
            return hitList.size();
        }
    
        private void cleanup() {
            // Eat all stale hits.
            while (hitList.getFirst() < System.currentTimeMillis() - OneMinute) {
                hitList.removeFirst();
            }
        }
    }
    

    但是,如果您的点击速度非常快,并且您怀疑保留所有点击的所有时间是否有效,您可以使用存储桶系统进行量化。在这里,我记录每一秒。显然,您可能会在一秒钟内获得尽可能多的点击数。

    class HitCounter {
    
        // One bucket - keeps track of how many hits since the start time.
        private class Bucket {
    
            // Probably should use an atomic.
            int count;
            // The time this bucket was started.
            long started = System.currentTimeMillis();
        }
        // My most recent list - only the last minute is retained.
        LinkedList<Bucket> hitList = new LinkedList<>();
        private static final long OneSecond = 1000L;
        private static final long OneMinute = OneSecond * 60L;
    
        public void hit() {
            // Grab the hit time.
            long now = System.currentTimeMillis();
            // Normally goes in the last bucket.
            Bucket bucket = hitList.size() > 0 ? hitList.getLast() : null;
            // Time for new bucket?
            if (bucket == null || now > bucket.started + OneSecond) {
                // Yup!
                hitList.add(bucket = new Bucket());
            }
            // Track the hit.
            bucket.count++;
            // Always clean up.
            cleanup();
        }
    
        public int hitCount() {
            // Make sure we are clean.
            cleanup();
            // Add up all the bucket counts.
            int total = 0;
            for (Bucket bucket : hitList) {
                total += bucket.count;
            }
            return total;
        }
    
        private void cleanup() {
            // Eat all stale hits.
            while (hitList.size() > 0 && hitList.getFirst().started < System.currentTimeMillis() - OneMinute - OneSecond) {
                hitList.removeFirst();
            }
        }
    }
    
    public void test() throws InterruptedException {
        HitCounter hitList = new HitCounter();
        for (int i = 0; i < 90; i++) {
            hitList.hit();
            System.out.println(i + " - " + hitList.hitCount());
            Thread.sleep(1000);
        }
    }
    

    【讨论】:

    • 如果 hit 之前被偶然调用过,此代码只会返回正确的 hitCount 值。例如:调用hit,等待2分钟,然后调用hitCount将返回1。
    • @simonzhu - 嗯 - 这可能需要一些调整。我可能会拿着一圈桶,每个桶都保存着那一秒记录的计数。
    • @simonzhu - 添加了第二个选项 - 不太准确,但不容易占用内存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 2021-09-28
    • 2018-01-17
    • 1970-01-01
    • 2014-09-13
    • 2020-03-08
    • 2019-07-25
    相关资源
    最近更新 更多