<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Devesh Agarwal on Medium]]></title>
        <description><![CDATA[Stories by Devesh Agarwal on Medium]]></description>
        <link>https://medium.com/@agarwaldevesh.08?source=rss-b22df15e3d92------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*7kx6eGBDRqe2JQi3</url>
            <title>Stories by Devesh Agarwal on Medium</title>
            <link>https://medium.com/@agarwaldevesh.08?source=rss-b22df15e3d92------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 24 May 2026 02:25:28 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@agarwaldevesh.08/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Introduction to Graph Theory (for beginners)]]></title>
            <link>https://medium.com/@agarwaldevesh.08/introduction-to-graph-theory-for-beginners-ae33e754dc5e?source=rss-b22df15e3d92------2</link>
            <guid isPermaLink="false">https://medium.com/p/ae33e754dc5e</guid>
            <category><![CDATA[fb]]></category>
            <category><![CDATA[trees]]></category>
            <category><![CDATA[graph-theory]]></category>
            <category><![CDATA[bfs-and-dfs]]></category>
            <category><![CDATA[dfs]]></category>
            <dc:creator><![CDATA[Devesh Agarwal]]></dc:creator>
            <pubDate>Thu, 10 Apr 2025 11:49:01 GMT</pubDate>
            <atom:updated>2025-04-11T04:45:12.009Z</atom:updated>
            <content:encoded><![CDATA[<h3>Graph Theory Simplified: A Beginner’s Guide with Java Examples</h3><p>Unlike physical data structures like arrays, lists, stacks, and queues, graphs and trees are abstract representations of data — often used to model networks, relationships, and hierarchical structures</p><p><strong>Structure of graph:<br></strong>A graph is a combination of nodes (which contains data, similar to linked list nodes) and these nodes are connected by edges.<br>Here’s where it gets interesting — in graphs, edges can be unidirectional, bidirectional, or even weighted, depending on the use case.<br>Depending on the structure or the type of edges, there are multiple type of graphs. <br>Some types of graphs: <br>1. <strong>Directed vs Undirected Graph</strong>: It depends on whether the edges are directed or not. For example, social media follow relationships (directed) vs. mutual friendships (undirected).<br>2. <strong>Weighted vs Unweighted Graph</strong>: It depends on whether the edges are weighted or not<br>3. <strong>Cyclic vs Acyclic Graph</strong>: It depends on whether the graph contains at least one cycle (a path where the start and end node are the same).<br>4. <strong>Connected vs Disconnected Graph</strong>: There is a path between every pair of vertices (for undirected graphs)<br>5. <strong>Tree</strong> : It is most common type of graph</p><p><strong>Tree vs Graph:<br></strong>A tree is a special kind of graph which is connected and does not contain any cycle. (as simple as that). <br>Additionally, a tree having n nodes will have n-1 edges. <strong>Binary Trees</strong>, <strong>N-ary Trees</strong>, and <strong>Trie structures</strong> are all specialised tree-based graphs.</p><p><strong>Representation of graph:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/606/1*3yHUON4gZLk-iokTqfaDgw.png" /></figure><p>Now, the question is how to represent the above structure in our code?<br>Do we create a completely new data structure for this? Actually, no!</p><p>We represent graphs using 2D array lists, which is termed as adjacency list when representing a graph.</p><p>So basically, if there are N number of nodes in a graph connected by M number of edges, for each node we will store a list of nodes, directly connected to that node. Now if the edges are weighted, we will store the pair of weight and the node reachable from that weighted edge.<br>Below is the function for initialising and representing a graph using adjacency list in Java programming language.</p><pre>List&lt;Integer&gt; adj[] = new ArrayList[100000]; // global variable for storing graph<br><br>// function takes number of nodes as input and the list of edges.<br>// for this ex, I have considered an bidirection and unweighted graph<br>public void initialiseGraph(int nodes, int[][] edges) {<br>  for(int i=1; i&lt;=nodes; i++)<br>  adj[i] = new ArrayList&lt;&gt;();<br>  for(int[] e : edges) {<br>    adj[e[0]].add(e[1]);<br>    adj[e[1]].add(e[0]);<br>  }<br>}</pre><p>Now, when we understood the representation of the graph, we have to understand how to use this representation to traverse a graph.</p><p><strong>Traversals of graph:<br></strong>There are 2 different algorithms for traversing a graph:</p><p><strong>Breadth-First Search</strong><br>It is a graph traversal algorithm that explores nodes level by level, starting from a given source node. It uses a queue data structure to keep track of the nodes to visit next, ensuring that all immediate neighbours of a node are explored before moving deeper into the graph.<br>In other words, BFS visits all the nodes at the current level before moving on to nodes at the next level, making it ideal for shortest path problems (in unweighted graphs) and layer-wise exploration.</p><p><strong>Data Structure Used</strong>: Queue (FIFO)<br><strong>Time Complexity</strong>: O(V + E) where V is vertices and E is edges<br><strong>Space Complexity</strong>: O(V) due to the visited array and queue</p><pre>public void bfs(int source) {<br>    Queue&lt;Integer&gt; q = new LinkedList&lt;&gt;();<br>    q.add(source);<br>    boolean[] vis = new boolean[100001];<br>    vis[source] = true;<br>    while(!q.isEmpty()) {<br>        int node = q.poll();<br>        System.out.print(node + &quot; &quot;);<br>        // for each node, we will add all its unvisited neighbours in the queue<br>        for(Integer it : adj[node]) {<br>            if(!vis[it])<br>                q.add(it);<br>        }<br>    }<br>}</pre><p><strong>Depth First Search<br></strong>It is a graph traversal algorithm that explores as far down a branch as possible before backtracking. It uses a stack (either explicitly or via recursion) to remember nodes to return to when it hits a dead end or already visited node.</p><p>DFS dives deep into a single path and only when that path is fully explored does it move to the next available branch. This makes it ideal for exploring all possible paths, detecting cycles, and performing topological sorting.</p><p><strong>Data Structure Used:</strong> Stack (often implemented using recursion)<br><strong>Time Complexity:</strong> O(V + E) where V is vertices and E is edges<br><strong>Space Complexity:</strong> O(V) due to the recursion stack or explicit stack</p><pre>public void dfs(int source) {<br>    boolean[] vis = new boolean[100001];<br>    dfsUtil(source, vis);<br>}<br><br>public void dfsUtil(int node, boolean[] vis) {<br>    vis[node] = true;<br>    System.out.print(node + &quot; &quot;);<br>    for(Integer it : adj[node]) {<br>        if(!vis[it])<br>            dfsUtil(it, vis);<br>    }<br>}</pre><p>Some common and important problems for praciticng graph<br>1. <a href="https://leetcode.com/problems/course-schedule/description/">Course schedule</a><br>2. <a href="https://leetcode.com/problems/rotting-oranges/description/">Rotten oranges</a><br>3. <a href="https://leetcode.com/problems/binary-tree-level-order-traversal/description/">Level order traversal of binary tree</a><br>4. <a href="https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/description/">Zigzag traversal of binary tree</a></p><p>Do like it and follow me on medium if this blog was helpful. 😊</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ae33e754dc5e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[System Design: Code Deployment System (HLD)]]></title>
            <link>https://medium.com/@agarwaldevesh.08/system-design-code-deployment-system-hld-8db9763ad833?source=rss-b22df15e3d92------2</link>
            <guid isPermaLink="false">https://medium.com/p/8db9763ad833</guid>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[system-design-interview]]></category>
            <dc:creator><![CDATA[Devesh Agarwal]]></dc:creator>
            <pubDate>Mon, 23 Dec 2024 17:13:20 GMT</pubDate>
            <atom:updated>2025-04-24T10:06:45.538Z</atom:updated>
            <content:encoded><![CDATA[<p>In this article, I will talk about the high level system design of a code deployment system. Refer to the functional requirements for better understanding of the problem statement.</p><h3>Requirements and Goals of the System:</h3><p><strong>Functional Requirements</strong></p><ol><li>Build and deploy the code</li><li>Deployment time should be quick and deployment takes place on global servers</li><li>Rollback to previous version if some bug is found after deployment</li><li>Store audit of previous builds and deployments</li></ol><p><strong>Non Functional requirements:</strong></p><ol><li>Scalable and highly available: System should be scalable to handle larger deployments and it should be available at all times.</li><li><strong>Eventual consistency:</strong> We will choose eventual consistency over strong consistency bcoz we need our system to be highly available at all times. So it is ok if the code is deployed on some servers of a region a little bit late then some other regions</li><li>Reliable</li></ol><h3>Capacity Estimation</h3><ol><li>The system should be extremely fast with a max time of 30 mins for the entire process of build and deployment.</li><li>Deployment will take place in multiple regions and each region will have lot of machines.</li><li>Due to large codebases the build files can take upto 10 GB space.</li></ol><h3>High Level System Design</h3><p>Whenever, some code is pushed in the master branch, our system should take this latest code and start the build and deployment process for the same.<br>We will follow a <strong>microservice architecture</strong> with independent services responsible for building and deploying the code.<br>So, when the code is pushed in master, the builder service needs to be notified about it and then it should also be provided with the latest commit id from the master branch.</p><p>For this, we would be using a <strong>queuing mechanism, probably Kafka</strong>. Like, we can add the commit id, commit timestamp in the Kafka topic, and our builder service will be reading from this Kafka topic. <br>For instructions to build the code, we can use a mongoDb which will store documents like below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*10FaaqcVUoSKIFGuSSwXbw.png" /></figure><p>We need these instructions bcoz in microservice architecture, different services can be written in different programming languages. The set of commands to get the build file will be different for each of them. Additionally, we also need to store the information about the build in a DB having below structure. It’s structure could be like the below schema.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oq1fZ9eBRm5Oa5xOq2zPng.png" /><figcaption>DB Schema to store build information</figcaption></figure><p>Since the build file can be huge, we will use some kind of <strong>blob storage, probably S3</strong> for storing the build files. Now using this build file, we will create a docker image. Our eventual plan would be that the deployment service will take this <strong>docker image</strong> and deploy in on the global servers.</p><p><strong>Fallback mechanism:</strong><br>For handling the condition when the builder service crashes while building, we will be monitoring the heart beats of the builder service regularly, and if it goes down, we will keep track of the time stamp at which it went down, so that when it comes up again, it will pick the commits from that time stamp only and start the build process again.</p><p><strong>DEPLOYMENT SERVICE:<br></strong>After the docker image is created, we need to notify our deployment service to deploy the image. Again we will use a queuing mechanism (probably Kafka) and push this docker image id along with the commit id in a seperate Kafka topic. The deployment service will take this docker image from the id in the Kafka topic and proceed with the deployment.<br>Now there can be 1000s of <strong>EC2 instances</strong> running at different location, but our build file needs to run on 3–5 instances only. (Its like having multiple pods of a service, but the count is still limited depending on the load).</p><p>We need to consider <strong>metrics like CPU and memory usage, throughput </strong>to decide on which EC2 instances, our service should be deployed.<br>We could also provide a monitoring service, which will show the health and status of the services deployed using kubernetes dashboard.</p><p><strong>Rollback Mechanism:</strong></p><p>If rollback is triggered at a certain timestamp, we will pick the commit Id and the docker image on the basis of timestamp, and deploy that docker image on our servers for efficient rollback.</p><p>Additionally, if any other process fails during build or deployment, we need to notify the user about the failure.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QQVZIsiX6RD2YA8dzIFYVA.png" /><figcaption>Final Design</figcaption></figure><p>Thanks for reading the blog. I hope it was somewhat helpful. 😊</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8db9763ad833" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Escape fire matrix : Intuit coding problem]]></title>
            <link>https://medium.com/@agarwaldevesh.08/escape-fire-matrix-intuit-coding-problem-388e77d73333?source=rss-b22df15e3d92------2</link>
            <guid isPermaLink="false">https://medium.com/p/388e77d73333</guid>
            <category><![CDATA[graph-theory]]></category>
            <category><![CDATA[c-programming]]></category>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[interview]]></category>
            <category><![CDATA[breadth-first-search]]></category>
            <dc:creator><![CDATA[Devesh Agarwal]]></dc:creator>
            <pubDate>Sat, 20 Jul 2024 18:01:01 GMT</pubDate>
            <atom:updated>2024-07-20T18:01:01.016Z</atom:updated>
            <content:encoded><![CDATA[<h3>Escape fire matrix : Intuit coding problem</h3><h3>Problem statement:</h3><p>There is a matrix of size <em>m*n</em>. Fire starts at some point <em>(fx, fy)</em>. John is standing at point <em>(x1, y1)</em> and wants to reach <em>(x2, y2) </em>which is the escape cell for the matrix. John moves 1 step every second second either horizontally or vertically. Additionally, fire spreads from the initial point with a speed of 1 step per second along the x and y axes of initial starting point. Can you help John to identify whether he can reach the destination safely.</p><p><strong>Constraints:</strong><br><em>1 &lt;= n,m &lt;= 1000</em></p><p><strong>Sample Input 1:</strong><br>6 6<br>2 3 1 1 0 1<br><strong>Output:</strong><br>Yes</p><p><strong>Sample Input 2:</strong><br>6 6<br>2 3 1 1 4 4<br><strong>Output:</strong><br>No</p><p><strong>Solution:</strong><br>We need to calculate the time at which the fire will reach any cell. Let’s say that <em>fire[i][j]</em> be such time. Then we need to perform a breadth first search from the starting location of John and check if there is any possible path for him to reach the destination.</p><p><strong>C++ solution</strong></p><pre>#include &lt;bits/stdc++.h&gt; <br>using namespace std;<br><br>#define pii pair&lt;int, int&gt;<br>int dir[]={-1, 0, 1, 0, -1};<br><br>bool solve() {<br>    int n, m;<br>    cin &gt;&gt; n &gt;&gt; m;<br>    int fx, fy, x1, y1, x2, y2;<br>    cin &gt;&gt; fx &gt;&gt; fy &gt;&gt; x1 &gt;&gt; y1 &gt;&gt; x2 &gt;&gt; y2;<br>    queue&lt;pii&gt; q;<br>    q.push({fx, fy});<br>    vector&lt;vector&lt;int&gt;&gt; fire(n, vector&lt;int&gt; (m, INT_MAX));<br>    // to store the time in which fire will reach cell[i][j]<br>    fire[fx][fy]=0;<br>    while(!q.empty()) {<br>        int sz = q.size();<br>        while(sz--) {<br>            pii p = q.front();<br>            q.pop();<br>            int x=p.first, y=p.second;<br>            for(int i=0; i&lt;4; i++) {<br>                int dx=x+dir[i], dy=y+dir[i+1];<br>                if(dx&gt;=0 &amp;&amp; dy&gt;=0 &amp;&amp; dx&lt;n &amp;&amp; dy&lt;m) {<br>                    if(fire[dx][dy]==INT_MAX) {<br>                        fire[dx][dy]=fire[x][y]+1;<br>                        q.push({dx, dy});<br>                    }<br>                }<br>            }<br>        }<br>    }<br>    q.push({x1, y1});<br>    if(x1==x2 &amp;&amp; y1==y2)<br>        return true;<br>    int dur=0;<br>    while(!q.empty()) {<br>        int sz = q.size();<br>        dur++;<br>        while(sz--) {<br>            pii p = q.front();<br>            q.pop();<br>            int x=p.first, y=p.second;<br>            for(int i=0; i&lt;4; i++) {<br>                int dx=x+dir[i], dy=y+dir[i+1];<br>                if(dx&gt;=0 &amp;&amp; dy&gt;=0 &amp;&amp; dx&lt;n &amp;&amp; dy&lt;m) {<br>                    if(fire[dx][dy] &lt;= dur)<br>                        continue;<br>// if we reach destination cell before fire reaches it then solution exists<br>                    if(dx==x2 &amp;&amp; dy==y2) <br>                        return true;<br>                    q.push({dx, dy});<br>                }<br>            }<br>        }<br>    }<br>    return false;<br>}<br><br>int main() {<br>    if(solve()) {<br>        cout &lt;&lt; &quot;YES\n&quot;;<br>    }<br>    else {<br>        cout &lt;&lt; &quot;NO\n&quot;;<br>    }<br>}</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=388e77d73333" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rate Limiter — System Design]]></title>
            <link>https://medium.com/@agarwaldevesh.08/rate-limiter-system-design-dd95cdc53d1c?source=rss-b22df15e3d92------2</link>
            <guid isPermaLink="false">https://medium.com/p/dd95cdc53d1c</guid>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[rate-limiting]]></category>
            <category><![CDATA[api]]></category>
            <dc:creator><![CDATA[Devesh Agarwal]]></dc:creator>
            <pubDate>Sun, 05 May 2024 13:34:59 GMT</pubDate>
            <atom:updated>2024-05-05T13:34:59.836Z</atom:updated>
            <content:encoded><![CDATA[<h3>Rate Limiter — System Design</h3><p>A <strong>Rate Limiter</strong> limits the number of client requests allowed to be sent to the server over a specified period. If the API request count exceeds the threshold defined by the rate limiter, all the excess calls are blocked.</p><p>Let’s look at some of the benefits of rate limiter:</p><ol><li>A rate limiter prevents DoS attacks, intentional or unintentional, by blocking the excess calls.</li><li>Reduces cost where the system is using a 3rd-party API service and is charged on a per-call-basis.</li><li>To reduce server load, a rate limiter is used to filter out excess requests caused by bots or users’ misbehaviour.</li></ol><p><strong>Design:</strong></p><p>Before starting the design, a critical question is that where should the rate limiter be placed — on the client side or the server side ?</p><p>Client-side rate limiting can be used in some scenarios, but it has limitations:</p><ol><li><strong>Easy to Bypass:</strong> Malicious actors can tamper with client-side code to bypass the rate limit.</li><li><strong>Inconsistent Enforcement:</strong> If each client implements its own rate limiting, enforcement may not be consistent across all users.</li></ol><p>Server Side:</p><ol><li><strong>Security:</strong> Server-side rate limiting ensures enforcement across all clients. A malicious client cannot bypass the limit by simply modifying client-side code.</li><li><strong>Centralised Control:</strong> The server has complete control over the rate limits, allowing for easier configuration and management</li><li><strong>Scalability:</strong> Server-side rate limiting scales better as the system grows, as the rate limiting logic is applied at a central point.</li></ol><p>Overall, server-side rate limiting offers a more secure, centralised, and scalable approach for protecting your system from abuse.</p><p>There are plenty of algorithms for rate limiting: we will look at some of them including a <strong>Token bucket</strong>,<strong> Leaky bucket</strong>,<strong> Sliding window counter</strong>, etc.</p><p><strong>Token Bucket Algorithm</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/926/1*bj-6LsDLXcMJ36HL35VPMA.png" /><figcaption>Visual representation of token bucket algorithm</figcaption></figure><p>The token bucket algorithm is based on an analogy of a fixed capacity bucket into which tokens, normally representing a unit of bytes or a single packet of predetermined size, are added at a fixed rate. <br>This algorithm has a centralised bucket host where you take tokens on each request, and slowly drip more tokens into the bucket. If the bucket is empty, reject the request.</p><pre>public class TokenBucket {<br><br>  // Using nanoseconds as the unit for rate<br>  private final int capacity; // Maximum number of tokens in the bucket<br>  private final long refillRateNanos; // Rate at which tokens are refilled (nanoseconds)<br>  private long lastRefillTimeNanos; // Time of the last refill (nanoseconds)<br>  private int availableTokens; // Current number of tokens in the bucket<br><br>  public TokenBucket(int capacity, long refillRate) {<br>    this.capacity = capacity;<br>    this.refillRateNanos = refillRate * 1_000_000_000L; // Convert refill rate to nanoseconds<br>    this.lastRefillTimeNanos = System.nanoTime();<br>    this.availableTokens = capacity;<br>  }<br><br>  public synchronized boolean tryConsume() {<br>    refillTokens();<br>    return availableTokens-- &gt; 0;<br>  }<br><br>  private void refillTokens() {<br>    long currentTimeNanos = System.nanoTime();<br>    long elapsedNanos = currentTimeNanos - lastRefillTimeNanos;<br>    long newTokens = (elapsedNanos / refillRateNanos) * capacity;<br>    availableTokens = Math.min(capacity, availableTokens + (int) newTokens);<br>    lastRefillTimeNanos = currentTimeNanos;<br>  }<br><br>  public static void main() {<br><br>    TokenBucket bucket = new TokenBucket(10, 1); // 10 requests per second<br>    <br>    if (bucket.tryConsume()) {<br>      // Allow the request<br>    } else {<br>      // Reject the request (rate limit exceeded)<br>    }<br>  }<br>}</pre><p>Above is the pseudo code for token bucket algorithm.</p><p><strong>Sliding Window Algorithm</strong></p><p>The Sliding Window Algorithm is a time-based method used to track and control the rate at which requests or operations can be made within a specific time window. It’s a dynamic system that adapts to changing traffic patterns, making it an effective tool for rate limiting in various applications.</p><h3>Visualizing sliding window</h3><p>Every time we get a request, we make a decision to either serve it or not; hence we check the number_of_requests made in last time_window_sec seconds. So this process of checking for a fixed window of time_window_sec seconds on every request, makes this approach a sliding window where the fixed window of size time_window_sec seconds is moving forward with each request.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xem0VJr6c258Xk9AZVzFBA.png" /></figure><pre>public class SlidingWindowRateLimiter {<br><br>  private final long windowSizeNanos; // Window size in nanoseconds<br>  private final int maxRequests; // Maximum allowed requests within the window<br>  private final Queue&lt;Long&gt; timestamps; // Queue to store request timestamps<br><br>  public SlidingWindowRateLimiter(long windowSizeMillis, int maxRequests) {<br>    this.windowSizeNanos = windowSizeMillis * 1_000_000_000L;<br>    this.maxRequests = maxRequests;<br>    this.timestamps = new LinkedList&lt;&gt;();<br>  }<br><br>  public synchronized boolean tryAcquire() {<br>    cleanupWindow();<br>    if (timestamps.size() &lt; maxRequests) {<br>      timestamps.add(System.nanoTime());<br>      return true;<br>    } else {<br>      return false;<br>    }<br>  }<br><br>  private void cleanupWindow() {<br>    long currentTimeNanos = System.nanoTime();<br>    while (!timestamps.isEmpty() &amp;&amp; currentTimeNanos - timestamps.peek() &gt; windowSizeNanos) {<br>      timestamps.poll();<br>    }<br>  }<br><br>  public static void main() {<br>    SlidingWindowRateLimiter limiter = new SlidingWindowRateLimiter(1000, 5); // 1 second window, 5 requests allowed<br>    if (limiter.tryAcquire()) {<br>      // Process request<br>    } else {<br>      // Reject request (rate limit exceeded)<br>    }<br>  }<br>}</pre><p>Above is the pseudo code for sliding window algorithm.</p><p>Now, let’s look at the high level design of a system with rate limiter in place.</p><p>Every time the client make a request to the server, the request goes through the rate limiter, which is linked to a rule engine. This component focuses on defining and evaluating the rules for applying rate limiting. Ex. if a lot of requests are coming from a same IP, then that IP can be blocked. Also, for some websites there is a spike in traffic during certain times of the year, and hence the rate limit for those times has to be increased, which is made configurable through the rule engine.<br>Using the response of the rule engine and the rate limiter, it is decided whether the request will be denied or it will be a success.<br>Below is the HLD for a system using rate limiter</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LGtBYbgzv3GwQbHhi1bjeQ.png" /></figure><p>Some of the real life applications of rate limiter:</p><ol><li>In a banking system you may request OTP (One Time Password) once every 5 minutes.</li><li>In a social media platform, a user maybe allowed to post maximum 5 posts per minute</li><li>You can register a new user from same IP maximum 5 times per day. This is case where we want to prevent bot/sock-puppet accounts</li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dd95cdc53d1c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Finding all edges lying in any of the shortest paths (Dijkstra’s algorithm)]]></title>
            <link>https://medium.com/@agarwaldevesh.08/finding-all-edges-lying-in-any-of-the-shortest-paths-dijkstras-algorithm-fc25dd4008e9?source=rss-b22df15e3d92------2</link>
            <guid isPermaLink="false">https://medium.com/p/fc25dd4008e9</guid>
            <category><![CDATA[graph]]></category>
            <category><![CDATA[dijkstra]]></category>
            <category><![CDATA[problem-solving]]></category>
            <category><![CDATA[leetcode]]></category>
            <dc:creator><![CDATA[Devesh Agarwal]]></dc:creator>
            <pubDate>Sun, 28 Apr 2024 09:26:57 GMT</pubDate>
            <atom:updated>2024-04-28T09:26:57.742Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Problem Statement:</strong></p><p>You are given a undirected and weighted graph of <em>n</em> nodes numbered from <em>0</em> to <em>n-1</em>. The graph consists of m edges represented by a 2D array <em>edges</em>, where <em>edges[i] = [u, v, w]</em> indicates that there is an edge between nodes <em>u</em> and <em>v</em> with weight <em>w</em>. <br>Consider all the shortest paths from node 0 to node <em>n-1</em> in the graph. You need to find a <strong>boolean</strong> array answer where <em>answer[i]</em> is true if the edge <em>edges[i]</em> is part of <strong>at least</strong> one shortest path. Otherwise, <em>answer[i]</em> is false.</p><p>Return the array <em>answer</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/490/1*4ZYX5E-Ua1d0RsDqmHI2SQ.png" /></figure><p>Consider the above graph as example:</p><p><strong>Input:</strong> <br>n = 6, edges = [[0,1,4],[0,2,1],[1,3,2],[1,4,3],[1,5,1],[2,3,1],[3,5,3],[4,5,2]]</p><p><strong>Output:</strong> <br>[true, true, true, false, true, true, true, false]</p><p><strong>Explanation:</strong><br>There are 3 shortest paths from node 0 to n-1 in the above graph.</p><p>Path <em>0 -&gt; 1 -&gt; 5 </em>: The sum of weights is 4 + 1 = 5<br>Path <em>0 -&gt; 2 -&gt; 3 -&gt; 5 </em>: The sum of weights is 1 + 1 + 3 = 5<br>Path <em>0 -&gt; 2 -&gt; 3 -&gt; 1 -&gt; 5 </em>: The sum of weights is 1 + 1 + 2 + 1 = 5</p><p><strong>Solution:</strong></p><p>One of the solutions can be to find all the shortest paths from 0 to n-1 and then take the union of all the edges lying in any of the shortest paths.<br>However, in a graph of n nodes, the time complexity of this solution will be more than <em>n*O(nlogn) </em>[nlogn for each shortest path if we use Dijkstra, and there can be a lot of shortest paths] , which a not a feasible solution if <em>n ≤ 100000.</em></p><p>So, in order to optimise this, we need to first figure out the key condition using which we can definitely say if an edge will be a part of any shortest path or not. <br>Let’s say we have an array <em>disFromSource[i] </em>= shortest distance from source node to any other node and another array <em>disFromDest[i] </em>= shortest distance from destination to any other node. So, for any edge <em>(u, v, w), </em>it will the part of any shortest path if :<br><em>disFromSource[u]+disFromDest[v]+w = disFromSource[n-1]</em></p><p>To calculate the two required arrays, we need to run Dijkstra algorithm twice, once considering node 0 as source and then considering node n-1 as source.</p><p>Java code snippet</p><pre>static ArrayList&lt;int[]&gt; adj[];<br><br>static long[] Dijkstra(int src, int n){<br>    long dis[] = new long[n];<br>    PriorityQueue&lt;long[]&gt; pq = new PriorityQueue&lt;&gt;(new Comparator&lt;&gt;() {<br>        public int compare(long a[], long b[]) {<br>            return a[1]&gt;b[1] ? 1 : -1;<br>        }<br>    });<br>    Arrays.fill(dis, Integer.MAX_VALUE);<br><br>    dis[src] = 0;<br>    pq.add(new long[]{src, 0});<br><br>    while(pq.size()!=0){<br>        long curr[] = pq.remove();<br>        int u = (int)curr[0];<br>        if(curr[1] &gt; dis[u])<br>            continue;<br>        for(int[] x : adj[u]){<br>            if(dis[x[0]] &gt; dis[u] + x[1]){<br>                dis[x[0]] = dis[u]+x[1];<br>                pq.add(new long[]{x[0], dis[x[0]]});<br>            }<br>        }<br>    }<br>    return dis;<br>}<br><br>public boolean[] findAnswer(int n, int[][] edges) {<br>    adj = new ArrayList[n];<br>    int m = edges.length;<br><br>    for(int i=0; i&lt;n; i++)<br>        adj[i] = new ArrayList&lt;&gt;();<br>    for(int[] e : edges) {<br>        adj[e[0]].add(new int[]{e[1], e[2]});<br>        adj[e[1]].add(new int[]{e[0], e[2]});<br>    }<br><br>    long disFromSource[] = Dijkstra(0, n);<br>    long disFromDest[] = Dijkstra(n-1, n);<br><br>    boolean[] ans = new boolean[m];<br>    long min = disFromSource[n-1];<br>    for(int i=0; i&lt;m; i++) {<br>        int u=edges[i][0], v=edges[i][1], w=edges[i][2];<br>        <br>        if((long)w + disFromSource[u]+disFromDest[v] == min || (long)w+disFromDest[u]+disFromSource[v]==min)<br>            ans[i] = true;<br>        else<br>            ans[i] = false;<br>    }<br>    return ans;<br>}</pre><p>Practice link for the problem: <br><a href="https://leetcode.com/problems/find-edges-in-shortest-paths/">https://leetcode.com/problems/find-edges-in-shortest-paths/</a></p><p>Thanks for reading !!<br>Please share feedback if you have any.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fc25dd4008e9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[File System (Composite Design Pattern)]]></title>
            <link>https://medium.com/@agarwaldevesh.08/file-system-composite-design-pattern-9f877ac5babb?source=rss-b22df15e3d92------2</link>
            <guid isPermaLink="false">https://medium.com/p/9f877ac5babb</guid>
            <category><![CDATA[filesystem]]></category>
            <category><![CDATA[system-design-concepts]]></category>
            <category><![CDATA[composite-design-pattern]]></category>
            <dc:creator><![CDATA[Devesh Agarwal]]></dc:creator>
            <pubDate>Sun, 21 Apr 2024 14:53:34 GMT</pubDate>
            <atom:updated>2024-04-22T08:37:03.101Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Composite</strong> is a structural design pattern that lets you compose objects into tree structures and then work with these structures as if they were individual objects. When we need to create a structure in a way that the objects in the structure has to be treated the same way, we can apply composite design pattern.</p><p>Composite Pattern consists of following objects.</p><ol><li><strong>Base Component</strong> — Base component is the interface for all objects in the composition. It can be an interface or an abstract class with some methods common to all the objects.</li><li><strong>Leaf</strong> — Defines the behaviour for the elements in the composition. It is the building block for the composition and implements base component. It doesn’t have references to other Components.</li><li><strong>Composite</strong> — It consists of leaf elements and implements the operations in base component.</li></ol><p>The most common application for this design pattern is a file system. In a file system, a folder can have a list of files + subfolders inside it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yDIsAUFrxqhoB_nWgiZjrQ.png" /></figure><p>Base component (Interface)</p><pre><br>public interface FileSystem {<br>    public void ls();<br>}<br></pre><p>File class (leaf component in the design pattern)</p><pre>public class File implements FileSystem {<br>    String fileName;<br><br>    public File(String name) {<br>        this.fileName = name;<br>    }<br><br>    @Override<br>    public void ls() {<br>        System.out.println(&quot;file name &quot; + fileName);<br>    }<br>}</pre><p>Directory (composite Object)</p><pre>public class Directory implements FileSystem {<br><br>    String directoryName;<br>    List&lt;FileSystem&gt; fileSystemList;<br><br>    public Directory(String name) {<br>        this.directoryName = name;<br>        fileSystemList = new ArrayList&lt;&gt;();<br>    }<br><br>    public void add(FileSystem fileSystemObj) {<br>        fileSystemList.add(fileSystemObj);<br>    }<br><br>    @Override<br>    public void ls() {<br>        System.out.println(&quot;Executing ls for directory name &quot; + directoryName);<br>        for(FileSystem fileSystemObj : fileSystemList) {<br>            fileSystemObj.ls();<br>        }<br>    }<br>}</pre><p>Thanks for reading!!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9f877ac5babb" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>