<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Messaoud Wael</title>
    <description>The latest articles on Forem by Messaoud Wael (@messaoud_wael_dd4b26a0d29).</description>
    <link>https://forem.com/messaoud_wael_dd4b26a0d29</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3724930%2Fa388b0d0-2f63-46ad-a664-d841cfe194df.jpg</url>
      <title>Forem: Messaoud Wael</title>
      <link>https://forem.com/messaoud_wael_dd4b26a0d29</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/messaoud_wael_dd4b26a0d29"/>
    <language>en</language>
    <item>
      <title>Master Coding Interviews : Part 3 ( Fast &amp; Slow Pointers Pattern )</title>
      <dc:creator>Messaoud Wael</dc:creator>
      <pubDate>Tue, 31 Mar 2026 11:57:59 +0000</pubDate>
      <link>https://forem.com/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-3-fast-slow-pointers-pattern--3fae</link>
      <guid>https://forem.com/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-3-fast-slow-pointers-pattern--3fae</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-1-sliding-window-pattern--35pk"&gt;Part 1&lt;/a&gt; we saw how a sliding window collapses a nested loop into a single pass over an array. In &lt;a href="https://dev.to/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-2-two-pointers-pattern"&gt;Part 2&lt;/a&gt; we used two pointers moving toward each other — or side by side — to restructure and search sorted arrays in O(n) time and O(1) space.&lt;/p&gt;

&lt;p&gt;Today's pattern shares that same O(1) space philosophy, but it lives in a different world: &lt;strong&gt;linked lists&lt;/strong&gt;. Meet the &lt;strong&gt;Fast &amp;amp; Slow Pointers&lt;/strong&gt; pattern — also known as Floyd's Cycle Detection Algorithm.&lt;/p&gt;




&lt;h3&gt;
  
  
  What is the Fast &amp;amp; Slow Pointers Pattern?
&lt;/h3&gt;

&lt;p&gt;The concept comes from a simple real-world intuition: imagine two runners on a circular track. One runs twice as fast as the other. If the track loops back on itself, the fast runner will eventually lap the slower one — they are guaranteed to meet. If the track is a straight line with a finish line, the fast runner simply gets there first and stops.&lt;/p&gt;

&lt;p&gt;We apply exactly this logic to linked lists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;slow pointer&lt;/strong&gt; advances &lt;strong&gt;one node&lt;/strong&gt; at a time&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;fast pointer&lt;/strong&gt; advances &lt;strong&gt;two nodes&lt;/strong&gt; at a time&lt;/li&gt;
&lt;li&gt;If the list has a cycle, they will eventually collide inside it&lt;/li&gt;
&lt;li&gt;If the list has no cycle, the fast pointer hits the end (&lt;code&gt;null&lt;/code&gt;) and we stop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern is remarkably versatile: it detects cycles, finds the middle of a list, and even identifies the &lt;em&gt;entry point&lt;/em&gt; of a cycle — all without any extra data structures.&lt;/p&gt;




&lt;h3&gt;
  
  
  Problem 1 — Linked List Cycle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Given the &lt;code&gt;head&lt;/code&gt; of a singly linked list, determine if the linked list has a cycle in it or not. Return &lt;code&gt;True&lt;/code&gt; if there is a cycle, &lt;code&gt;False&lt;/code&gt; otherwise.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;head = [3, 2, 0, -4]&lt;/code&gt; where the tail connects back to the node at index 1&lt;/li&gt;
&lt;li&gt;Output: &lt;code&gt;True&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most natural solution that comes to mind is to keep track of every node we visit using a hash set. If we ever encounter a node we've seen before, we know there's a cycle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hasCycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;   &lt;span class="c1"&gt;# We've seen this node before — cycle detected
&lt;/span&gt;            &lt;span class="n"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;  &lt;span class="c1"&gt;# Reached the end of the list — no cycle
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution works correctly, but it comes with a cost we can't ignore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Space complexity : O(n)&lt;/strong&gt; : We store a reference to every visited node in the hash set — for a linked list with a million nodes, that's a million references sitting in memory.&lt;/li&gt;
&lt;li&gt;In memory-constrained environments — embedded systems, low-resource servers, or simply very large linked lists — allocating that extra data structure is not always acceptable.&lt;/li&gt;
&lt;li&gt;The problem itself hints at a better path: can you solve it using &lt;strong&gt;O(1) memory&lt;/strong&gt; ?&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Optimization through the Fast &amp;amp; Slow Pointers Pattern
&lt;/h3&gt;

