Welcome to Subscribe On Youtube

3508. Implement Router

Description

Design a data structure that can efficiently manage data packets in a network router. Each data packet consists of the following attributes:

  • source: A unique identifier for the machine that generated the packet.
  • destination: A unique identifier for the target machine.
  • timestamp: The time at which the packet arrived at the router.

Implement the Router class:

Router(int memoryLimit): Initializes the Router object with a fixed memory limit.

  • memoryLimit is the maximum number of packets the router can store at any given time.
  • If adding a new packet would exceed this limit, the oldest packet must be removed to free up space.

bool addPacket(int source, int destination, int timestamp): Adds a packet with the given attributes to the router.

  • A packet is considered a duplicate if another packet with the same source, destination, and timestamp already exists in the router.
  • Return true if the packet is successfully added (i.e., it is not a duplicate); otherwise return false.

int[] forwardPacket(): Forwards the next packet in FIFO (First In First Out) order.

  • Remove the packet from storage.
  • Return the packet as an array [source, destination, timestamp].
  • If there are no packets to forward, return an empty array.

int getCount(int destination, int startTime, int endTime):

  • Returns the number of packets currently stored in the router (i.e., not yet forwarded) that have the specified destination and have timestamps in the inclusive range [startTime, endTime].

Note that queries for addPacket will be made in increasing order of timestamp.

 

Example 1:

Input:
["Router", "addPacket", "addPacket", "addPacket", "addPacket", "addPacket", "forwardPacket", "addPacket", "getCount"]
[[3], [1, 4, 90], [2, 5, 90], [1, 4, 90], [3, 5, 95], [4, 5, 105], [], [5, 2, 110], [5, 100, 110]]

Output:
[null, true, true, false, true, true, [2, 5, 90], true, 1]

Explanation

Router router = new Router(3); // Initialize Router with memoryLimit of 3.
router.addPacket(1, 4, 90); // Packet is added. Return True.
router.addPacket(2, 5, 90); // Packet is added. Return True.
router.addPacket(1, 4, 90); // This is a duplicate packet. Return False.
router.addPacket(3, 5, 95); // Packet is added. Return True
router.addPacket(4, 5, 105); // Packet is added, [1, 4, 90] is removed as number of packets exceeds memoryLimit. Return True.
router.forwardPacket(); // Return [2, 5, 90] and remove it from router.
router.addPacket(5, 2, 110); // Packet is added. Return True.
router.getCount(5, 100, 110); // The only packet with destination 5 and timestamp in the inclusive range [100, 110] is [4, 5, 105]. Return 1.

Example 2:

Input:
["Router", "addPacket", "forwardPacket", "forwardPacket"]
[[2], [7, 4, 90], [], []]

Output:
[null, true, [7, 4, 90], []]

Explanation

Router router = new Router(2); // Initialize Router with memoryLimit of 2.
router.addPacket(7, 4, 90); // Return True.
router.forwardPacket(); // Return [7, 4, 90].
router.forwardPacket(); // There are no packets left, return [].

 

Constraints:

  • 2 <= memoryLimit <= 105
  • 1 <= source, destination <= 2 * 105
  • 1 <= timestamp <= 109
  • 1 <= startTime <= endTime <= 109
  • At most 105 calls will be made to addPacket, forwardPacket, and getCount methods altogether.
  • queries for addPacket will be made in increasing order of timestamp.

Solutions

