933. Number of Recent Calls

933. Number of Recent Calls

Write a class RecentCounter to count recent requests.

It has only one method: ping(int t), where t represents some time in milliseconds.

Return the number of pings that have been made from 3000 milliseconds ago until now.

Any ping with time in [t - 3000, t] will count, including the current ping.

It is guaranteed that every call to ping uses a strictly larger value of t than before.

Example:

Input: inputs = ["RecentCounter","ping","ping","ping","ping"], inputs = [[],[1],[100],[3001],[3002]]
Output: [null,1,2,3,3]

Note:

  1. Each test case will have at most 10000 calls to ping.
  2. Each test case will call ping with strictly increasing values of t.
  3. Each call to ping will have 1 <= t <= 10^9.

State the problem (as you understand it): 

  • return the elements within the range [t - 3000, t]. 

Solve examples that are big enough and are normal cases (manually to figure out the general solution): 

  • The input 3002 in the example means that we need to return pings with time 100, 3001, and 3002 because 2 calculated from 3002 - 3000 and 3002 are the lower bound and upperbound of the range of elements we can return, respectively. So,
    1. figure out the lowerbound of the range, that is t - 3000
    2. return timestamps which are equal to or greater than the lowerbound

Ask clarification questions:

  1. are we required to remove obsolete timestamps, that is timestamps which occured before t - 3000?
  2. how many calls to ping will I get?
  3. will I get random values of t for calls to ping?
  4. what is the valid range of input for the parameter t?

State assumptions:

  1. I will get at most 10000 calls to ping
  2. ping will be called with strictly increasing values of t
  3. each call to ping will have 1 <= t <= 10^9

Consider several test cases (edge cases, base cases):

See if a Data Structure fits the problem:

  1. use queue to keep timestamps in increasing order and get O(n) time complexity for pings
  2. use TreeMap to keep timestamps in increasing order and it's ceiling method to get O(log(n)) time complexity for pings

See if an Algorithm fits the problem:

  1. ad-hoc algorithm

Extract the core problem:

  • return elements within the range [t-3000, t] efficiently

Try breaking it down into subproblems:

Explain Potential Solutions (see solutin section):

Other solutions:

  1. Use TreeSet and it's add() and tailSet() methods. Time complexity is O(log(N)), and space complexity is O(N)
  2. Use binary search to find the index of the ceiling of t - 3000, then list.size() - index is the answer. Time complexity of O(log(N))

Compare solutions:

  • using Queue gives the fastest time complexity since ping() will have an amortised time of O(1)

Follow Up (TODO):

Solution 1:


Ideas: 

  • keep a queue of the most recent calls in increasing order of t
  • since it is guaranteed that every call to ping uses a strictly larger value of t than before, we don't need any data structure that provides sorting

Steps:

  1. when we see a new call with time t, remove all calls that occurred before t - 3000
  2. return queue's size

Validate the correctness (of your pseudocode with a test case):

Data Structure:

  • use a queue

Time Complexity:

  • O(1), since there will be N calls to ping() we need to analyse the complexity of N calls to ping(). The N calls will have a total complexity of O(N). Why? Because even if the number of iteration of the while loop in the worst case for one call is N, after N calls there will only be N iterations of the while loop in total. This is because at every iteration of the while loop we remove one element of the queue and of course we can only remove maximum N elements in total. I think this analysis is called the aggregate method. So ping() has an amortised time of O(1)

Space Complexity:

  • O(W), where W = 3000W=3000 is the size of the window we should scan for recent calls. In this problem, the complexity can be considered O(1)
class RecentCounter {
    private Queue<Integer> queue = new LinkedList<>();

    public RecentCounter() {
    }
    
    public int ping(int t) {
        this.queue.add(t);
        while (this.queue.peek() < t - 3000) {
            this.queue.poll();
        }
        return this.queue.size();
    }
}

Test your code again to make sure you don't have any bugs.

Solution 2:


Ideas: 

  • use current time and total number of calls as the key and value of TreeMap, respectively

Steps:

  1. add the given time to the TreeMap
  2. return the size of a map whose keys are greater than or equal to the t - 3000

Validate the correctness (of your pseudocode with a test case):

Data Structure:

  • use a TreeMap

Time Complexity:

  • O(log(N))

Space Complexity:

  • O(N), where N is the number of ping calls from first one till now.
class RecentCounter {
    private Queue<Integer> queue = new LinkedList<>();

    public RecentCounter() {
    }
    
    public int ping(int t) {
        this.queue.add(t);
        while (this.queue.peek() < t - 3000) {
            this.queue.poll();
        }
        return this.queue.size();
    }
}

Test your code again to make sure you don't have any bugs.

Solution 3:


Ideas: 

  • use ArrayList to store timestamps
  • use binary search to find the index of the ceiling of t - 3000

Steps:

  1. add the given time to the ArrayList
  2. use binary search to find the index of the ceiling of t - 3000
  3. return list's size - index

Validate the correctness (of your pseudocode with a test case):

Data Structure:

  • use an ArrayList

Time Complexity:

  • O(log(N))

Space Complexity:

  • O(N), where N is the number of ping calls from first one till now.
class RecentCounter {
    private List<Integer> list = new ArrayList<>();

    public RecentCounter() {
    }
    
    public int ping(int t) {
        this.list.add(t);
        int target = t - 3000;
        
        int left = 0;
        int right = list.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (list.get(mid) >= target) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        
        return list.size() - left;
    }
}

Test your code again to make sure you don't have any bugs.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值