&lt;p&gt;Here's where Floyd's algorithm shines. We replace the hash set entirely with just two pointers — and get O(1) space as a result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hasCycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;   &lt;span class="c1"&gt;# Tortoise: moves one step at a time
&lt;/span&gt;        &lt;span class="n"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;   &lt;span class="c1"&gt;# Hare: moves two steps at a time
&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;fast&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;          &lt;span class="c1"&gt;# Tortoise takes one step
&lt;/span&gt;            &lt;span class="n"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;     &lt;span class="c1"&gt;# Hare takes two steps
&lt;/span&gt;
            &lt;span class="c1"&gt;# If the pointers meet, the hare has lapped the tortoise
&lt;/span&gt;            &lt;span class="c1"&gt;# — a cycle exists
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

        &lt;span class="c1"&gt;# Fast pointer reached the end of the list — no cycle
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Time complexity : O(n)&lt;/strong&gt; — in the worst case, the fast pointer traverses the list once.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Space complexity : O(1)&lt;/strong&gt; — two pointers, no auxiliary data structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does it work ?&lt;/strong&gt; If a cycle exists, the fast pointer enters it and begins "lapping" the slow pointer. Each iteration, the gap between them shrinks by exactly one step. Since the gap is finite and decreases by one per iteration, they are mathematically guaranteed to meet. If there is no cycle, the fast pointer reaches &lt;code&gt;null&lt;/code&gt; and the loop exits cleanly.&lt;/p&gt;


&lt;h3&gt;
  
  
  Problem 2 — Middle of the Linked List
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Given the &lt;code&gt;head&lt;/code&gt; of a singly linked list, return the &lt;strong&gt;middle node&lt;/strong&gt; of the linked list. If there are two middle nodes, return the &lt;strong&gt;second&lt;/strong&gt; middle node.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input: &lt;code&gt;head = [1, 2, 3, 4, 5]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Output: Node with value &lt;code&gt;3&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The straightforward solution is to count all nodes in a first pass, then walk to the midpoint in a second pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;middleNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;

        &lt;span class="c1"&gt;# First pass: count all nodes
&lt;/span&gt;        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;

        &lt;span class="c1"&gt;# Second pass: walk to the middle
&lt;/span&gt;        &lt;span class="n"&gt;middle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;middle&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is perfectly correct, and it does run in O(n) time — but it makes &lt;strong&gt;two full passes&lt;/strong&gt; over the list and requires you to know the total length before you can find the middle. Can we find the middle in a single pass, without knowing the length upfront ?&lt;/p&gt;




&lt;h3&gt;
  
  
  Optimization: Finding the Middle in One Pass
&lt;/h3&gt;

&lt;p&gt;This is where the Fast &amp;amp; Slow Pointers pattern reveals a second superpower. Since the fast pointer moves at twice the speed of the slow pointer, by the time the fast pointer reaches the end of the list, the slow pointer will have traveled exactly half the distance — landing precisely at the middle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;middleNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;   &lt;span class="c1"&gt;# Will reach the middle when fast reaches the end
&lt;/span&gt;        &lt;span class="n"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;   &lt;span class="c1"&gt;# Moves twice as fast as slow
&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;fast&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;          &lt;span class="c1"&gt;# One step
&lt;/span&gt;            &lt;span class="n"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;     &lt;span class="c1"&gt;# Two steps
&lt;/span&gt;
        &lt;span class="c1"&gt;# When fast is at the end, slow is at the middle
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;slow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Time complexity : O(n)&lt;/strong&gt; — a single pass through the list.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Space complexity : O(1)&lt;/strong&gt; — no extra memory allocated.&lt;/p&gt;