Solution 1

  • class Router {
        private int lim;
        private Set<Long> vis = new HashSet<>();
        private Deque<int[]> q = new ArrayDeque<>();
        private Map<Integer, Integer> idx = new HashMap<>();
        private Map<Integer, List<Integer>> d = new HashMap<>();
    
        public Router(int memoryLimit) {
            this.lim = memoryLimit;
        }
    
        public boolean addPacket(int source, int destination, int timestamp) {
            long x = f(source, destination, timestamp);
            if (vis.contains(x)) {
                return false;
            }
            vis.add(x);
            if (q.size() >= lim) {
                forwardPacket();
            }
            q.offer(new int[] {source, destination, timestamp});
            d.computeIfAbsent(destination, k -> new ArrayList<>()).add(timestamp);
            return true;
        }
    
        public int[] forwardPacket() {
            if (q.isEmpty()) {
                return new int[] {};
            }
            int[] packet = q.poll();
            int s = packet[0], d_ = packet[1], t = packet[2];
            vis.remove(f(s, d_, t));
            idx.merge(d_, 1, Integer::sum);
            return new int[] {s, d_, t};
        }
    
        private long f(int a, int b, int c) {
            return ((long) a << 46) | ((long) b << 29) | (long) c;
        }
    
        public int getCount(int destination, int startTime, int endTime) {
            List<Integer> ls = d.getOrDefault(destination, List.of());
            int k = idx.getOrDefault(destination, 0);
            int i = lowerBound(ls, startTime, k);
            int j = lowerBound(ls, endTime + 1, k);
            return j - i;
        }
    
        private int lowerBound(List<Integer> list, int target, int fromIndex) {
            int l = fromIndex, r = list.size();
            while (l < r) {
                int m = (l + r) >>> 1;
                if (list.get(m) < target) {
                    l = m + 1;
                } else {
                    r = m;
                }
            }
            return l;
        }
    }
    
    /**
     * Your Router object will be instantiated and called as such:
     * Router obj = new Router(memoryLimit);
     * boolean param_1 = obj.addPacket(source,destination,timestamp);
     * int[] param_2 = obj.forwardPacket();
     * int param_3 = obj.getCount(destination,startTime,endTime);
     */
    
    
  • class Router {
    private:
        int lim;
        unordered_set<long long> vis;
        deque<array<int, 3>> q;
        unordered_map<int, int> idx;
        unordered_map<int, vector<int>> d;
    
        long long f(int a, int b, int c) {
            return ((long long) a << 46) | ((long long) b << 29) | (long long) c;
        }
    
    public:
        Router(int memoryLimit) {
            lim = memoryLimit;
        }
    
        bool addPacket(int source, int destination, int timestamp) {
            long long x = f(source, destination, timestamp);
            if (vis.count(x)) {
                return false;
            }
            vis.insert(x);
            if ((int) q.size() >= lim) {
                forwardPacket();
            }
            q.push_back({source, destination, timestamp});
            d[destination].push_back(timestamp);
            return true;
        }
    
        vector<int> forwardPacket() {
            if (q.empty()) {
                return {};
            }
            auto packet = q.front();
            q.pop_front();
            int s = packet[0], d_ = packet[1], t = packet[2];
            vis.erase(f(s, d_, t));
            idx[d_]++;
            return {s, d_, t};
        }
    
        int getCount(int destination, int startTime, int endTime) {
            auto& ls = d[destination];
            int k = idx[destination];
            auto i = lower_bound(ls.begin() + k, ls.end(), startTime);
            auto j = lower_bound(ls.begin() + k, ls.end(), endTime + 1);
            return j - i;
        }
    };
    
    /**
     * Your Router object will be instantiated and called as such:
     * Router* obj = new Router(memoryLimit);
     * bool param_1 = obj->addPacket(source,destination,timestamp);
     * vector<int> param_2 = obj->forwardPacket();
     * int param_3 = obj->getCount(destination,startTime,endTime);
     */
    
    
  • class Router:
    
        def __init__(self, memoryLimit: int):
            self.lim = memoryLimit
            self.vis = set()
            self.q = deque()
            self.idx = defaultdict(int)
            self.d = defaultdict(list)
    
        def addPacket(self, source: int, destination: int, timestamp: int) -> bool:
            x = self.f(source, destination, timestamp)
            if x in self.vis:
                return False
            self.vis.add(x)
            if len(self.q) >= self.lim:
                self.forwardPacket()
            self.q.append((source, destination, timestamp))
            self.d[destination].append(timestamp)
            return True
    
        def forwardPacket(self) -> List[int]:
            if not self.q:
                return []
            s, d, t = self.q.popleft()
            self.vis.remove(self.f(s, d, t))
            self.idx[d] += 1
            return [s, d, t]
    
        def f(self, a: int, b: int, c: int) -> int:
            return a << 46 | b << 29 | c
    
        def getCount(self, destination: int, startTime: int, endTime: int) -> int:
            ls = self.d[destination]
            k = self.idx[destination]
            i = bisect_left(ls, startTime, k)
            j = bisect_left(ls, endTime + 1, k)
            return j - i
    
    
    # Your Router object will be instantiated and called as such:
    # obj = Router(memoryLimit)
    # param_1 = obj.addPacket(source,destination,timestamp)
    # param_2 = obj.forwardPacket()
    # param_3 = obj.getCount(destination,startTime,endTime)
    
    
  • type Router struct {
    	lim int
    	vis map[int64]struct{}
    	q   [][3]int
    	idx map[int]int
    	d   map[int][]int
    }
    
    func Constructor(memoryLimit int) Router {
    	return Router{
    		lim: memoryLimit,
    		vis: make(map[int64]struct{}),
    		q:   make([][3]int, 0),
    		idx: make(map[int]int),
    		d:   make(map[int][]int),
    	}
    }
    
    func (this *Router) f(a, b, c int) int64 {
    	return int64(a)<<46 | int64(b)<<29 | int64(c)
    }
    
    func (this *Router) AddPacket(source int, destination int, timestamp int) bool {
    	x := this.f(source, destination, timestamp)
    	if _, ok := this.vis[x]; ok {
    		return false
    	}
    	this.vis[x] = struct{}{}
    	if len(this.q) >= this.lim {
    		this.ForwardPacket()
    	}
    	this.q = append(this.q, [3]int{source, destination, timestamp})
    	this.d[destination] = append(this.d[destination], timestamp)
    	return true
    }
    
    func (this *Router) ForwardPacket() []int {
    	if len(this.q) == 0 {
    		return []int{}
    	}
    	packet := this.q[0]
    	this.q = this.q[1:]
    	s, d, t := packet[0], packet[1], packet[2]
    	delete(this.vis, this.f(s, d, t))
    	this.idx[d]++
    	return []int{s, d, t}
    }
    
    func (this *Router) GetCount(destination int, startTime int, endTime int) int {
    	ls := this.d[destination]
    	k := this.idx[destination]
    	i := sort.Search(len(ls)-k, func(i int) bool { return ls[i+k] >= startTime }) + k
    	j := sort.Search(len(ls)-k, func(i int) bool { return ls[i+k] >= endTime+1 }) + k
    	return j - i
    }
    
    /**
     * Your Router object will be instantiated and called as such:
     * obj := Constructor(memoryLimit)
     * param_1 := obj.AddPacket(source,destination,timestamp)
     * param_2 := obj.ForwardPacket()
     * param_3 := obj.GetCount(destination,startTime,endTime)
     */
    
    
  • class Router {
        private lim: number;
        private vis: Set<number>;
        private q: [number, number, number][];
        private idx: Map<number, number>;
        private d: Map<number, number[]>;
    
        constructor(memoryLimit: number) {
            this.lim = memoryLimit;
            this.vis = new Set();
            this.q = [];
            this.idx = new Map();
            this.d = new Map();
        }
    
        private f(a: number, b: number, c: number): number {
            return ((BigInt(a) << 46n) | (BigInt(b) << 29n) | BigInt(c)) as unknown as number;
        }
    
        addPacket(source: number, destination: number, timestamp: number): boolean {
            const x = this.f(source, destination, timestamp);
            if (this.vis.has(x)) {
                return false;
            }
            this.vis.add(x);
            if (this.q.length >= this.lim) {
                this.forwardPacket();
            }
            this.q.push([source, destination, timestamp]);
            if (!this.d.has(destination)) {
                this.d.set(destination, []);
            }
            this.d.get(destination)!.push(timestamp);
            return true;
        }
    
        forwardPacket(): number[] {
            if (this.q.length === 0) {
                return [];
            }
            const [s, d, t] = this.q.shift()!;
            this.vis.delete(this.f(s, d, t));
            this.idx.set(d, (this.idx.get(d) ?? 0) + 1);
            return [s, d, t];
        }
    
        getCount(destination: number, startTime: number, endTime: number): number {
            const ls = this.d.get(destination) ?? [];
            const k = this.idx.get(destination) ?? 0;
            const i = this.lowerBound(ls, startTime, k);
            const j = this.lowerBound(ls, endTime + 1, k);
            return j - i;
        }
    
        private lowerBound(arr: number[], target: number, from: number): number {
            let l = from,
                r = arr.length;
            while (l < r) {
                const m = Math.floor((l + r) / 2);
                if (arr[m] < target) {
                    l = m + 1;
                } else {
                    r = m;
                }
            }
            return l;
        }
    }
    
    /**
     * Your Router object will be instantiated and called as such:
     * var obj = new Router(memoryLimit)
     * var param_1 = obj.addPacket(source,destination,timestamp)
     * var param_2 = obj.forwardPacket()
     * var param_3 = obj.getCount(destination,startTime,endTime)
     */
    
    
  • use std::collections::{HashSet, HashMap, VecDeque};
    
    struct Router {
        lim: usize,
        vis: HashSet<i64>,
        q: VecDeque<(i32, i32, i32)>,
        idx: HashMap<i32, usize>,
        d: HashMap<i32, Vec<i32>>,
    }
    
    impl Router {
        fn new(memory_limit: i32) -> Self {
            Router {
                lim: memory_limit as usize,
                vis: HashSet::new(),
                q: VecDeque::new(),
                idx: HashMap::new(),
                d: HashMap::new(),
            }
        }
    
        fn f(a: i32, b: i32, c: i32) -> i64 {
            ((a as i64) << 46) | ((b as i64) << 29) | (c as i64)
        }
    
        fn add_packet(&mut self, source: i32, destination: i32, timestamp: i32) -> bool {
            let x = Self::f(source, destination, timestamp);
            if self.vis.contains(&x) {
                return false;
            }
            self.vis.insert(x);
            if self.q.len() >= self.lim {
                self.forward_packet();
            }
            self.q.push_back((source, destination, timestamp));
            self.d.entry(destination).or_default().push(timestamp);
            true
        }
    
        fn forward_packet(&mut self) -> Vec<i32> {
            if let Some((s, d, t)) = self.q.pop_front() {
                self.vis.remove(&Self::f(s, d, t));
                *self.idx.entry(d).or_insert(0) += 1;
                vec![s, d, t]
            } else {
                vec![]
            }
        }
    
        fn get_count(&self, destination: i32, start_time: i32, end_time: i32) -> i32 {
            let ls = self.d.get(&destination);
            if ls.is_none() {
                return 0;
            }
            let ls = ls.unwrap();
            let k = *self.idx.get(&destination).unwrap_or(&0);
            let i = k + ls[k..].partition_point(|&x| x < start_time);
            let j = k + ls[k..].partition_point(|&x| x < end_time + 1);
            (j - i) as i32
        }
    }
    
    

All Problems

All Solutions