&lt;p&gt;The two-pass approach and this one-pass approach share the same time complexity on paper, but the single-pass version is cleaner and more elegant — and it demonstrates a deep understanding of the pattern that interviewers notice.&lt;/p&gt;




&lt;h3&gt;
  
  
  When to use this pattern
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;When dealing with &lt;strong&gt;linked lists&lt;/strong&gt; where you need to detect or reason about cycles&lt;/li&gt;
&lt;li&gt;When you need to find the &lt;strong&gt;middle of a linked list&lt;/strong&gt; in a single pass&lt;/li&gt;
&lt;li&gt;When the problem asks for &lt;strong&gt;O(1) space&lt;/strong&gt; on a linked list problem — this is almost always the signal&lt;/li&gt;
&lt;li&gt;When the brute-force solution uses a &lt;strong&gt;hash set&lt;/strong&gt; to track visited nodes — that extra space is almost always replaceable with fast &amp;amp; slow pointers&lt;/li&gt;
&lt;li&gt;When the problem involves &lt;strong&gt;cyclic sequences&lt;/strong&gt;, repeated states, or asks for the entry point of a cycle&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What's next ? Practice
&lt;/h3&gt;

&lt;p&gt;Head over to LeetCode and explore the &lt;a href="https://leetcode.com/tag/linked-list/" rel="noopener noreferrer"&gt;linked list problem set&lt;/a&gt;. A few great next problems to challenge yourself with this pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linked List Cycle II&lt;/strong&gt; (Medium) — can you find the &lt;em&gt;exact node&lt;/em&gt; where the cycle begins ?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Happy Number&lt;/strong&gt; (Easy) — fast &amp;amp; slow pointers applied to a numeric sequence, not a list&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reorder List&lt;/strong&gt; (Medium) — combines middle-finding with a reversal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PS: Not every linked list problem requires this pattern, and Floyd's algorithm isn't the only way to detect a cycle. Keep building your instinct for &lt;em&gt;when&lt;/em&gt; a pattern fits — that recognition is the real skill interviewers are testing.&lt;/p&gt;

&lt;p&gt;See you in the next article for another coding pattern !&lt;/p&gt;

</description>
      <category>coding</category>
      <category>algorithms</category>
      <category>interview</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Master Coding Interviews : Part 2 ( Two Pointers Pattern )</title>
      <dc:creator>Messaoud Wael</dc:creator>
      <pubDate>Mon, 30 Mar 2026 16:32:27 +0000</pubDate>
      <link>https://forem.com/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-2-two-pointers-pattern--16mc</link>
      <guid>https://forem.com/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-2-two-pointers-pattern--16mc</guid>
      <description>&lt;p&gt;If you read &lt;a href="https://dev.to/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-1-sliding-window-pattern--35pk"&gt;Part 1 of this series&lt;/a&gt;, you already know how a single pattern can transform a slow, brute-force solution into an elegant, optimized one. Today we're going to do the same thing — but with a different tool in our belt: the &lt;strong&gt;Two Pointers&lt;/strong&gt; pattern.&lt;/p&gt;

&lt;p&gt;This one is everywhere in coding interviews. Once you recognize it, you'll start seeing it in problems you might have struggled with before.&lt;/p&gt;




&lt;h3&gt;
  
  
  What is the Two Pointers Pattern?
&lt;/h3&gt;

&lt;p&gt;The idea is simple: instead of using one index to iterate through your data structure, you use &lt;strong&gt;two&lt;/strong&gt;. These two pointers move through the array (or string) according to specific conditions, and together they help you find the answer without needing nested loops.&lt;/p&gt;

&lt;p&gt;There are two main variants you'll encounter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Opposite-direction pointers&lt;/strong&gt; : One pointer starts at the beginning, the other at the end. They move toward each other until they meet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Same-direction pointers (fast &amp;amp; slow)&lt;/strong&gt; : Both pointers start at the same end, but move at different speeds or under different conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's jump straight into a problem to see the first variant in action.&lt;/p&gt;




&lt;h3&gt;
  
  
  Problem 1 — Two Sum II: Input Array Is Sorted
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe015bfp2mkqszc5ggret.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe015bfp2mkqszc5ggret.png" alt="Two Sum II: Input Array Is Sorted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given a &lt;strong&gt;1-indexed&lt;/strong&gt; array of integers &lt;code&gt;numbers&lt;/code&gt; that is already sorted in non-decreasing order, find two numbers such that they add up to a specific &lt;code&gt;target&lt;/code&gt; number. Return the indices of the two numbers as an integer array &lt;code&gt;[index1, index2]&lt;/code&gt; of length 2.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The brute-force approach is fairly intuitive: try every possible pair and check whether it adds up to the target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;twoSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# 1-indexed result
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works — but just like in Part 1, it hides a performance problem we can't ignore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time complexity : O(n²)&lt;/strong&gt; : For an array of 30,000 elements, this is potentially 900 million comparisons.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time Limit Exceeded&lt;/strong&gt; : For large inputs on LeetCode, this solution will almost certainly hit the TLE wall.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In a real production context, a quadratic loop like this over large datasets is a performance bottleneck waiting to happen.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Optimization through the Two Pointers Pattern
&lt;/h3&gt;

&lt;p&gt;Here's the key insight we're missing in the brute-force: &lt;strong&gt;the array is already sorted&lt;/strong&gt;. That's a hint the problem is giving us for free, and the Two Pointers pattern is exactly how we take advantage of it.&lt;/p&gt;

&lt;p&gt;We place one pointer at the very beginning of the array (&lt;code&gt;left&lt;/code&gt;) and one at the very end (&lt;code&gt;right&lt;/code&gt;). Then we look at their sum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the sum &lt;strong&gt;equals the target&lt;/strong&gt; → we're done.&lt;/li&gt;
&lt;li&gt;If the sum is &lt;strong&gt;too large&lt;/strong&gt; → we need a smaller number, so we move &lt;code&gt;right&lt;/code&gt; one step to the left.&lt;/li&gt;
&lt;li&gt;If the sum is &lt;strong&gt;too small&lt;/strong&gt; → we need a larger number, so we move &lt;code&gt;left&lt;/code&gt; one step to the right.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each iteration eliminates a candidate, and since both pointers are converging toward the center, we'll find the answer — or confirm it doesn't exist — in a single pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;twoSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;                    &lt;span class="c1"&gt;# Left pointer starts at the beginning
&lt;/span&gt;        &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;   &lt;span class="c1"&gt;# Right pointer starts at the end
&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;current_sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_sum&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Found the pair — return 1-indexed positions
&lt;/span&gt;                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;current_sum&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Sum is too large: move right pointer inward to get a smaller value
&lt;/span&gt;                &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Sum is too small: move left pointer inward to get a larger value
&lt;/span&gt;                &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;# No solution found (problem guarantees one exists, but good practice)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This brings us down to &lt;strong&gt;O(n) time complexity&lt;/strong&gt; and &lt;strong&gt;O(1) space complexity&lt;/strong&gt; — a dramatic improvement over the brute-force approach, and it passes LeetCode with no issues.&lt;/p&gt;




&lt;h3&gt;
  
  
  Variant 2 — Same-Direction Pointers
&lt;/h3&gt;

&lt;p&gt;The second variant doesn't converge from opposite ends. Instead, both pointers start from the same side and move in the &lt;strong&gt;same direction&lt;/strong&gt;, but at different speeds or under different conditions. This is perfect for problems where you need to &lt;strong&gt;restructure&lt;/strong&gt; an array in-place or detect a specific pattern as you scan forward.&lt;/p&gt;

&lt;p&gt;Let's look at a classic example.&lt;/p&gt;




&lt;h3&gt;
  
  
  Problem 2 — Remove Duplicates from Sorted Array
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgijihfq4g5ovqarx4wd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgijihfq4g5ovqarx4wd.png" alt="Remove Duplicates from Sorted Array"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given an integer array &lt;code&gt;nums&lt;/code&gt; sorted in non-decreasing order, remove the duplicates &lt;strong&gt;in-place&lt;/strong&gt; such that each unique element appears only once. Return the number of unique elements &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The naïve instinct here might be to use a set to collect unique values and rebuild the array — but the problem explicitly requires an &lt;strong&gt;in-place&lt;/strong&gt; solution using O(1) extra memory. A set would cost us O(n) space, which defeats the purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;removeDuplicates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# This doesn't satisfy the in-place constraint
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beyond the space constraint violation, this approach creates auxiliary data structures we don't need. The Two Pointers pattern gives us a cleaner — and compliant — solution.&lt;/p&gt;




&lt;h3&gt;
  
  
  Optimization: Same-Direction Two Pointers
&lt;/h3&gt;

&lt;p&gt;Here's the idea: we use a &lt;code&gt;slow&lt;/code&gt; pointer to track the position where the next unique element should be written, and a &lt;code&gt;fast&lt;/code&gt; pointer to scan ahead through the array looking for new unique values. Whenever &lt;code&gt;fast&lt;/code&gt; finds a value different from what &lt;code&gt;slow&lt;/code&gt; is pointing at, we advance &lt;code&gt;slow&lt;/code&gt; and write that new value there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;removeDuplicates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# 'slow' marks the boundary of our unique-elements section
&lt;/span&gt;        &lt;span class="n"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="c1"&gt;# 'fast' scans ahead to discover new unique elements
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;fast&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;

            &lt;span class="c1"&gt;# When fast finds a value different from slow's position,
&lt;/span&gt;            &lt;span class="c1"&gt;# a new unique element has been discovered
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="n"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;                  &lt;span class="c1"&gt;# Expand the unique section
&lt;/span&gt;                &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="c1"&gt;# Write the new unique value in place
&lt;/span&gt;
        &lt;span class="c1"&gt;# slow is now the index of the last unique element
&lt;/span&gt;        &lt;span class="c1"&gt;# so the count of unique elements is slow + 1
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Time complexity : O(n)&lt;/strong&gt; — &lt;code&gt;fast&lt;/code&gt; does a single pass through the array.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Space complexity : O(1)&lt;/strong&gt; — everything is done in-place, no extra data structures.&lt;/p&gt;

&lt;p&gt;The elegance here is that the two pointers work as a team: &lt;code&gt;fast&lt;/code&gt; does the exploration, &lt;code&gt;slow&lt;/code&gt; does the writing. They never interfere with each other because &lt;code&gt;slow&lt;/code&gt; can only be at or behind &lt;code&gt;fast&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  When to use this pattern
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;When dealing with &lt;strong&gt;sorted&lt;/strong&gt; arrays or strings (a big hint for opposite-direction pointers)&lt;/li&gt;
&lt;li&gt;When the problem asks you to find a &lt;strong&gt;pair&lt;/strong&gt; (or triplet) of elements that satisfy a condition&lt;/li&gt;
&lt;li&gt;When you need to &lt;strong&gt;restructure or deduplicate&lt;/strong&gt; an array &lt;strong&gt;in-place&lt;/strong&gt; with O(1) space&lt;/li&gt;
&lt;li&gt;When the brute-force solution involves &lt;strong&gt;nested loops&lt;/strong&gt; over the same linear data structure — that's almost always a signal that two pointers can collapse it to O(n)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What's next ? Practice
&lt;/h3&gt;

&lt;p&gt;Head over to LeetCode and try the &lt;a href="https://leetcode.com/tag/two-pointers/" rel="noopener noreferrer"&gt;Two Pointers problem list&lt;/a&gt; — there are over 200 problems tagged with this pattern. Start with the easy ones to build your instinct, then move into medium difficulty.&lt;/p&gt;

&lt;p&gt;A few good ones to try next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Container With Most Water&lt;/strong&gt; (Medium) — opposite-direction pointers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3Sum&lt;/strong&gt; (Medium) — two pointers inside an outer loop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linked List Cycle&lt;/strong&gt; (Easy) — fast &amp;amp; slow pointers on a linked list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PS: As with the Sliding Window pattern, Two Pointers isn't always the &lt;em&gt;only&lt;/em&gt; valid approach. It's a powerful tool when certain conditions are met — sorted data, in-place constraints, pair/subset problems — but always think about whether the pattern genuinely fits before reaching for it.&lt;/p&gt;

&lt;p&gt;See you in the next article for another coding pattern !&lt;/p&gt;

</description>
      <category>coding</category>
      <category>interview</category>
      <category>webdev</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Master Coding Interviews : Part 1 ( Sliding Window Pattern )</title>
      <dc:creator>Messaoud Wael</dc:creator>
      <pubDate>Thu, 29 Jan 2026 20:34:00 +0000</pubDate>
      <link>https://forem.com/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-1-sliding-window-pattern--35pk</link>
      <guid>https://forem.com/messaoud_wael_dd4b26a0d29/master-coding-interviews-part-1-sliding-window-pattern--35pk</guid>
      <description>&lt;p&gt;If you’re having a coding interview, and that you are overwhelmed by the number of coding problems out there, you’re not alone. Especially when you are in a hurry, you want to grasp as much problem solving skills as possible, and this article ( and other parts coming up ) exist to help you with that.&lt;/p&gt;

&lt;p&gt;When tackling a coding problem, there is generally a pattern of how to solve it; what I mean by pattern is the way you want to approach the problem efficiently ( in terms of space and time complexity ) based on the problem requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Let’s look at a specific problem to showcase today’s pattern in practice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjlj25yamuow00cagow5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjlj25yamuow00cagow5x.png" alt="Leet Code Problem: Maximum Average Subarray I " width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first simple solution that may come to mind is to compute the average of all possible sub-arrays and return the maximum value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Solution:
    def findMaxAverage(self, nums: List[int], k: int) -&amp;gt; float:
        max_avg = -1000

        for i in range(len(nums) - k + 1):
            current_sum = 0
            for j in range(i, i + k):
                current_sum += nums[j]
            max_avg = max(max_avg, current_sum / k)

        return max_avg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution works fine, however we may encounter some potential problems with it :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time complexity : O(n*k) : So for example, If $n = 100,000$ and $k = 50,000$, this solution would perform roughly 5 billion operations&lt;/li&gt;
&lt;li&gt;Time Limit Exceeded issue: For large inputs, and in specific environment settings, this solution may resolve in a time limit issue because the environment has a threshold of operations per second. For example, in LeetCode, for a large input it has raised the TLE error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdj38xtyqos014s76fcgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdj38xtyqos014s76fcgt.png" alt="Leet Code TLE problem" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Outside online problem solving platforms, in a real-world solution, this may result in high CPU usage which may result in potential “hangs” for the users&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimization through the Sliding Window Pattern
&lt;/h3&gt;

&lt;p&gt;We could improve the solution using a &lt;strong&gt;&lt;em&gt;sliding window pattern&lt;/em&gt;&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;As the name suggests, we try to construct a window that grows and shrinks according to the requirements of the problem, and perform the main solution within that window. Let me showcase that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Solution:
    def findMaxAverage(self, nums: List[int], k: int) -&amp;gt; float:
        current_sum = 0
        left = 0 # Left boundary of the window
        avg = 0
        max_avg = -1000

        # The index used inside the loop represents the right boundary of the window
        # So window size is: right - left + 1
        for right in range(len(nums)): 
            diff = right - left + 1
            current_sum += nums[right]

            # If window's size attains the required length for the subset
            # we have to adjust its size by incremeting the left index 
            # after calculating the average value
            if diff == k:
                avg = current_sum / k
                max_avg = max(avg,max_avg)
                current_sum -= nums[left]
                left +=1

        return max_avg

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This algorithm optimizes the previous solution with O(n) time complexity and the same O(1) space complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use this pattern
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When dealing with linear data structures ( lists, string,… )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The solution has to deal with finding some subset&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What’s next ? Practice
&lt;/h3&gt;

&lt;p&gt;You may use the LeetCode platform online and pick some &lt;a href="https://leetcode.com/problem-list/sliding-window/" rel="noopener noreferrer"&gt;sliding window problems&lt;/a&gt; from there to practice. You have a set of 161 questions !&lt;/p&gt;

&lt;p&gt;PS: Some of these problems may be solved efficiently, not only by using this pattern. Keep in mind that a pattern exists to help you with one way of solving a problem when some requirements are gathered, but may not be the only approach we could use !&lt;/p&gt;

&lt;p&gt;See you in the next article for another coding pattern !&lt;/p&gt;

</description>
      <category>coding</category>
      <category>algorithms</category>
      <category>interview</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Azure Fundamentals Series : NSG vs Firewall</title>
      <dc:creator>Messaoud Wael</dc:creator>
      <pubDate>Thu, 22 Jan 2026 01:05:58 +0000</pubDate>
      <link>https://forem.com/messaoud_wael_dd4b26a0d29/azure-fundamentals-series-nsg-vs-firewall-2dij</link>
      <guid>https://forem.com/messaoud_wael_dd4b26a0d29/azure-fundamentals-series-nsg-vs-firewall-2dij</guid>
      <description>&lt;p&gt;Azure Firewall and Network Security groups are two of the most common security components used in the Azure network infrastructure. Their main role is controlling the inbound and outbound traffic by filtering unwanted traffic, and that's where the confusion comes from. If they are so similar at first glance, how do they differ and when to use each one ?&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison
&lt;/h2&gt;

&lt;p&gt;Below is a summarized comparison table between the main features of the 2 security services, followed by a deeper explanation for each comparison.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Azure Firewall&lt;/th&gt;
&lt;th&gt;Network Security Group&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security service to secure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VNet&lt;/td&gt;
&lt;td&gt;a resource/subnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operates on OSI layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3, 4 &amp;amp; 7&lt;/td&gt;
&lt;td&gt;3 &amp;amp; 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Uses&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;application, transport, network,NAT rules and threat intelligence&lt;/td&gt;
&lt;td&gt;basic network and transport rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Has intelligent threat mechanism built in&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Blocks traffic from known malicious IPs automatically&lt;/td&gt;
&lt;td&gt;Doesn't have a built-in intelligent-threat mechanism&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Paid-service&lt;/td&gt;
&lt;td&gt;Free ( Part of the Resource / Subnet cost )&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supports auto-scaling&lt;/td&gt;
&lt;td&gt;Does not scale; it is just a list of rules applied to a subnet/resource.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Application Scope
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NSG works at the resource-level:&lt;/strong&gt; It is directly attached to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A subnet (filtering traffic for all resources in that subnet)&lt;/li&gt;
&lt;li&gt;A network interface (NIC) of a Virtual Machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Azure Firewall works at the network-level:&lt;/strong&gt; It is deployed into a dedicated subnet within a VNet. You route traffic through it. This allows it to protect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An entire VNet (by applying routes to its subnets)&lt;/li&gt;
&lt;li&gt;Multiple VNets (via peering or Virtual WAN Hub)&lt;/li&gt;
&lt;li&gt;Specific subnets within a VNet&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;A small dive into how a Firewall works&lt;/strong&gt; : We define an Azure Route Table in which we specify User-Defined-routes ( a destination IP address + next hop address which in our case , is going to be a private IP address representing the network location of our firewall ). We assign this table to each subnet, so we can ensure that all traffic coming to our destination is being redirected to the Firewall.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Layers they work on
&lt;/h2&gt;

&lt;p&gt;( 2nd point of comparison, which will also include the 3rd and 4th ones, and you'll understand how they are bound together )&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NSG&lt;/strong&gt; operates as a stateless and isolated packet-filtering tool at the Network (Layer 3) and Transport (Layer 4) layers. It makes simple allow/deny decisions based on the fundamental information in packet headers.&lt;/p&gt;

&lt;p&gt;It inspects 5 parameters :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source IP Address (Layer 3)&lt;/li&gt;
&lt;li&gt;Destination IP Address (Layer 3)&lt;/li&gt;
&lt;li&gt;Protocol (e.g., TCP, UDP) (Layer 4)&lt;/li&gt;
&lt;li&gt;Source Port (Layer 4)&lt;/li&gt;
&lt;li&gt;Destination Port (Layer 4)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Limitation - Stateless:&lt;/strong&gt; NSG does not understand if a packet is part of an existing, legitimate conversation. You must explicitly define rules for both the initial request (e.g., Port X → Port 80) and the traffic's return (Port 80 → Port X).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure Firewall&lt;/strong&gt; is a stateful tool that inspects traffic at Network (L3), Transport (L4), and Application (L7) layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3 &amp;amp; 4 (Stateful Inspection):&lt;/strong&gt; Like an NSG, it sees IPs, ports and the used protocol. However, it is stateful, in other words, it understands and tracks the state of network connections. A very simple example to understand this is, if a VM placed inside an internal subnet initiates an outbound connection to the internet, the firewall automatically allows the return traffic back to that VM without needing an explicit inbound rule. This simplifies management and increases security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 7 (Application Layer):&lt;/strong&gt; Azure Firewall have some superpowers operating at this layer ! It is actually capable of inspecting the actual content of the traffic to make intelligent decisions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FQDN Filtering:&lt;/strong&gt; Can allow or deny traffic based on Fully Qualified Domain Names (e.g., *.windowsupdate.microsoft.com), not just IP addresses, which are dynamic and can change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Rules:&lt;/strong&gt; Can identify traffic based on the application protocol (e.g., WindowsUpdate, AzureKubernetesService).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Categories:&lt;/strong&gt; Can filter outbound web traffic by categories (e.g., Social Media, Gambling).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Threat Intelligence:&lt;/strong&gt; Can alert and deny traffic to/from known malicious IP addresses and domains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Address Translation (NAT):&lt;/strong&gt; It provides DNAT (Destination NAT) rules, which allow you to translate a public IP on the firewall to a private IP/port inside your VNet (e.g., exposing an internal SSH server securely).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cost-comparison
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NSG&lt;/strong&gt; is a built-in networking resource in Azure with no additional charge, since it comes as a protection layer with the resource you're paying for ( e.g., Virtual Machine )&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;Azure Firewall&lt;/strong&gt; is a platform-as-a-service (PaaS) offering with associated costs that scale with features and throughput. Cost differs between different existing tiers ( Basic, Standard and Premium )&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling
&lt;/h2&gt;

&lt;p&gt;While NSG rules automatically apply to new resources within their assigned subnet or NIC, they are inherently static configurations. This can create operational challenges. For example, when scaling your infrastructure, like provisioning new VMs across multiple regions for a Black Friday event, each new environment or unique traffic pattern may require manual rule duplication or some reevaluation of IP ranges =&amp;gt; separate manual management. NSG scales with your resources but does not dynamically adapt to your evolving security needs.&lt;/p&gt;

&lt;p&gt;On the other hand, Azure Firewall addresses this through centralized policy management. A single firewall policy governs traffic for all resources, regardless of scale. When you provision new VMs or expand to new regions, the security rules automatically apply without duplication so enabling true scalability.&lt;/p&gt;

&lt;p&gt;Furthermore, Azure Firewall is designed as a resilient service. It can be deployed across multiple Availability Zones, providing automatic failover and high availability (e.g., up to 99.99% SLA for Premium SKU deployments).&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Analogy
&lt;/h2&gt;

&lt;p&gt;Think of Azure Virtual Network as a corporate campus. In this context, Azure Firewall is the main security gatehouse that all vehicles must pass through to enter or leave the campus grounds. NSGs are the individual door locks and/or department access cards that control movement within the buildings and offices once inside.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>cloudcomputing</category>
      <category>architecture</category>
      <category>az900</category>
    </item>
  </channel>
</rss>
