<?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>DEV Community: Hommies</title>
    <description>The latest articles on DEV Community by Hommies (@hommies_fcbf2afe8ddb0c2a7).</description>
    <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7</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%2F3935048%2F4936ff25-ae04-441c-94d9-acce58982ad0.jpg</url>
      <title>DEV Community: Hommies</title>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hommies_fcbf2afe8ddb0c2a7"/>
    <language>en</language>
    <item>
      <title>LeetCode Solution: 2. Add Two Numbers</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Sun, 31 May 2026 17:16:54 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-2-add-two-numbers-254f</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-2-add-two-numbers-254f</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Add Two Numbers 🟡 Medium: Summing Up Linked Lists Like a Pro!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hey there, aspiring algorithm wizards! 👋 ahB1IK4YXF here, ready to demystify another classic LeetCode challenge. Today, we're tackling "Add Two Numbers," a fantastic problem that combines linked lists with some good old-fashioned arithmetic. Don't let the "Medium" tag scare you; we'll break it down step by step, and you'll see it's quite approachable once you grasp the core idea.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Problem: Adding Numbers Represented by Linked Lists
&lt;/h3&gt;

&lt;p&gt;Imagine you're back in elementary school, learning to add two multi-digit numbers. You line them up, add digit by digit from right to left, and carry over any extra tens. This problem is exactly that, but with a twist: our numbers are represented by &lt;strong&gt;linked lists&lt;/strong&gt;, and their digits are stored in &lt;strong&gt;reverse order&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;You're given two non-empty linked lists, &lt;code&gt;l1&lt;/code&gt; and &lt;code&gt;l2&lt;/code&gt;. Each node contains a single digit (0-9). The digits are stored in reverse order, meaning the &lt;code&gt;head&lt;/code&gt; of the list represents the "ones" place, the next node the "tens" place, and so on.&lt;/p&gt;

&lt;p&gt;Your task? Add these two numbers and return the sum as a new linked list, also in reverse order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1: The Magic Reveal&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;l1 = [2,4,3]&lt;/code&gt; represents the number 342.&lt;br&gt;
&lt;code&gt;l2 = [5,6,4]&lt;/code&gt; represents the number 465.&lt;/p&gt;

&lt;p&gt;If we add 342 + 465, we get 807.&lt;br&gt;
The problem expects the output as &lt;code&gt;[7,0,8]&lt;/code&gt;, which is 807 in reverse order. Perfect!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2: Simple Zeroes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;l1 = [0]&lt;/code&gt;, &lt;code&gt;l2 = [0]&lt;/code&gt;&lt;br&gt;
Output: &lt;code&gt;[0]&lt;/code&gt;&lt;br&gt;
(0 + 0 = 0)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 3: Handling Carries and Different Lengths&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;l1 = [9,9,9,9,9,9,9]&lt;/code&gt; (represents 9,999,999)&lt;br&gt;
&lt;code&gt;l2 = [9,9,9,9]&lt;/code&gt; (represents 9,999)&lt;br&gt;
Output: &lt;code&gt;[8,9,9,9,0,0,0,1]&lt;/code&gt; (represents 10,009,998)&lt;/p&gt;

&lt;p&gt;Notice how the output list is longer than &lt;code&gt;l2&lt;/code&gt; and even &lt;code&gt;l1&lt;/code&gt; in some cases. This is crucial!&lt;/p&gt;


&lt;h3&gt;
  
  
  Intuition: Back to Basics (but with pointers!)
&lt;/h3&gt;

&lt;p&gt;At its heart, this problem is just basic addition. Think about how you'd add 15 + 7:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the ones digits: 5 + 7 = 12.&lt;/li&gt;
&lt;li&gt;Write down '2'.&lt;/li&gt;
&lt;li&gt;Carry over '1' to the tens place.&lt;/li&gt;
&lt;li&gt;Add the tens digits (including the carry): 1 (from 15) + 0 (from 7) + 1 (carry) = 2.&lt;/li&gt;
&lt;li&gt;Write down '2'.
Result: 22.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fact that the linked list digits are in &lt;em&gt;reverse order&lt;/em&gt; actually simplifies things for us! The head of the list (&lt;code&gt;l1-&amp;gt;val&lt;/code&gt;, &lt;code&gt;l2-&amp;gt;val&lt;/code&gt;) is already our "ones" place. So, we can just iterate through the lists from head to tail, performing digit-by-digit addition just like we would on paper, moving from right to left (which is left to right in our linked lists).&lt;/p&gt;

&lt;p&gt;We need a variable to keep track of the &lt;code&gt;carry&lt;/code&gt; as we move from one pair of digits to the next.&lt;/p&gt;


&lt;h3&gt;
  
  
  The Approach: A Step-by-Step Construction
&lt;/h3&gt;

&lt;p&gt;We'll build our result linked list node by node. Here's the plan:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialize a Dummy Head&lt;/strong&gt;: Creating a "dummy" node for our result list is a common and super handy trick in linked list problems. Instead of worrying about creating the very first node of the result list and handling it specially, we create a dummy node, attach our results to &lt;code&gt;dummy.next&lt;/code&gt;, and then return &lt;code&gt;dummy.next&lt;/code&gt; at the end. This keeps our code clean and consistent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;ListNode* dummy = new ListNode();&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;ListNode* current = dummy;&lt;/code&gt; (We'll use &lt;code&gt;current&lt;/code&gt; to traverse and add new nodes to the result list).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialize Carry&lt;/strong&gt;: We'll need a variable, &lt;code&gt;carry&lt;/code&gt;, initialized to 0, to store any carry-over from previous additions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;int carry = 0;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iterate Through the Lists&lt;/strong&gt;: We'll use a &lt;code&gt;while&lt;/code&gt; loop that continues as long as there are digits in &lt;code&gt;l1&lt;/code&gt;, or digits in &lt;code&gt;l2&lt;/code&gt;, or a &lt;code&gt;carry&lt;/code&gt; still needs to be processed. This handles lists of different lengths and the final carry if the sum results in an extra digit (e.g., &lt;code&gt;99 + 1 = 100&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;while (l1 || l2 || carry)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Calculate the Sum for Current Digits&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Start &lt;code&gt;total&lt;/code&gt; with the &lt;code&gt;carry&lt;/code&gt; from the previous step.&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;l1&lt;/code&gt; is not null, add its current digit (&lt;code&gt;l1-&amp;gt;val&lt;/code&gt;) to &lt;code&gt;total&lt;/code&gt; and advance &lt;code&gt;l1&lt;/code&gt; to its &lt;code&gt;next&lt;/code&gt; node.&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;l2&lt;/code&gt; is not null, add its current digit (&lt;code&gt;l2-&amp;gt;val&lt;/code&gt;) to &lt;code&gt;total&lt;/code&gt; and advance &lt;code&gt;l2&lt;/code&gt; to its &lt;code&gt;next&lt;/code&gt; node.&lt;/li&gt;
&lt;li&gt;  This gracefully handles cases where one list is shorter than the other – the &lt;code&gt;if (l1)&lt;/code&gt; and &lt;code&gt;if (l2)&lt;/code&gt; checks ensure we only add existing digits.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Determine the New Digit and Carry&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The digit for our new result node is &lt;code&gt;total % 10&lt;/code&gt; (the remainder when divided by 10).&lt;/li&gt;
&lt;li&gt;  The new &lt;code&gt;carry&lt;/code&gt; is &lt;code&gt;total / 10&lt;/code&gt; (the quotient when divided by 10).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create and Append New Node&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Create a new &lt;code&gt;ListNode&lt;/code&gt; with the calculated digit.&lt;/li&gt;
&lt;li&gt;  Attach this new node to &lt;code&gt;current-&amp;gt;next&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Move &lt;code&gt;current&lt;/code&gt; forward to this newly added node: &lt;code&gt;current = current-&amp;gt;next;&lt;/code&gt; This prepares &lt;code&gt;current&lt;/code&gt; to append the next digit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Return the Result&lt;/strong&gt;: After the loop finishes, all digits (and any final carry) will have been processed. Our dummy node's &lt;code&gt;next&lt;/code&gt; pointer will point to the head of our actual result linked list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;return dummy-&amp;gt;next;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Important C++ detail&lt;/strong&gt;: The solution code also includes &lt;code&gt;delete res;&lt;/code&gt; where &lt;code&gt;res&lt;/code&gt; was the original &lt;code&gt;dummy&lt;/code&gt; pointer. This is good practice to free the memory allocated for the initial dummy node itself, as we're returning &lt;code&gt;res-&amp;gt;next&lt;/code&gt; (the actual result list head) and no longer need the dummy.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;

&lt;p&gt;Let's put it all together in C++:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */&lt;/span&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="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;addTwoNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create a dummy node to simplify list construction&lt;/span&gt;
        &lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&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;ListNode&lt;/span&gt;&lt;span class="o"&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;dummy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'current' will traverse and build the new list&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;carry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Initialize carry-over to 0&lt;/span&gt;

        &lt;span class="c1"&gt;// Loop as long as there are digits in either list or a carry remains&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;carry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;carry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Start sum with any carry from previous addition&lt;/span&gt;

            &lt;span class="c1"&gt;// Add digit from l1 if it exists&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;l1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Move to the next digit in l1&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Add digit from l2 if it exists&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;l2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Move to the next digit in l2&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Calculate the digit for the new node and the new carry&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;digit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// The current digit is the remainder&lt;/span&gt;
            &lt;span class="n"&gt;carry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// The new carry is the quotient&lt;/span&gt;

            &lt;span class="c1"&gt;// Create a new node with the calculated digit&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ListNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digit&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Move 'current' to the newly added node&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// The actual result list starts from dummy-&amp;gt;next&lt;/span&gt;
        &lt;span class="c1"&gt;// We delete the initial dummy node to prevent memory leak (good practice in C++)&lt;/span&gt;
        &lt;span class="n"&gt;ListNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'res' in the original code snippet was 'dummy' here&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The provided solution code snippet uses &lt;code&gt;res&lt;/code&gt; as the initial dummy and &lt;code&gt;dummy&lt;/code&gt; as the &lt;code&gt;current&lt;/code&gt; pointer. My version uses &lt;code&gt;dummy&lt;/code&gt; as the initial dummy and &lt;code&gt;current&lt;/code&gt; as the traversing pointer, which is a common naming convention. The logic is identical.&lt;/p&gt;




&lt;h3&gt;
  
  
  Time &amp;amp; Space Complexity Analysis
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time Complexity: O(max(N, M))&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;N&lt;/code&gt; is the number of nodes in &lt;code&gt;l1&lt;/code&gt;, and &lt;code&gt;M&lt;/code&gt; is the number of nodes in &lt;code&gt;l2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  We iterate through both linked lists exactly once. The loop runs for a number of times equal to the length of the longer list (plus possibly one more iteration if there's a final carry).&lt;/li&gt;
&lt;li&gt;  Each operation inside the loop (addition, modulo, division, node creation) takes constant time.&lt;/li&gt;
&lt;li&gt;  Therefore, the time complexity is directly proportional to the length of the longer input list.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity: O(max(N, M))&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We create a new linked list to store the sum.&lt;/li&gt;
&lt;li&gt;  In the worst case, the sum list can be one node longer than the maximum length of &lt;code&gt;l1&lt;/code&gt; or &lt;code&gt;l2&lt;/code&gt; (e.g., adding &lt;code&gt;99&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; results in &lt;code&gt;100&lt;/code&gt;, which is three digits while the inputs were two and one).&lt;/li&gt;
&lt;li&gt;  So, the number of new nodes created is proportional to the length of the longer input list.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Dummy Nodes&lt;/strong&gt;: A powerful pattern for building new linked lists or modifying existing ones, eliminating edge cases for the head of the list.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Iterative Traversal&lt;/strong&gt;: For problems requiring processing linked lists linearly, an iterative approach with pointers is often the most straightforward and efficient.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Handling Carries&lt;/strong&gt;: This problem perfectly illustrates how to manage carry-over values in digit-by-digit operations, a fundamental concept in arithmetic and computer science.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Flexible Loop Conditions&lt;/strong&gt;: The &lt;code&gt;while (l1 || l2 || carry)&lt;/code&gt; condition is elegant. It ensures all digits from both lists are processed, and crucially, accounts for any final carry that might extend the result list.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Modular Arithmetic&lt;/strong&gt;: Using &lt;code&gt;% 10&lt;/code&gt; to get the current digit and &lt;code&gt;/ 10&lt;/code&gt; to get the carry is a classic trick for working with digits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This problem is a fantastic introduction to linked lists and showcases how data structures can represent everyday concepts in interesting ways. Keep practicing, and you'll be a linked list master in no time!&lt;/p&gt;




&lt;h3&gt;
  
  
  Submission Details
&lt;/h3&gt;

&lt;p&gt;Author: ahB1IK4YXF&lt;br&gt;
Publishing Time: 2026-05-31 22:46:31&lt;br&gt;
Problem Link: &lt;a href="https://leetcode.com/problems/add-two-numbers/" rel="noopener noreferrer"&gt;https://leetcode.com/problems/add-two-numbers/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 1. Two Sum</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Sun, 31 May 2026 17:08:59 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-1-two-sum-4c1h</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-1-two-sum-4c1h</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Two Sum 🟢 Easy: Your First Step into LeetCode Magic!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Problem Explanation: The Quest for the Perfect Pair
&lt;/h2&gt;

&lt;p&gt;Imagine you have a list of numbers, like &lt;code&gt;[2, 7, 11, 15]&lt;/code&gt;. Your goal is to find two numbers from this list that, when added together, equal a specific &lt;code&gt;target&lt;/code&gt; number, say &lt;code&gt;9&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sounds simple, right? But there's a catch! You don't just return the numbers themselves, you need to return their &lt;em&gt;positions&lt;/em&gt; (or indices) in the original list.&lt;/p&gt;

&lt;p&gt;Let's look at our example: &lt;code&gt;nums = [2, 7, 11, 15]&lt;/code&gt;, &lt;code&gt;target = 9&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If we take &lt;code&gt;2&lt;/code&gt; (at index &lt;code&gt;0&lt;/code&gt;) and &lt;code&gt;7&lt;/code&gt; (at index &lt;code&gt;1&lt;/code&gt;), their sum is &lt;code&gt;2 + 7 = 9&lt;/code&gt;. Bingo!&lt;/li&gt;
&lt;li&gt;  So, our answer would be &lt;code&gt;[0, 1]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few important rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Exactly one solution:&lt;/strong&gt; You're guaranteed to find one pair that works. No need to worry about multiple pairs or no pairs at all.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;No duplicates:&lt;/strong&gt; You can't use the same number twice. If &lt;code&gt;nums = [3, 3]&lt;/code&gt; and &lt;code&gt;target = 6&lt;/code&gt;, you use the &lt;code&gt;3&lt;/code&gt; at index &lt;code&gt;0&lt;/code&gt; and the &lt;code&gt;3&lt;/code&gt; at index &lt;code&gt;1&lt;/code&gt;. You can't use the &lt;code&gt;3&lt;/code&gt; at index &lt;code&gt;0&lt;/code&gt; with itself.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Order doesn't matter:&lt;/strong&gt; &lt;code&gt;[0, 1]&lt;/code&gt; is the same as &lt;code&gt;[1, 0]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This problem, "Two Sum," is often the very first problem people encounter on coding platforms like LeetCode. It's a fantastic way to start building your algorithmic thinking!&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Intuition: From Brute Force to Brilliant!
&lt;/h2&gt;

&lt;p&gt;When faced with a problem like this, the first thought for many beginners (and even seasoned pros!) is often: "How can I check &lt;em&gt;every single possibility&lt;/em&gt;?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "Brute Force" Idea (and why we want something better):&lt;/strong&gt;&lt;br&gt;
You could pick the first number, then go through &lt;em&gt;all&lt;/em&gt; the other numbers to see if any of them add up to the &lt;code&gt;target&lt;/code&gt;. Then pick the second number, and again, check all subsequent numbers. This looks like nested loops:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;For each number 'num1' in the array:
    For each *other* number 'num2' in the array (that hasn't been checked with num1):
        If num1 + num2 == target:
            Return their indices!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works! But imagine our list &lt;code&gt;nums&lt;/code&gt; has 10,000 numbers. The outer loop runs 10,000 times, and the inner loop also runs nearly 10,000 times for each outer loop iteration. That's roughly &lt;code&gt;10,000 * 10,000 = 100,000,000&lt;/code&gt; operations! That's a lot, and for larger lists, it becomes too slow. We call this a &lt;code&gt;O(n^2)&lt;/code&gt; (read as "O of n squared") solution, and we can do better!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "Aha!" Moment: What are we &lt;em&gt;really&lt;/em&gt; looking for?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's say we pick a number &lt;code&gt;num&lt;/code&gt;. If we want &lt;code&gt;num + another_num = target&lt;/code&gt;, then &lt;code&gt;another_num&lt;/code&gt; &lt;em&gt;must&lt;/em&gt; be equal to &lt;code&gt;target - num&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, for every &lt;code&gt;num&lt;/code&gt; we encounter, we're not just looking for &lt;em&gt;any&lt;/em&gt; other number. We're looking for a &lt;em&gt;very specific&lt;/em&gt; &lt;code&gt;complement&lt;/code&gt; number: &lt;code&gt;target - num&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we could quickly ask, "Hey, have I seen &lt;code&gt;complement&lt;/code&gt; before, and if so, where was it?", we could solve this much faster! This is where the magic of a &lt;strong&gt;Hash Map&lt;/strong&gt; (or &lt;code&gt;unordered_map&lt;/code&gt; in C++ and &lt;code&gt;dictionary&lt;/code&gt; in Python) comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Approach: Leveraging the Power of Hash Maps
&lt;/h2&gt;

&lt;p&gt;A hash map is like a super-fast dictionary. You give it a &lt;code&gt;key&lt;/code&gt; (like a word), and it immediately tells you its &lt;code&gt;value&lt;/code&gt; (like the definition), or if it hasn't seen that key before. This "immediate" lookup usually takes constant time, &lt;code&gt;O(1)&lt;/code&gt;, which is incredibly efficient!&lt;/p&gt;

&lt;p&gt;Here's how we can use a hash map to solve Two Sum in a single pass:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialize an empty hash map:&lt;/strong&gt; This map will store numbers we've seen so far, along with their indices. So, &lt;code&gt;number_value -&amp;gt; its_index&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Example: &lt;code&gt;{2: 0, 7: 1}&lt;/code&gt; means "the number 2 was found at index 0, and the number 7 was found at index 1".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Iterate through the &lt;code&gt;nums&lt;/code&gt; array, one number at a time, along with its index.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For each &lt;code&gt;num&lt;/code&gt; at &lt;code&gt;current_index&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
a.  Calculate the &lt;code&gt;complement&lt;/code&gt; we need: &lt;code&gt;complement = target - num&lt;/code&gt;.&lt;br&gt;
b.  &lt;strong&gt;Check if &lt;code&gt;complement&lt;/code&gt; exists in our hash map.&lt;/strong&gt;&lt;br&gt;
    *   If &lt;strong&gt;YES&lt;/strong&gt;, it means we've previously encountered the &lt;code&gt;complement&lt;/code&gt; number. We've found our pair!&lt;br&gt;
        *   The current number is &lt;code&gt;num&lt;/code&gt; (at &lt;code&gt;current_index&lt;/code&gt;).&lt;br&gt;
        *   The other number is &lt;code&gt;complement&lt;/code&gt; (whose index is stored in the hash map).&lt;br&gt;
        *   Return &lt;code&gt;[current_index, hash_map[complement]]&lt;/code&gt;.&lt;br&gt;
    *   If &lt;strong&gt;NO&lt;/strong&gt;, the &lt;code&gt;complement&lt;/code&gt; is not in our map yet. This means &lt;code&gt;num&lt;/code&gt; isn't part of a pair with any number we've seen &lt;em&gt;so far&lt;/em&gt;.&lt;br&gt;
        *   So, we add &lt;code&gt;num&lt;/code&gt; and its &lt;code&gt;current_index&lt;/code&gt; to our hash map: &lt;code&gt;hash_map[num] = current_index&lt;/code&gt;. This way, if a future number needs &lt;code&gt;num&lt;/code&gt; as its complement, it can find it quickly.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Let's walk through &lt;code&gt;nums = [2, 7, 11, 15]&lt;/code&gt;, &lt;code&gt;target = 9&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start:&lt;/strong&gt; &lt;code&gt;map = {}&lt;/code&gt; (empty)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iteration 1:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;num = 2&lt;/code&gt;, &lt;code&gt;current_index = 0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;complement = 9 - 2 = 7&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Is &lt;code&gt;7&lt;/code&gt; in &lt;code&gt;map&lt;/code&gt;? No.&lt;/li&gt;
&lt;li&gt;  Add &lt;code&gt;2&lt;/code&gt; to map: &lt;code&gt;map = {2: 0}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Iteration 2:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;num = 7&lt;/code&gt;, &lt;code&gt;current_index = 1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;complement = 9 - 7 = 2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Is &lt;code&gt;2&lt;/code&gt; in &lt;code&gt;map&lt;/code&gt;? &lt;strong&gt;YES!&lt;/strong&gt; Its index is &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  We found the pair! Return &lt;code&gt;[current_index (1), map[2] (0)]&lt;/code&gt;, which is &lt;code&gt;[1, 0]&lt;/code&gt;. (Remember, order doesn't matter, so &lt;code&gt;[0, 1]&lt;/code&gt; is also correct).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;And just like that, we found the pair in a single pass through the array!&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Code: Bringing it to Life in C++
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&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="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;twoSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// We'll use an unordered_map (hash map) to store numbers&lt;/span&gt;
        &lt;span class="c1"&gt;// we've seen and their corresponding indices.&lt;/span&gt;
        &lt;span class="c1"&gt;// Key: The number itself&lt;/span&gt;
        &lt;span class="c1"&gt;// Value: The index where that number was found&lt;/span&gt;
        &lt;span class="n"&gt;unordered_map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pairIdx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Iterate through the array `nums` from left to right&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&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;0&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;&amp;lt;&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;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&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;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// Get the current number&lt;/span&gt;

            &lt;span class="c1"&gt;// Calculate the 'complement' needed:&lt;/span&gt;
            &lt;span class="c1"&gt;// If num + complement = target, then complement = target - num&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;complement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&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;// Check if this 'complement' already exists in our map.&lt;/span&gt;
            &lt;span class="c1"&gt;// If it does, we've found our pair!&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pairIdx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;complement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;pairIdx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// If complement is found, return its index (from the map)&lt;/span&gt;
                &lt;span class="c1"&gt;// and the current number's index (i).&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;pairIdx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;complement&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="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// If the complement wasn't found, it means the current 'num'&lt;/span&gt;
            &lt;span class="c1"&gt;// doesn't form a pair with any number we've seen so far.&lt;/span&gt;
            &lt;span class="c1"&gt;// So, we add the current 'num' and its 'index' to our map&lt;/span&gt;
            &lt;span class="c1"&gt;// for future numbers to potentially find it as their complement.&lt;/span&gt;
            &lt;span class="n"&gt;pairIdx&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// According to the problem constraints, there's always exactly one solution,&lt;/span&gt;
        &lt;span class="c1"&gt;// so this line should technically never be reached in a valid test case.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Time &amp;amp; Space Complexity Analysis
&lt;/h2&gt;

&lt;p&gt;Understanding how efficient our code is crucial for competitive programming and real-world development! We measure efficiency using "Big O" notation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Brute Force Approach (nested loops):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Time Complexity: &lt;code&gt;O(n^2)&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  We have two nested loops. If &lt;code&gt;n&lt;/code&gt; is the number of elements in &lt;code&gt;nums&lt;/code&gt;, the outer loop runs &lt;code&gt;n&lt;/code&gt; times, and the inner loop runs approximately &lt;code&gt;n&lt;/code&gt; times for each outer iteration. This leads to &lt;code&gt;n * n&lt;/code&gt; operations in the worst case.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Space Complexity: &lt;code&gt;O(1)&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  This approach uses a constant amount of extra space (just a few variables for loop counters, etc.), regardless of the input array size.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hash Map Approach (our solution):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Time Complexity: &lt;code&gt;O(n)&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  We iterate through the &lt;code&gt;nums&lt;/code&gt; array only once.&lt;/li&gt;
&lt;li&gt;  Inside the loop, hash map operations (&lt;code&gt;find&lt;/code&gt; and insertion &lt;code&gt;[]&lt;/code&gt;) take &lt;code&gt;O(1)&lt;/code&gt; time on average. In the worst case (due to hash collisions), they can degrade to &lt;code&gt;O(n)&lt;/code&gt;, but this is rare with good hash functions and typically averaged out.&lt;/li&gt;
&lt;li&gt;  Since we do a constant amount of work for each of the &lt;code&gt;n&lt;/code&gt; elements, the total time complexity is linear, &lt;code&gt;O(n)&lt;/code&gt;. This is significantly faster than &lt;code&gt;O(n^2)&lt;/code&gt; for large &lt;code&gt;n&lt;/code&gt;!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Space Complexity: &lt;code&gt;O(n)&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  In the worst-case scenario, if no pair is found until the very last element, our hash map could end up storing all &lt;code&gt;n&lt;/code&gt; elements from the &lt;code&gt;nums&lt;/code&gt; array. Each element stored takes up some memory. Thus, the space required grows linearly with the input size &lt;code&gt;n&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This is a classic example of a &lt;strong&gt;time-space trade-off&lt;/strong&gt;: by using extra space (for the hash map), we dramatically reduce the time it takes to find the solution!&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;The Power of Hash Maps:&lt;/strong&gt; For problems requiring fast lookups (checking if an element exists, or getting its associated value), hash maps (or hash tables) are your best friend! They can often turn &lt;code&gt;O(n)&lt;/code&gt; or &lt;code&gt;O(n^2)&lt;/code&gt; search problems into &lt;code&gt;O(1)&lt;/code&gt; average-time lookups.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Complementary Thinking:&lt;/strong&gt; Many "sum" or "difference" problems can be reframed. Instead of searching for &lt;em&gt;any&lt;/em&gt; two numbers, think: if I have &lt;code&gt;X&lt;/code&gt;, what &lt;code&gt;Y&lt;/code&gt; do I &lt;em&gt;need&lt;/em&gt; (&lt;code&gt;target - X&lt;/code&gt;)? Then, how fast can I find &lt;code&gt;Y&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Time-Space Trade-off:&lt;/strong&gt; Sometimes, using more memory (space) can lead to much faster execution times. This is a common design pattern in algorithms.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Foundation Problem:&lt;/strong&gt; Two Sum is a fundamental problem. Mastering it builds a strong foundation for tackling more complex algorithmic challenges! It teaches you to look beyond the obvious brute-force and consider data structures that optimize specific operations.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  8. Submission Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Author Account:&lt;/strong&gt; ahB1IK4YXF&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Publishing Time:&lt;/strong&gt; 2026-05-31 22:38:38&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 17. Letter Combinations of a Phone Number</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Sun, 31 May 2026 17:05:55 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-17-letter-combinations-of-a-phone-number-20aj</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-17-letter-combinations-of-a-phone-number-20aj</guid>
      <description>&lt;h1&gt;
  
  
  Cracking the Code: Phone Number Letter Combinations (LeetCode 17) 🟡 Medium
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Author Account:&lt;/strong&gt; p1Hzd8mRM8&lt;br&gt;
&lt;strong&gt;Publishing Time:&lt;/strong&gt; 2026-05-31 22:35:29&lt;/p&gt;



&lt;p&gt;Hey fellow coders! 👋 Have you ever wondered how old-school phone keypads could translate into a fun coding challenge? Today, we're diving into LeetCode problem 17: "Letter Combinations of a Phone Number." It's a fantastic problem to introduce you to the powerful concept of &lt;strong&gt;backtracking&lt;/strong&gt; – a fundamental technique in competitive programming!&lt;/p&gt;

&lt;p&gt;Don't worry if "backtracking" sounds intimidating. We'll break it down step-by-step, making it super clear and enjoyable. Let's get started! 🚀&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Problem Explanation
&lt;/h2&gt;

&lt;p&gt;Imagine an old-fashioned telephone keypad. Each digit (from 2 to 9) corresponds to a set of letters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;2&lt;/code&gt; -&amp;gt; &lt;code&gt;abc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;3&lt;/code&gt; -&amp;gt; &lt;code&gt;def&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;4&lt;/code&gt; -&amp;gt; &lt;code&gt;ghi&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;5&lt;/code&gt; -&amp;gt; &lt;code&gt;jkl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;6&lt;/code&gt; -&amp;gt; &lt;code&gt;mno&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;7&lt;/code&gt; -&amp;gt; &lt;code&gt;pqrs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;8&lt;/code&gt; -&amp;gt; &lt;code&gt;tuv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;9&lt;/code&gt; -&amp;gt; &lt;code&gt;wxyz&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Note: &lt;code&gt;1&lt;/code&gt; doesn't map to any letters in this problem, just like on actual keypads for letters.)&lt;/p&gt;

&lt;p&gt;The problem asks us to take a string of digits (e.g., &lt;code&gt;"23"&lt;/code&gt;) and return &lt;em&gt;all possible letter combinations&lt;/em&gt; that these digits could represent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1: &lt;code&gt;digits = "23"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;2&lt;/code&gt; maps to &lt;code&gt;a, b, c&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;3&lt;/code&gt; maps to &lt;code&gt;d, e, f&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we combine them, we get:&lt;br&gt;
&lt;code&gt;ad&lt;/code&gt;, &lt;code&gt;ae&lt;/code&gt;, &lt;code&gt;af&lt;/code&gt;&lt;br&gt;
&lt;code&gt;bd&lt;/code&gt;, &lt;code&gt;be&lt;/code&gt;, &lt;code&gt;bf&lt;/code&gt;&lt;br&gt;
&lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;ce&lt;/code&gt;, &lt;code&gt;cf&lt;/code&gt;&lt;br&gt;
Output: &lt;code&gt;["ad","ae","af","bd","be","bf","cd","ce","cf"]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2: &lt;code&gt;digits = "2"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;2&lt;/code&gt; maps to &lt;code&gt;a, b, c&lt;/code&gt;
Output: &lt;code&gt;["a","b","c"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;  The input &lt;code&gt;digits&lt;/code&gt; string will have a length between 1 and 4.&lt;/li&gt;
&lt;li&gt;  Each character in &lt;code&gt;digits&lt;/code&gt; will be a digit from &lt;code&gt;'2'&lt;/code&gt; to &lt;code&gt;'9'&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These constraints are quite friendly, meaning we don't have to worry about huge inputs, which is great for our chosen approach!&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Intuition: Building Blocks and Choices
&lt;/h2&gt;

&lt;p&gt;How do we even begin to generate all these combinations? Let's think about &lt;code&gt;digits = "23"&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; We start with the first digit, &lt;code&gt;'2'&lt;/code&gt;. What are our choices? &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, or &lt;code&gt;c&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; Let's pick &lt;code&gt;'a'&lt;/code&gt;. Now, we move to the next digit, &lt;code&gt;'3'&lt;/code&gt;. What are our choices for &lt;code&gt;'3'&lt;/code&gt;? &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;e&lt;/code&gt;, or &lt;code&gt;f&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; If we picked &lt;code&gt;'a'&lt;/code&gt; and then &lt;code&gt;'d'&lt;/code&gt;, we get &lt;code&gt;"ad"&lt;/code&gt;. We've used all digits, so &lt;code&gt;"ad"&lt;/code&gt; is a valid combination!&lt;/li&gt;
&lt;li&gt; But what if after &lt;code&gt;'a'&lt;/code&gt;, we picked &lt;code&gt;'e'&lt;/code&gt;? We get &lt;code&gt;"ae"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; And then &lt;code&gt;'f'&lt;/code&gt;? We get &lt;code&gt;"af"&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice a pattern? For each digit, we explore all its possible letters. This sounds a lot like building a tree of choices!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Level 0 (Start):&lt;/strong&gt; Empty string&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Level 1 (Digit '2'):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Choose 'a'&lt;/li&gt;
&lt;li&gt;  Choose 'b'&lt;/li&gt;
&lt;li&gt;  Choose 'c'&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Level 2 (Digit '3'):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  If 'a' was chosen, then choose 'd', 'e', 'f'&lt;/li&gt;
&lt;li&gt;  If 'b' was chosen, then choose 'd', 'e', 'f'&lt;/li&gt;
&lt;li&gt;  If 'c' was chosen, then choose 'd', 'e', 'f'&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This "explore all possibilities" and then "build up the result" is the core idea behind &lt;strong&gt;backtracking&lt;/strong&gt; (or recursion).&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Approach: The Backtracking Magic ✨
&lt;/h2&gt;

&lt;p&gt;Backtracking is essentially a refined brute-force approach. You systematically try every possible path to find a solution. If a path doesn't lead to a solution (or leads to an invalid one), you "backtrack" (undo your last choice) and try another path.&lt;/p&gt;

&lt;p&gt;For this problem, we'll use a recursive function:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mapping:&lt;/strong&gt; First, we need a way to quickly look up letters for each digit. A dictionary (or hash map) is perfect for this.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;digit_to_letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;abc&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;def&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ghi&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;jkl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;6&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mno&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;7&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pqrs&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tuv&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wxyz&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;The Recursive Helper Function (&lt;code&gt;backtrack&lt;/code&gt;):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It will take two main arguments:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;idx&lt;/code&gt;: The index of the digit we are currently processing in the input &lt;code&gt;digits&lt;/code&gt; string.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;current_combination&lt;/code&gt;: The string built so far.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  It also needs access to &lt;code&gt;digits&lt;/code&gt; (the input string) and &lt;code&gt;res&lt;/code&gt; (the list where we'll store our final combinations).&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Base Case:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  When do we know we've formed a complete combination? When &lt;code&gt;idx&lt;/code&gt; (our current digit index) reaches the &lt;code&gt;len(digits)&lt;/code&gt;. This means we've processed all the digits.&lt;/li&gt;
&lt;li&gt;  At this point, we add our &lt;code&gt;current_combination&lt;/code&gt; to our &lt;code&gt;res&lt;/code&gt; list and &lt;code&gt;return&lt;/code&gt; (stop this path of recursion).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Recursive Step:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Get the &lt;code&gt;current_digit&lt;/code&gt; using &lt;code&gt;digits[idx]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Look up its corresponding &lt;code&gt;letters&lt;/code&gt; using our &lt;code&gt;digit_to_letters&lt;/code&gt; map.&lt;/li&gt;
&lt;li&gt;  Now, iterate through &lt;em&gt;each&lt;/em&gt; &lt;code&gt;letter&lt;/code&gt; in these &lt;code&gt;letters&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;  For each &lt;code&gt;letter&lt;/code&gt;, we make a choice: append it to our &lt;code&gt;current_combination&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Then, we make a &lt;strong&gt;recursive call&lt;/strong&gt; to &lt;code&gt;backtrack&lt;/code&gt;, moving to the &lt;code&gt;next digit&lt;/code&gt; (&lt;code&gt;idx + 1&lt;/code&gt;) and passing our &lt;code&gt;updated combination&lt;/code&gt; (&lt;code&gt;current_combination + letter&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  Crucially, when the recursive call returns, because we are passing new strings (&lt;code&gt;current_combination + letter&lt;/code&gt;), Python handles the "backtracking" part automatically. The &lt;code&gt;current_combination&lt;/code&gt; in the &lt;em&gt;current&lt;/em&gt; function call remains unchanged for the &lt;em&gt;next&lt;/em&gt; iteration of the loop, allowing us to explore other choices from the &lt;code&gt;current_digit&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Let's trace &lt;code&gt;digits = "23"&lt;/code&gt; again with this logic:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backtrack(0, "")&lt;/code&gt;&lt;br&gt;
    &lt;code&gt;idx = 0&lt;/code&gt;, &lt;code&gt;current_combination = ""&lt;/code&gt;&lt;br&gt;
    &lt;code&gt;current_digit = '2'&lt;/code&gt;, &lt;code&gt;letters = "abc"&lt;/code&gt;&lt;br&gt;
    *   &lt;strong&gt;Loop for 'a':&lt;/strong&gt;&lt;br&gt;
        &lt;code&gt;backtrack(1, "a")&lt;/code&gt;&lt;br&gt;
            &lt;code&gt;idx = 1&lt;/code&gt;, &lt;code&gt;current_combination = "a"&lt;/code&gt;&lt;br&gt;
            &lt;code&gt;current_digit = '3'&lt;/code&gt;, &lt;code&gt;letters = "def"&lt;/code&gt;&lt;br&gt;
            *   &lt;strong&gt;Loop for 'd':&lt;/strong&gt;&lt;br&gt;
                &lt;code&gt;backtrack(2, "ad")&lt;/code&gt;&lt;br&gt;
                    &lt;code&gt;idx = 2&lt;/code&gt;, &lt;code&gt;len(digits) = 2&lt;/code&gt;. &lt;code&gt;idx == len(digits)&lt;/code&gt; is TRUE.&lt;br&gt;
                    &lt;code&gt;res.append("ad")&lt;/code&gt;&lt;br&gt;
                    &lt;code&gt;return&lt;/code&gt;&lt;br&gt;
            *   &lt;strong&gt;Loop for 'e':&lt;/strong&gt;&lt;br&gt;
                &lt;code&gt;backtrack(2, "ae")&lt;/code&gt;&lt;br&gt;
                    &lt;code&gt;idx = 2&lt;/code&gt;. &lt;code&gt;res.append("ae")&lt;/code&gt;. &lt;code&gt;return&lt;/code&gt;&lt;br&gt;
            *   &lt;strong&gt;Loop for 'f':&lt;/strong&gt;&lt;br&gt;
                &lt;code&gt;backtrack(2, "af")&lt;/code&gt;. &lt;code&gt;res.append("af")&lt;/code&gt;. &lt;code&gt;return&lt;/code&gt;&lt;br&gt;
            &lt;code&gt;return&lt;/code&gt; (from &lt;code&gt;backtrack(1, "a")&lt;/code&gt;)&lt;br&gt;
    *   &lt;strong&gt;Loop for 'b':&lt;/strong&gt;&lt;br&gt;
        &lt;code&gt;backtrack(1, "b")&lt;/code&gt;&lt;br&gt;
            ... (similar process for "bd", "be", "bf") ...&lt;br&gt;
            &lt;code&gt;return&lt;/code&gt;&lt;br&gt;
    *   &lt;strong&gt;Loop for 'c':&lt;/strong&gt;&lt;br&gt;
        &lt;code&gt;backtrack(1, "c")&lt;/code&gt;&lt;br&gt;
            ... (similar process for "cd", "ce", "cf") ...&lt;br&gt;
            &lt;code&gt;return&lt;/code&gt;&lt;br&gt;
&lt;code&gt;return res&lt;/code&gt; (from initial call)&lt;/p&gt;

&lt;p&gt;This methodical exploration ensures we hit every single possible combination!&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Code
&lt;/h2&gt;

&lt;p&gt;Here's the Python implementation based on our backtracking approach:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&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;letterCombinations&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;digits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="c1"&gt;# Handle the edge case where the input is an empty string
&lt;/span&gt;        &lt;span class="c1"&gt;# Although constraints say 1 &amp;lt;= digits.length, it's good practice.
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;digits&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="c1"&gt;# Mapping of digits to letters
&lt;/span&gt;        &lt;span class="n"&gt;digit_to_letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;abc&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;def&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ghi&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;jkl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;6&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mno&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;7&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pqrs&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tuv&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wxyz&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# This list will store all the final combinations
&lt;/span&gt;        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="c1"&gt;# The backtracking recursive helper function
&lt;/span&gt;        &lt;span class="c1"&gt;# idx: current digit index we are processing
&lt;/span&gt;        &lt;span class="c1"&gt;# current_combination: the string built so far
&lt;/span&gt;        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idx&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;current_combination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="c1"&gt;# Base case: If we have processed all digits
&lt;/span&gt;            &lt;span class="c1"&gt;# The length of our current_combination should be equal to the
&lt;/span&gt;            &lt;span class="c1"&gt;# total number of digits in the input.
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;idx&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;digits&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;res&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;current_combination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

            &lt;span class="c1"&gt;# Get the current digit and its corresponding letters
&lt;/span&gt;            &lt;span class="n"&gt;current_digit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;digit_to_letters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;current_digit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="c1"&gt;# Iterate through each letter for the current digit
&lt;/span&gt;            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;letter&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;letters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Make a choice: append the letter to our combination
&lt;/span&gt;                &lt;span class="c1"&gt;# Then, recursively call backtrack for the next digit
&lt;/span&gt;                &lt;span class="c1"&gt;# with the updated combination.
&lt;/span&gt;                &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idx&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;current_combination&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Start the backtracking process from the first digit (index 0)
&lt;/span&gt;        &lt;span class="c1"&gt;# with an empty initial combination string.
&lt;/span&gt;        &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Time &amp;amp; Space Complexity Analysis
&lt;/h2&gt;

&lt;p&gt;Let &lt;code&gt;N&lt;/code&gt; be the length of the input &lt;code&gt;digits&lt;/code&gt; string.&lt;br&gt;
Let &lt;code&gt;M&lt;/code&gt; be the maximum number of letters a digit can map to (which is 4 for '7' and '9', and 3 for others).&lt;/p&gt;

&lt;h3&gt;
  
  
  Time Complexity: &lt;code&gt;O(M^N * N)&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  In the worst case, each digit can map to &lt;code&gt;M&lt;/code&gt; (approximately 4) letters.&lt;/li&gt;
&lt;li&gt;  Since we have &lt;code&gt;N&lt;/code&gt; digits, and for each digit, we explore &lt;code&gt;M&lt;/code&gt; choices, the total number of combinations generated will be roughly &lt;code&gt;M^N&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;  For &lt;code&gt;digits = "23"&lt;/code&gt;, &lt;code&gt;N=2&lt;/code&gt;, &lt;code&gt;M=3&lt;/code&gt; (avg). Combinations: &lt;code&gt;3 * 3 = 9&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  For &lt;code&gt;digits = "79"&lt;/code&gt;, &lt;code&gt;N=2&lt;/code&gt;, &lt;code&gt;M=4&lt;/code&gt;. Combinations: &lt;code&gt;4 * 4 = 16&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  For each combination, we are building a string of length &lt;code&gt;N&lt;/code&gt;. Appending characters to a string (or concatenating strings) in Python takes &lt;code&gt;O(length_of_new_string)&lt;/code&gt; time. In our case, &lt;code&gt;current_combination + letter&lt;/code&gt; creates a new string.&lt;/li&gt;

&lt;li&gt;  Therefore, generating each of the &lt;code&gt;M^N&lt;/code&gt; combinations takes &lt;code&gt;O(N)&lt;/code&gt; time.&lt;/li&gt;

&lt;li&gt;  Total time complexity: &lt;code&gt;O(M^N * N)&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Given &lt;code&gt;N&lt;/code&gt; is very small (max 4), this &lt;code&gt;M^N * N&lt;/code&gt; complexity is perfectly acceptable. For &lt;code&gt;N=4&lt;/code&gt; and &lt;code&gt;M=4&lt;/code&gt;, &lt;code&gt;4^4 * 4 = 256 * 4 = 1024&lt;/code&gt; operations, which is incredibly fast!&lt;/p&gt;

&lt;h3&gt;
  
  
  Space Complexity: &lt;code&gt;O(M^N * N)&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Recursion Stack Space:&lt;/strong&gt; The maximum depth of the recursion is &lt;code&gt;N&lt;/code&gt; (one call for each digit). So, the space for the call stack is &lt;code&gt;O(N)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Result Storage:&lt;/strong&gt; We store all the generated combinations in the &lt;code&gt;res&lt;/code&gt; list.

&lt;ul&gt;
&lt;li&gt;  There are &lt;code&gt;M^N&lt;/code&gt; total combinations.&lt;/li&gt;
&lt;li&gt;  Each combination string has a length of &lt;code&gt;N&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Therefore, the space required to store the results is &lt;code&gt;O(M^N * N)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Combining these, the dominant factor is storing the results, so the overall space complexity is &lt;code&gt;O(M^N * N)&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Backtracking for Combinations:&lt;/strong&gt; This problem is a classic example of when to use backtracking. Whenever you need to find &lt;em&gt;all possible combinations&lt;/em&gt; or &lt;em&gt;all possible paths&lt;/em&gt; by making a series of choices, backtracking is your go-to.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Recursive Structure:&lt;/strong&gt; Backtracking problems are inherently recursive. Identify your:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Base Case:&lt;/strong&gt; When do you stop recursing and record a result? (Here: when &lt;code&gt;idx == len(digits)&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Recursive Step:&lt;/strong&gt; How do you make a choice, recurse, and then potentially undo/try another choice? (Here: loop through letters, append, recurse).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;State Management:&lt;/strong&gt; Pay attention to how you pass and update your &lt;code&gt;current_combination&lt;/code&gt;. In Python, string concatenation (&lt;code&gt;+&lt;/code&gt;) creates new strings, which simplifies "undoing" (as the previous string state remains intact in the caller's scope).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Mapping:&lt;/strong&gt; Using a dictionary (&lt;code&gt;digit_to_letters&lt;/code&gt;) for quick lookups is efficient and clean.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Complexity:&lt;/strong&gt; While backtracking can look exponential (&lt;code&gt;M^N&lt;/code&gt;), it's often the nature of combinatoric problems. Always check constraints (&lt;code&gt;N&lt;/code&gt; up to 4 here) to ensure your exponential solution is feasible.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  8. Submission Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Author Account:&lt;/strong&gt; p1Hzd8mRM8&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Publishing Time:&lt;/strong&gt; 2026-05-31 22:35:29&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This problem is an excellent stepping stone for understanding more complex backtracking problems like N-Queens, Sudoku Solver, or Permutations. Master this one, and you're well on your way! Keep coding and happy problem-solving! 🥳&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 15. 3Sum</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Sun, 31 May 2026 16:53:35 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-15-3sum-558p</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-15-3sum-558p</guid>
      <description>&lt;h1&gt;
  
  
  Cracking the Code: Solving LeetCode's 3Sum Problem with Two Pointers 🟡 Medium
&lt;/h1&gt;

&lt;p&gt;Hey there, fellow coders! 👋 Today, we're diving into a classic LeetCode problem that might seem daunting at first glance but becomes a satisfying puzzle with the right approach: &lt;strong&gt;15. 3Sum&lt;/strong&gt;. It's a fantastic problem to sharpen your problem-solving skills, especially with arrays and pointers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Explanation
&lt;/h2&gt;

&lt;p&gt;We're given an array of integers, &lt;code&gt;nums&lt;/code&gt;. Our mission is to find all unique triplets &lt;code&gt;[nums[i], nums[j], nums[k]]&lt;/code&gt; such that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, and &lt;code&gt;k&lt;/code&gt; are distinct indices (meaning &lt;code&gt;i != j&lt;/code&gt;, &lt;code&gt;i != k&lt;/code&gt;, and &lt;code&gt;j != k&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; The sum of the three numbers &lt;code&gt;nums[i] + nums[j] + nums[k]&lt;/code&gt; equals zero.&lt;/li&gt;
&lt;li&gt; The final solution set must &lt;em&gt;not&lt;/em&gt; contain duplicate triplets. For example, &lt;code&gt;[-1, 0, 1]&lt;/code&gt; and &lt;code&gt;[0, -1, 1]&lt;/code&gt; are considered the same triplet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's look at an example:&lt;/p&gt;

&lt;p&gt;Input: &lt;code&gt;nums = [-1,0,1,2,-1,-4]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, we need to find three numbers that add up to 0. Some possibilities are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;(-1) + 0 + 1 = 0&lt;/code&gt; (indices &lt;code&gt;0, 1, 2&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;(-1) + 2 + (-1) = 0&lt;/code&gt; (indices &lt;code&gt;0, 3, 4&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The distinct triplets in the output would be &lt;code&gt;[[-1,-1,2], [-1,0,1]]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Constraints are also important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The array will have between 3 and 3000 elements.&lt;/li&gt;
&lt;li&gt;  Numbers range from -10^5 to 10^5.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intuition
&lt;/h2&gt;

&lt;p&gt;First thoughts often lead to brute force: three nested loops to check every possible combination of &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, and &lt;code&gt;k&lt;/code&gt;. This would be an &lt;code&gt;O(N^3)&lt;/code&gt; solution, which is usually too slow for arrays up to 3000 elements (&lt;code&gt;3000^3&lt;/code&gt; is huge!). We need a smarter way.&lt;/p&gt;

&lt;p&gt;What if we could fix one number and then find two others? This reminds us of the "Two Sum" problem! If we fix &lt;code&gt;nums[i]&lt;/code&gt;, we then need to find two other numbers, &lt;code&gt;nums[j]&lt;/code&gt; and &lt;code&gt;nums[k]&lt;/code&gt;, such that &lt;code&gt;nums[j] + nums[k] = -nums[i]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How can we efficiently find two numbers that sum to a target? This is where &lt;strong&gt;sorting&lt;/strong&gt; and the &lt;strong&gt;Two-Pointer technique&lt;/strong&gt; shine!&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;Here's the step-by-step breakdown of an efficient approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sort the Array:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  This is the cornerstone. Sorting &lt;code&gt;nums&lt;/code&gt; allows us to easily move pointers and efficiently skip duplicate numbers. It also makes it simple to adjust our sum (if it's too small, increase a number; if too large, decrease a number).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iterate and Fix the First Element (&lt;code&gt;nums[i]&lt;/code&gt;):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We'll use a single loop (&lt;code&gt;for i in range(n)&lt;/code&gt;) to pick the first number of our potential triplet.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Skip Duplicates for &lt;code&gt;nums[i]&lt;/code&gt;:&lt;/strong&gt; Since we want unique triplets, if &lt;code&gt;nums[i]&lt;/code&gt; is the same as the previous &lt;code&gt;nums[i-1]&lt;/code&gt;, we've already considered all triplets starting with &lt;code&gt;nums[i-1]&lt;/code&gt;. So, we can &lt;code&gt;continue&lt;/code&gt; to the next &lt;code&gt;i&lt;/code&gt;. This is crucial for avoiding duplicate triplets like &lt;code&gt;[-1, 0, 1]&lt;/code&gt; and &lt;code&gt;[-1, 0, 1]&lt;/code&gt; if &lt;code&gt;-1&lt;/code&gt; appears multiple times at the start of the array.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the Two-Pointer Technique for the Remaining Two Elements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Once &lt;code&gt;nums[i]&lt;/code&gt; is fixed, our target sum for the remaining two numbers &lt;code&gt;nums[j]&lt;/code&gt; and &lt;code&gt;nums[k]&lt;/code&gt; becomes &lt;code&gt;target = -nums[i]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Initialize two pointers: &lt;code&gt;j&lt;/code&gt; starting at &lt;code&gt;i + 1&lt;/code&gt; (the element right after &lt;code&gt;nums[i]&lt;/code&gt;) and &lt;code&gt;k&lt;/code&gt; starting at &lt;code&gt;n - 1&lt;/code&gt; (the last element of the array).&lt;/li&gt;
&lt;li&gt;  Enter a &lt;code&gt;while j &amp;lt; k&lt;/code&gt; loop:

&lt;ul&gt;
&lt;li&gt;  Calculate the &lt;code&gt;current_sum = nums[j] + nums[k]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;If &lt;code&gt;current_sum &amp;lt; target&lt;/code&gt;&lt;/strong&gt;: The sum is too small. To increase the sum, we need a larger number. Since the array is sorted, increment &lt;code&gt;j&lt;/code&gt; (move the left pointer to the right).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;If &lt;code&gt;current_sum &amp;gt; target&lt;/code&gt;&lt;/strong&gt;: The sum is too large. To decrease the sum, we need a smaller number. Decrement &lt;code&gt;k&lt;/code&gt; (move the right pointer to the left).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;If &lt;code&gt;current_sum == target&lt;/code&gt;&lt;/strong&gt;: We found a triplet! &lt;code&gt;[nums[i], nums[j], nums[k]]&lt;/code&gt;. Add it to our &lt;code&gt;ans&lt;/code&gt; list.

&lt;ul&gt;
&lt;li&gt;  Then, we need to move &lt;em&gt;both&lt;/em&gt; pointers to find other potential triplets. Increment &lt;code&gt;j&lt;/code&gt; and decrement &lt;code&gt;k&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Skip Duplicates for &lt;code&gt;nums[j]&lt;/code&gt; and &lt;code&gt;nums[k]&lt;/code&gt;&lt;/strong&gt;: After finding a valid triplet, &lt;code&gt;nums[j]&lt;/code&gt; and &lt;code&gt;nums[k]&lt;/code&gt; might have duplicates. To ensure unique triplets, we need to advance &lt;code&gt;j&lt;/code&gt; as long as &lt;code&gt;nums[j]&lt;/code&gt; is equal to the previous &lt;code&gt;nums[j-1]&lt;/code&gt;, and similarly for &lt;code&gt;k&lt;/code&gt; (as long as &lt;code&gt;nums[k]&lt;/code&gt; is equal to &lt;code&gt;nums[k+1]&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This combined strategy transforms an &lt;code&gt;O(N^3)&lt;/code&gt; brute force into a much more efficient &lt;code&gt;O(N^2)&lt;/code&gt; solution!&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&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;threeSum&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="nb"&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;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&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;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;n&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;nums&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="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Step 1: Sort the array
&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="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# Step 2: Iterate fixing the first element
&lt;/span&gt;            &lt;span class="c1"&gt;# Skip duplicate for the first element
&lt;/span&gt;            &lt;span class="c1"&gt;# We check i &amp;gt; 0 to avoid index out of bounds on the first element
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&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;nums&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="k"&gt;continue&lt;/span&gt;

            &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&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="c1"&gt;# Left pointer starts after i
&lt;/span&gt;            &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&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 of the array
&lt;/span&gt;
            &lt;span class="c1"&gt;# Step 3: Two-pointer approach
&lt;/span&gt;            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;total_sum&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;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;nums&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;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&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;total_sum&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&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="c1"&gt;# Need a larger sum, move left pointer right
&lt;/span&gt;                &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;total_sum&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;k&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;# Need a smaller sum, move right pointer left
&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;# total_sum == 0, found a triplet!
&lt;/span&gt;                    &lt;span class="n"&gt;ans&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;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="n"&gt;nums&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="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;

                    &lt;span class="c1"&gt;# Move pointers and skip duplicates for j and k
&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="n"&gt;k&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;# Skip duplicates for j
&lt;/span&gt;                    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;and&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;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;nums&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="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="c1"&gt;# Skip duplicates for k
&lt;/span&gt;                    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;and&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;k&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;k&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;k&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="n"&gt;ans&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time &amp;amp; Space Complexity Analysis
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time Complexity:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Sorting the array&lt;/strong&gt;: This takes &lt;code&gt;O(N log N)&lt;/code&gt; time.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Outer loop (&lt;code&gt;for i&lt;/code&gt;):&lt;/strong&gt; This loop runs &lt;code&gt;N&lt;/code&gt; times.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Inner &lt;code&gt;while&lt;/code&gt; loop (Two Pointers &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt;):&lt;/strong&gt; In the worst case, the &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; pointers traverse the remaining array once for each &lt;code&gt;i&lt;/code&gt;. This takes &lt;code&gt;O(N)&lt;/code&gt; time.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Skipping duplicates:&lt;/strong&gt; These &lt;code&gt;while&lt;/code&gt; loops also run at most &lt;code&gt;N&lt;/code&gt; times in total across all &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; movements for a fixed &lt;code&gt;i&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Combining these, the dominant part is &lt;code&gt;N&lt;/code&gt; (for &lt;code&gt;i&lt;/code&gt;) multiplied by &lt;code&gt;N&lt;/code&gt; (for &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; traversal), which is &lt;code&gt;O(N^2)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Therefore, the total time complexity is &lt;code&gt;O(N log N + N^2)&lt;/code&gt;, which simplifies to &lt;strong&gt;O(N^2)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Sorting:&lt;/strong&gt; Python's &lt;code&gt;list.sort()&lt;/code&gt; typically uses Timsort, which can take &lt;code&gt;O(N)&lt;/code&gt; auxiliary space in the worst case (though often less). If we consider the algorithm itself beyond the standard library sort implementation, an in-place sort would be &lt;code&gt;O(1)&lt;/code&gt; auxiliary space.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Result list (&lt;code&gt;ans&lt;/code&gt;):&lt;/strong&gt; The space required to store the output triplets depends on the number of unique triplets. In the worst case, this could be &lt;code&gt;O(N^2)&lt;/code&gt;. However, typically, when we talk about space complexity, we're referring to &lt;em&gt;auxiliary&lt;/em&gt; space used by the algorithm, not including the input or the required output.&lt;/li&gt;
&lt;li&gt;  Excluding the output, the auxiliary space complexity is primarily due to sorting, which is &lt;strong&gt;O(N)&lt;/strong&gt; for Python's default sort, or &lt;code&gt;O(log N)&lt;/code&gt; for certain in-place sorts.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Sort First!&lt;/strong&gt; For many array problems involving searching for combinations or manipulating relative order, sorting is often the key preprocessing step.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Two Pointers for Sorted Arrays:&lt;/strong&gt; This technique is a workhorse! It efficiently finds pairs or helps reduce search space in sorted arrays.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Handle Duplicates Carefully:&lt;/strong&gt; Unique results often mean adding extra checks to skip elements that would lead to redundant calculations or duplicate outputs. This is a common pitfall in these types of problems.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Submission Details
&lt;/h2&gt;

&lt;p&gt;Authored by: p1Hzd8mRM8&lt;br&gt;
Published: 2026-05-31 22:23:04&lt;/p&gt;

&lt;p&gt;That's it for 3Sum! This problem is a fantastic way to practice combining sorting with the two-pointer technique and mastering duplicate handling. Keep coding, and happy problem-solving! ✨&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 13. Roman to Integer</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Thu, 21 May 2026 11:37:46 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-13-roman-to-integer-3ne5</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-13-roman-to-integer-3ne5</guid>
      <description>&lt;h1&gt;
  
  
  How to Conquer Roman Numerals: LeetCode #13 Explained Simply!
&lt;/h1&gt;

&lt;p&gt;Hey there, future coding superstar! 👋 Ever looked at Roman numerals and thought, "That's a cool system, but how would I code that conversion?" Today, we're diving into LeetCode problem #13, "Roman to Integer," a fantastic problem for beginners that teaches some core programming concepts.&lt;/p&gt;

&lt;p&gt;Let's unravel this ancient number system together and turn it into elegant Python code!&lt;/p&gt;




&lt;h2&gt;
  
  
  The Roman Numeral Mystery (Problem Explanation)
&lt;/h2&gt;

&lt;p&gt;Roman numerals use a set of seven symbols:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;I&lt;/code&gt; = 1&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;V&lt;/code&gt; = 5&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;X&lt;/code&gt; = 10&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;L&lt;/code&gt; = 50&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;C&lt;/code&gt; = 100&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;D&lt;/code&gt; = 500&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;M&lt;/code&gt; = 1000&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usually, they're written from largest value to smallest, and you just add them up. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;II&lt;/code&gt; = 1 + 1 = 2&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;XII&lt;/code&gt; = 10 + 1 + 1 = 12&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;XXVII&lt;/code&gt; = 10 + 10 + 5 + 1 + 1 = 27&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds simple, right? But here's the twist! There are &lt;strong&gt;six special cases&lt;/strong&gt; where a smaller numeral comes &lt;em&gt;before&lt;/em&gt; a larger one, and instead of adding, you &lt;strong&gt;subtract&lt;/strong&gt; it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;IV&lt;/code&gt; = 4 (5 - 1)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;IX&lt;/code&gt; = 9 (10 - 1)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;XL&lt;/code&gt; = 40 (50 - 10)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;XC&lt;/code&gt; = 90 (100 - 10)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;CD&lt;/code&gt; = 400 (500 - 100)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;CM&lt;/code&gt; = 900 (1000 - 100)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, your task is to take a Roman numeral string (like "MCMXCIV") and convert it into its integer equivalent (like 1994). The input string is guaranteed to be a valid Roman numeral within a certain range.&lt;/p&gt;

&lt;p&gt;Let's look at an example to clarify:&lt;br&gt;
&lt;strong&gt;Input:&lt;/strong&gt; &lt;code&gt;s = "MCMXCIV"&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;1994&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;M&lt;/code&gt; = 1000&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;CM&lt;/code&gt; = 900 (C before M means 1000 - 100)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;XC&lt;/code&gt; = 90 (X before C means 100 - 10)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;IV&lt;/code&gt; = 4 (I before V means 5 - 1)
Total: 1000 + 900 + 90 + 4 = 1994&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The "Aha!" Moment (Intuition)
&lt;/h2&gt;

&lt;p&gt;The core challenge is handling those subtraction cases (&lt;code&gt;IV&lt;/code&gt;, &lt;code&gt;IX&lt;/code&gt;, etc.). How do we know whether to add or subtract a symbol's value?&lt;/p&gt;

&lt;p&gt;Think about it: when you see &lt;code&gt;IV&lt;/code&gt;, you process &lt;code&gt;I&lt;/code&gt; and then &lt;code&gt;V&lt;/code&gt;. The &lt;code&gt;I&lt;/code&gt; isn't added directly because it's followed by a &lt;em&gt;larger&lt;/em&gt; value (&lt;code&gt;V&lt;/code&gt;). If it was &lt;code&gt;III&lt;/code&gt;, each &lt;code&gt;I&lt;/code&gt; would be added because it's followed by a &lt;em&gt;smaller or equal&lt;/em&gt; value (&lt;code&gt;I&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;This gives us a huge hint: &lt;strong&gt;we need to look at the next character!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If the current symbol's value is &lt;strong&gt;less than&lt;/strong&gt; the next symbol's value, it's a subtraction case. We should subtract the current symbol's value.&lt;/li&gt;
&lt;li&gt;  Otherwise (if the current symbol's value is greater than or equal to the next symbol's value), it's a standard addition case. We should add the current symbol's value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This "look ahead" strategy is the key to solving this problem efficiently!&lt;/p&gt;


&lt;h2&gt;
  
  
  Your Step-by-Step Guide (Approach)
&lt;/h2&gt;

&lt;p&gt;Let's break down how we can implement this "look ahead" strategy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Lookup Table:&lt;/strong&gt; First things first, we need an easy way to get the integer value for each Roman symbol. A dictionary (or hash map) is perfect for this! It maps each Roman character to its integer value (&lt;code&gt;'I': 1&lt;/code&gt;, &lt;code&gt;'V': 5&lt;/code&gt;, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initialize Result:&lt;/strong&gt; We'll need a variable, let's call it &lt;code&gt;result&lt;/code&gt;, to keep a running total of our integer conversion. Start it at &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iterate with a "Look Ahead":&lt;/strong&gt; We'll loop through the Roman numeral string. However, since we need to compare the current character with the &lt;em&gt;next&lt;/em&gt; one, we should stop our loop one character before the end of the string.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  For each pair of &lt;code&gt;(current_char, next_char)&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;  Look up &lt;code&gt;current_char&lt;/code&gt;'s value (&lt;code&gt;val_current&lt;/code&gt;) in our dictionary.&lt;/li&gt;
&lt;li&gt;  Look up &lt;code&gt;next_char&lt;/code&gt;'s value (&lt;code&gt;val_next&lt;/code&gt;) in our dictionary.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Condition Check:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;val_current &amp;lt; val_next&lt;/code&gt; (e.g., 'I' is 1, 'V' is 5, so 1 &amp;lt; 5): This is a subtraction case! Add &lt;code&gt;-val_current&lt;/code&gt; to our &lt;code&gt;result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Else (&lt;code&gt;val_current &amp;gt;= val_next&lt;/code&gt;): This is an addition case! Add &lt;code&gt;val_current&lt;/code&gt; to our &lt;code&gt;result&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handle the Last Character:&lt;/strong&gt; Our loop stops one character before the end. This means the very last character in the string was never compared as a &lt;code&gt;current_char&lt;/code&gt; to a &lt;code&gt;next_char&lt;/code&gt;. Since a last character can &lt;em&gt;never&lt;/em&gt; be part of a subtraction pair (it has no character &lt;em&gt;after&lt;/em&gt; it), its value is &lt;strong&gt;always added&lt;/strong&gt;. So, after the loop, we simply add the value of the &lt;code&gt;last_char&lt;/code&gt; to our &lt;code&gt;result&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Return:&lt;/strong&gt; Finally, &lt;code&gt;result&lt;/code&gt; holds the complete integer conversion. Return it!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  The Code (Python)
&lt;/h2&gt;

&lt;p&gt;Here's the Python solution based on our approach:&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;romanToInt&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;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;res&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;# Initialize our result accumulator
&lt;/span&gt;
        &lt;span class="c1"&gt;# Our handy lookup table for Roman symbols to integer values
&lt;/span&gt;        &lt;span class="n"&gt;roman_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;I&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;V&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;X&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;L&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;C&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;D&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;M&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# Iterate through the string, comparing current character (a) with the next (b)
&lt;/span&gt;        &lt;span class="c1"&gt;# The zip(s, s[1:]) trick cleverly creates pairs:
&lt;/span&gt;        &lt;span class="c1"&gt;# (s[0], s[1]), (s[1], s[2]), ..., (s[N-2], s[N-1])
&lt;/span&gt;        &lt;span class="c1"&gt;# This processes all pairs *except* for the very last character s[N-1]
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;current_char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&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="n"&gt;current_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;roman_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;current_char&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;next_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;roman_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_char&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_value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;next_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# If current value is smaller than next, it's a subtraction case (e.g., IV, IX)
&lt;/span&gt;                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;current_value&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;# Otherwise, it's a standard addition case (e.g., III, L)
&lt;/span&gt;                &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;current_value&lt;/span&gt;

        &lt;span class="c1"&gt;# After the loop, the value of the *last* character in the string
&lt;/span&gt;        &lt;span class="c1"&gt;# has not yet been added to `res`. It will always be an addition.
&lt;/span&gt;        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;roman_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&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="p"&gt;]]&lt;/span&gt; 

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Performance Check (Time &amp;amp; Space Complexity)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time Complexity: O(N)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We iterate through the input string &lt;code&gt;s&lt;/code&gt; once using the &lt;code&gt;zip&lt;/code&gt; function, which effectively processes each character pair. The length of the string is &lt;code&gt;N&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Looking up values in our &lt;code&gt;roman_map&lt;/code&gt; (a dictionary) takes &lt;code&gt;O(1)&lt;/code&gt; (constant time) on average.&lt;/li&gt;
&lt;li&gt;  Therefore, the total time complexity is directly proportional to the length of the input string.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We use a dictionary (&lt;code&gt;roman_map&lt;/code&gt;) to store the symbol-to-value mappings. This dictionary has a fixed size (7 entries), regardless of how long the input Roman numeral string &lt;code&gt;s&lt;/code&gt; is.&lt;/li&gt;
&lt;li&gt;  No other data structures are used that grow with the input size.&lt;/li&gt;
&lt;li&gt;  Thus, the auxiliary space used is constant.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Lookahead Pattern:&lt;/strong&gt; This problem is a classic example of when to use a "lookahead" pattern in string processing. By considering the &lt;em&gt;next&lt;/em&gt; element, you can make informed decisions about the &lt;em&gt;current&lt;/em&gt; element.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hash Maps/Dictionaries are Your Friends:&lt;/strong&gt; For quick lookups of values associated with specific keys (like Roman symbols to their integers), dictionaries are incredibly efficient and make your code clean.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Edge Cases Matter:&lt;/strong&gt; Always consider the beginning, middle, and end of your input. Here, the very last character needed special handling because our &lt;code&gt;zip&lt;/code&gt; iteration didn't include a "next" for it.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;That's it! You've successfully converted Roman numerals to integers using a clever approach. Keep practicing, and you'll be tackling even more complex problems in no time!&lt;/p&gt;




&lt;p&gt;Authored by: p1Hzd8mRM8&lt;br&gt;&lt;br&gt;
Published: 2026-05-21 17:07:27&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 12. Integer to Roman</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Thu, 21 May 2026 11:36:00 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-12-integer-to-roman-1eco</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-12-integer-to-roman-1eco</guid>
      <description>&lt;h1&gt;
  
  
  Unraveling the Mystery of Roman Numerals: A LeetCode Journey (Problem 12. Integer to Roman)
&lt;/h1&gt;

&lt;p&gt;Hey LeetCoders and aspiring developers! 👋 Today, we're taking a trip back in time to ancient Rome... well, almost! We're tackling LeetCode problem 12: "Integer to Roman." This problem asks us to convert a standard integer into its Roman numeral representation. It sounds simple, but Roman numerals have some quirky rules that make this a fun challenge. Let's dive in!&lt;/p&gt;




&lt;h2&gt;
  
  
  🧐 Problem Explanation: What are Roman Numerals Anyway?
&lt;/h2&gt;

&lt;p&gt;Roman numerals use a system of seven symbols, each representing a specific value:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The general idea is to build numbers by adding these symbols. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;II&lt;/code&gt; = 1 + 1 = 2&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;VI&lt;/code&gt; = 5 + 1 = 6&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;LX&lt;/code&gt; = 50 + 10 = 60&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;MCC&lt;/code&gt; = 1000 + 100 + 100 = 1200&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here's where it gets interesting – there are special "subtractive forms" for numbers that would otherwise require four repeated symbols or just sound clunky:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Subtractive Rule:&lt;/strong&gt; If a smaller value symbol appears &lt;em&gt;before&lt;/em&gt; a larger value symbol, it means subtraction.

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;IV&lt;/code&gt; = 5 - 1 = 4 (instead of &lt;code&gt;IIII&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;IX&lt;/code&gt; = 10 - 1 = 9 (instead of &lt;code&gt;VIIII&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;XL&lt;/code&gt; = 50 - 10 = 40&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;XC&lt;/code&gt; = 100 - 10 = 90&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;CD&lt;/code&gt; = 500 - 100 = 400&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;CM&lt;/code&gt; = 1000 - 100 = 900&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Crucially, the problem states that Roman numerals are formed by converting decimal place values from highest to lowest. This means when converting &lt;code&gt;3749&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You first convert &lt;code&gt;3000&lt;/code&gt; (MMM)&lt;/li&gt;
&lt;li&gt;  Then &lt;code&gt;700&lt;/code&gt; (DCC)&lt;/li&gt;
&lt;li&gt;  Then &lt;code&gt;40&lt;/code&gt; (XL)&lt;/li&gt;
&lt;li&gt;  Then &lt;code&gt;9&lt;/code&gt; (IX)&lt;/li&gt;
&lt;li&gt;  Combining them gives &lt;code&gt;MMMDCCXLIX&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can't do things like &lt;code&gt;IL&lt;/code&gt; for 49, because &lt;code&gt;I&lt;/code&gt; is not a decimal place lower than &lt;code&gt;L&lt;/code&gt; (which is in the tens place, &lt;code&gt;I&lt;/code&gt; is in the ones place). &lt;code&gt;49&lt;/code&gt; is &lt;code&gt;40&lt;/code&gt; (&lt;code&gt;XL&lt;/code&gt;) + &lt;code&gt;9&lt;/code&gt; (&lt;code&gt;IX&lt;/code&gt;). This "decimal place" rule is important for understanding the valid subtractive forms.&lt;/p&gt;

&lt;p&gt;Our task is to take an integer &lt;code&gt;num&lt;/code&gt; (between 1 and 3999) and return its Roman numeral string representation.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 Intuition: The "Aha!" Moment
&lt;/h2&gt;

&lt;p&gt;When I first look at this, my brain immediately thinks, "Okay, I need to figure out which Roman symbols make up the number." But with the additive and &lt;em&gt;especially&lt;/em&gt; the subtractive rules, a simple &lt;code&gt;if num &amp;gt;= value: add symbol&lt;/code&gt; loop might get complicated fast.&lt;/p&gt;

&lt;p&gt;The key insight comes from the combination of the specific rules and the examples:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Fixed Symbols &amp;amp; Values:&lt;/strong&gt; We have a known set of symbol-value pairs.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Greedy Approach:&lt;/strong&gt; We want to build the Roman numeral from left to right, which means processing the largest possible values first.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Subtractive Forms are Special:&lt;/strong&gt; &lt;code&gt;CM&lt;/code&gt; (900) is &lt;em&gt;one unit&lt;/em&gt; in the Roman system, not &lt;code&gt;D&lt;/code&gt; then &lt;code&gt;CCCC&lt;/code&gt;. Same for &lt;code&gt;CD&lt;/code&gt;, &lt;code&gt;XC&lt;/code&gt;, &lt;code&gt;XL&lt;/code&gt;, &lt;code&gt;IX&lt;/code&gt;, &lt;code&gt;IV&lt;/code&gt;. These special forms are essentially "preferred" over their additive counterparts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This leads to the "aha!" moment: If we create a list of &lt;em&gt;all valid Roman numeral values&lt;/em&gt;, including the subtractive forms, and sort them from largest to smallest, we can simply go through this list and greedily subtract the largest possible value from our input number until it becomes zero.&lt;/p&gt;

&lt;p&gt;For example, if &lt;code&gt;num = 900&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If we only considered &lt;code&gt;M=1000, D=500, C=100&lt;/code&gt;, we might try to use &lt;code&gt;D&lt;/code&gt; (500), leaving &lt;code&gt;400&lt;/code&gt;. Then try &lt;code&gt;C&lt;/code&gt; four times. This would be incorrect (&lt;code&gt;DCCCC&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  But if our list explicitly contains &lt;code&gt;(900, 'CM')&lt;/code&gt;, then &lt;code&gt;900&lt;/code&gt; would be matched directly, giving us &lt;code&gt;CM&lt;/code&gt; and the correct result.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✍️ Approach: Step-by-Step Greedy Conversion
&lt;/h2&gt;

&lt;p&gt;Based on our intuition, here's the plan:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a lookup table:&lt;/strong&gt; We'll define a list of tuples, where each tuple contains &lt;code&gt;(integer_value, roman_symbol_string)&lt;/code&gt;. This list is critical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It must include all standard symbols (&lt;code&gt;M&lt;/code&gt;, &lt;code&gt;D&lt;/code&gt;, &lt;code&gt;C&lt;/code&gt;, &lt;code&gt;L&lt;/code&gt;, &lt;code&gt;X&lt;/code&gt;, &lt;code&gt;V&lt;/code&gt;, &lt;code&gt;I&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  It &lt;em&gt;must&lt;/em&gt; also include the special subtractive forms (&lt;code&gt;CM&lt;/code&gt;, &lt;code&gt;CD&lt;/code&gt;, &lt;code&gt;XC&lt;/code&gt;, &lt;code&gt;XL&lt;/code&gt;, &lt;code&gt;IX&lt;/code&gt;, &lt;code&gt;IV&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Crucially, this list must be sorted in descending order of the integer values.&lt;/strong&gt; This ensures our greedy approach always picks the largest possible Roman numeral component first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our list will look something like this:&lt;br&gt;
&lt;code&gt;[(1000, 'M'), (900, 'CM'), (500, 'D'), (400, 'CD'), (100, 'C'), (90, 'XC'), (50, 'L'), (40, 'XL'), (10, 'X'), (9, 'IX'), (5, 'V'), (4, 'IV'), (1, 'I')]&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initialize result:&lt;/strong&gt; Start with an empty list or string to build our Roman numeral. A list is generally more efficient for appending in Python, then we'll join it at the end.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iterate and subtract:&lt;/strong&gt; Loop through our &lt;code&gt;value_symbols&lt;/code&gt; list (which is sorted largest to smallest):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  For each &lt;code&gt;(value, symbol)&lt;/code&gt; pair:

&lt;ul&gt;
&lt;li&gt;  Check how many times this &lt;code&gt;value&lt;/code&gt; can fit into our current &lt;code&gt;num&lt;/code&gt;. Let's call this &lt;code&gt;count&lt;/code&gt;. &lt;code&gt;count = num // value&lt;/code&gt; (integer division).&lt;/li&gt;
&lt;li&gt;  Append the &lt;code&gt;symbol&lt;/code&gt; repeated &lt;code&gt;count&lt;/code&gt; times to our result list. For example, if &lt;code&gt;num&lt;/code&gt; is 3000 and &lt;code&gt;value&lt;/code&gt; is 1000, &lt;code&gt;count&lt;/code&gt; will be 3, and we'll append "MMM".&lt;/li&gt;
&lt;li&gt;  Update &lt;code&gt;num&lt;/code&gt; by subtracting &lt;code&gt;count * value&lt;/code&gt; from it. This consumes the portion of the number we just converted.&lt;/li&gt;
&lt;li&gt;  We can add an early &lt;code&gt;break&lt;/code&gt; if &lt;code&gt;num&lt;/code&gt; becomes 0, as there's nothing left to convert.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Join and return:&lt;/strong&gt; Once the loop finishes, all parts of &lt;code&gt;num&lt;/code&gt; will have been converted. Join the elements in our result list into a single string and return it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's trace &lt;code&gt;num = 1994&lt;/code&gt; with this approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;code&gt;res = []&lt;/code&gt;, &lt;code&gt;num = 1994&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; &lt;code&gt;value_symbols&lt;/code&gt; list: &lt;code&gt;[(1000, 'M'), (900, 'CM'), ..., (1, 'I')]&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;value&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;symbol&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;num&lt;/code&gt; (start)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;count = num // value&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;res.append(symbol * count)&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;num -= count * value&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;num&lt;/code&gt; (end)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;'M'&lt;/td&gt;
&lt;td&gt;1994&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;res = ['M']&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1994 - 1000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;994&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;900&lt;/td&gt;
&lt;td&gt;'CM'&lt;/td&gt;
&lt;td&gt;994&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;res = ['M', 'CM']&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;994 - 900&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;'D'&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;'CD'&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;'C'&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;'XC'&lt;/td&gt;
&lt;td&gt;94&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;res = ['M', 'CM', 'XC']&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;94 - 90&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;'L'&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;'XL'&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;'X'&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;'IX'&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;'V'&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;'IV'&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;res = ['M', 'CM', 'XC', 'IV']&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4 - 4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;'I'&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;(break loop)&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Finally, &lt;code&gt;''.join(res)&lt;/code&gt; gives us &lt;code&gt;"MCMXCIV"&lt;/code&gt;, which is the correct answer! This greedy approach, combined with a carefully constructed and ordered lookup table, handles all the Roman numeral rules elegantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  💻 Code
&lt;/h2&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;intToRoman&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;num&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Define the Roman numeral values and their corresponding symbols.
&lt;/span&gt;        &lt;span class="c1"&gt;# This list is crucial: it must be sorted in descending order of values,
&lt;/span&gt;        &lt;span class="c1"&gt;# and include the special subtractive forms (like 900 for CM)
&lt;/span&gt;        &lt;span class="c1"&gt;# BEFORE their additive components (like 500 for D and 100 for C).
&lt;/span&gt;        &lt;span class="n"&gt;value_symbols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;M&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CM&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;D&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;C&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XC&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;L&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;XL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;X&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;IX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;V&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;IV&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Initialize an empty list to store the Roman numeral characters.
&lt;/span&gt;        &lt;span class="c1"&gt;# Appending to a list and then joining is generally more efficient
&lt;/span&gt;        &lt;span class="c1"&gt;# than repeated string concatenation in Python.
&lt;/span&gt;        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="c1"&gt;# Iterate through our defined value-symbol pairs.
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;value_symbols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# If num has become 0, we've converted the entire number,
&lt;/span&gt;            &lt;span class="c1"&gt;# so we can break early.
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;

            &lt;span class="c1"&gt;# Calculate how many times the current 'value' fits into 'num'.
&lt;/span&gt;            &lt;span class="c1"&gt;# E.g., if num = 3000 and value = 1000, count = 3.
&lt;/span&gt;            &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

            &lt;span class="c1"&gt;# Append the 'symbol' repeated 'count' times to our result list.
&lt;/span&gt;            &lt;span class="c1"&gt;# E.g., if count = 3 and symbol = 'M', it appends 'MMM'.
&lt;/span&gt;            &lt;span class="n"&gt;res&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;symbol&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Subtract the converted portion from num.
&lt;/span&gt;            &lt;span class="c1"&gt;# E.g., num = 3000 - (3 * 1000) = 0.
&lt;/span&gt;            &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

        &lt;span class="c1"&gt;# Join all the symbols in the list to form the final Roman numeral string.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⏱️ Time &amp;amp; Space Complexity Analysis
&lt;/h2&gt;

&lt;p&gt;Let's break down how efficient our solution is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time Complexity: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The &lt;code&gt;value_symbols&lt;/code&gt; list has a fixed size (13 elements).&lt;/li&gt;
&lt;li&gt;  We iterate through this list exactly once.&lt;/li&gt;
&lt;li&gt;  Inside the loop, operations like integer division (&lt;code&gt;//&lt;/code&gt;), multiplication (&lt;code&gt;*&lt;/code&gt;), list &lt;code&gt;append()&lt;/code&gt;, and subtraction (&lt;code&gt;-&lt;/code&gt;) take constant time. The string multiplication &lt;code&gt;symbol * count&lt;/code&gt; and &lt;code&gt;append&lt;/code&gt; are also bounded because the maximum &lt;code&gt;count&lt;/code&gt; is small (at most 3 for 'I', 'X', 'C', 'M') and the Roman numeral string's total length for &lt;code&gt;num &amp;lt;= 3999&lt;/code&gt; is very short (e.g., "MMMCMXCIX" for 3999 has 7 characters).&lt;/li&gt;
&lt;li&gt;  Since the number of iterations and the work done in each iteration are bounded by a constant (independent of the input &lt;code&gt;num&lt;/code&gt;'s magnitude, within the given constraints), the overall time complexity is constant.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The &lt;code&gt;value_symbols&lt;/code&gt; list is a fixed-size data structure (13 tuples), so it takes constant space.&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;res&lt;/code&gt; list stores the characters of the resulting Roman numeral string. The maximum length of a Roman numeral for an integer up to 3999 is also very small (e.g., "MMMCMXCIX" has 7 characters).&lt;/li&gt;
&lt;li&gt;  Therefore, the space used is bounded by a constant, leading to O(1) space complexity.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This solution is incredibly efficient because it leverages the fixed and relatively small nature of the Roman numeral system's rules and symbols.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Greedy Approach Power:&lt;/strong&gt; This problem is a classic example where a greedy approach shines. By always taking the largest possible valid Roman numeral component first, and ensuring your lookup table accounts for special cases (like subtractive forms) in the correct order, you can simplify complex rules.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Lookup Tables are Your Friend:&lt;/strong&gt; When dealing with predefined mappings or rules, a well-structured lookup table (like our &lt;code&gt;value_symbols&lt;/code&gt; list) can make your code much cleaner and easier to reason about than a series of nested &lt;code&gt;if/else&lt;/code&gt; statements.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Order Matters!&lt;/strong&gt; For greedy algorithms, the order of elements in your lookup table is paramount. Always ensure the largest values (including special combinations) come first.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Python String Efficiency:&lt;/strong&gt; Appending to a list and then using &lt;code&gt;''.join()&lt;/code&gt; is generally more efficient for building strings than repeated string concatenation (&lt;code&gt;+=&lt;/code&gt;) in Python, especially for potentially longer strings (though in this specific problem, the string length is so small that the difference would be negligible).&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;And there you have it! Converting integers to Roman numerals might seem tricky at first, but with a solid understanding of the rules and a well-designed greedy approach, it becomes quite straightforward.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Author Account: p1Hzd8mRM8&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Publishing Time: 2026-05-21 17:05:20&lt;/em&gt;&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 10. Regular Expression Matching</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Thu, 21 May 2026 11:22:46 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-10-regular-expression-matching-7hp</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-10-regular-expression-matching-7hp</guid>
      <description>&lt;h1&gt;
  
  
  Mastering Regular Expressions: A Deep Dive into LeetCode 10 with Dynamic Programming
&lt;/h1&gt;

&lt;p&gt;Hey there, fellow coders! 👋 Are you ready to tackle one of LeetCode's classic challenges that might seem daunting at first glance but becomes quite elegant with the right approach? Today, we're diving into &lt;strong&gt;Problem 10: Regular Expression Matching&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This problem is a fantastic way to sharpen your dynamic programming (DP) skills and gain a deeper understanding of how regular expressions actually work under the hood. Don't worry if regex feels like magic – we're going to demystify it together!&lt;/p&gt;




&lt;h2&gt;
  
  
  The Puzzle: Regular Expression Matching
&lt;/h2&gt;

&lt;p&gt;We're given two strings: an &lt;code&gt;input string s&lt;/code&gt; and a &lt;code&gt;pattern p&lt;/code&gt;. Our goal is to determine if the &lt;code&gt;pattern p&lt;/code&gt; completely matches the &lt;code&gt;input string s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The twist? The &lt;code&gt;pattern p&lt;/code&gt; isn't just plain text. It can contain two special characters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;'.'&lt;/code&gt;: This dot matches &lt;strong&gt;any single character&lt;/strong&gt;. Think of it as a wildcard for one character.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;'*'&lt;/code&gt;: This asterisk matches &lt;strong&gt;zero or more&lt;/strong&gt; of the &lt;em&gt;preceding element&lt;/em&gt;. This is where things get interesting!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt; The match must cover the &lt;em&gt;entire&lt;/em&gt; input string &lt;code&gt;s&lt;/code&gt;, not just a part of it.&lt;/p&gt;

&lt;p&gt;Let's look at a few examples to solidify our understanding:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1: Basic Mismatch&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;s = "aa"&lt;/code&gt;, &lt;code&gt;p = "a"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why?&lt;/strong&gt; The pattern "a" only matches the first 'a' of "aa". It doesn't cover the entire string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example 2: The Power of &lt;code&gt;*&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;s = "aa"&lt;/code&gt;, &lt;code&gt;p = "a*"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why?&lt;/strong&gt; &lt;code&gt;*&lt;/code&gt; means "zero or more of the preceding element," which is 'a'. By repeating 'a' once, the pattern becomes "aa", matching the input. If &lt;code&gt;s&lt;/code&gt; was "a", it would also match (zero repetitions). If &lt;code&gt;s&lt;/code&gt; was "aaa", it would match (two repetitions).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example 3: &lt;code&gt;.*&lt;/code&gt; - The Ultimate Wildcard Combo&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;s = "ab"&lt;/code&gt;, &lt;code&gt;p = ".*"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why?&lt;/strong&gt; &lt;code&gt;.&lt;/code&gt; matches any single character. &lt;code&gt;*&lt;/code&gt; means "zero or more" of whatever precedes it. So, &lt;code&gt;.*&lt;/code&gt; means "zero or more of any character." It can match "ab", "a", "", "xyz", anything!&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The "Aha!" Moment: Intuition
&lt;/h2&gt;

&lt;p&gt;When you see problems involving matching parts of strings, especially with wildcards or options like "zero or more," your mind should start thinking about &lt;strong&gt;Dynamic Programming (DP)&lt;/strong&gt;. Why DP? Because the decision at any point (does &lt;code&gt;s[i]&lt;/code&gt; match &lt;code&gt;p[j]&lt;/code&gt;) often depends on the results of smaller subproblems.&lt;/p&gt;

&lt;p&gt;Imagine trying to match &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;p[j]&lt;/code&gt; is a regular character or &lt;code&gt;.&lt;/code&gt; you just check if &lt;code&gt;s[i]&lt;/code&gt; matches &lt;code&gt;p[j]&lt;/code&gt; and then move on to matching the rest of &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  But what if &lt;code&gt;p[j]&lt;/code&gt; is &lt;code&gt;*&lt;/code&gt;? This is the tricky part. &lt;code&gt;*&lt;/code&gt; gives us options:

&lt;ol&gt;
&lt;li&gt; It could match &lt;strong&gt;zero&lt;/strong&gt; occurrences of the character before it.&lt;/li&gt;
&lt;li&gt; It could match &lt;strong&gt;one or more&lt;/strong&gt; occurrences of the character before it.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These multiple choices, and the fact that we can build up a solution from smaller matches, strongly hints at DP!&lt;/p&gt;




&lt;h2&gt;
  
  
  Our Strategy: Dynamic Programming Grid
&lt;/h2&gt;

&lt;p&gt;We'll use a 2D boolean array, let's call it &lt;code&gt;dp&lt;/code&gt;, where &lt;code&gt;dp[i][j]&lt;/code&gt; will be &lt;code&gt;True&lt;/code&gt; if the first &lt;code&gt;i&lt;/code&gt; characters of &lt;code&gt;s&lt;/code&gt; (i.e., &lt;code&gt;s[0...i-1]&lt;/code&gt;) match the first &lt;code&gt;j&lt;/code&gt; characters of &lt;code&gt;p&lt;/code&gt; (i.e., &lt;code&gt;p[0...j-1]&lt;/code&gt;). Otherwise, it will be &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let &lt;code&gt;m&lt;/code&gt; be the length of &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; be the length of &lt;code&gt;p&lt;/code&gt;. Our &lt;code&gt;dp&lt;/code&gt; table will be &lt;code&gt;(m+1) x (n+1)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Initialize the DP Table
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;dp[0][0] = True&lt;/code&gt;: An empty string (&lt;code&gt;s&lt;/code&gt; with 0 characters) always matches an empty pattern (&lt;code&gt;p&lt;/code&gt; with 0 characters). This is our base case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;First Row (&lt;code&gt;dp[0][j]&lt;/code&gt; for &lt;code&gt;j &amp;gt; 0&lt;/code&gt;):&lt;/strong&gt; This represents matching an empty string &lt;code&gt;s&lt;/code&gt; with a non-empty pattern &lt;code&gt;p&lt;/code&gt;.&lt;br&gt;
An empty string can only be matched by a pattern that allows zero characters. This typically happens with &lt;code&gt;*&lt;/code&gt;.&lt;br&gt;
If &lt;code&gt;p[j-1]&lt;/code&gt; is &lt;code&gt;'*'&lt;/code&gt;, then it can match zero of the preceding element (&lt;code&gt;p[j-2]&lt;/code&gt;). In this scenario, &lt;code&gt;dp[0][j]&lt;/code&gt; would be &lt;code&gt;True&lt;/code&gt; if &lt;code&gt;dp[0][j-2]&lt;/code&gt; was &lt;code&gt;True&lt;/code&gt;. All other &lt;code&gt;dp[0][j]&lt;/code&gt; would be &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Fill the DP Table
&lt;/h3&gt;

&lt;p&gt;We'll iterate through &lt;code&gt;s&lt;/code&gt; (from &lt;code&gt;i = 1&lt;/code&gt; to &lt;code&gt;m&lt;/code&gt;) and &lt;code&gt;p&lt;/code&gt; (from &lt;code&gt;j = 1&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt;) to fill the table. For each &lt;code&gt;dp[i][j]&lt;/code&gt;, we consider two main scenarios for the current character &lt;code&gt;p[j-1]&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 1: &lt;code&gt;p[j-1]&lt;/code&gt; is NOT &lt;code&gt;'*'&lt;/code&gt; (i.e., it's a regular character or &lt;code&gt;'.'&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;p[j-1]&lt;/code&gt; matches &lt;code&gt;s[i-1]&lt;/code&gt; (meaning &lt;code&gt;p[j-1] == s[i-1]&lt;/code&gt; or &lt;code&gt;p[j-1] == '.'&lt;/code&gt;), then &lt;code&gt;s[0...i-1]&lt;/code&gt; matches &lt;code&gt;p[0...j-1]&lt;/code&gt; &lt;strong&gt;only if&lt;/strong&gt; &lt;code&gt;s[0...i-2]&lt;/code&gt; matched &lt;code&gt;p[0...j-2]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  So, &lt;code&gt;dp[i][j] = dp[i-1][j-1]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Otherwise (if &lt;code&gt;p[j-1]&lt;/code&gt; doesn't match &lt;code&gt;s[i-1]&lt;/code&gt;), &lt;code&gt;dp[i][j] = False&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scenario 2: &lt;code&gt;p[j-1]&lt;/code&gt; IS &lt;code&gt;'*'&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the trickiest part. The &lt;code&gt;*&lt;/code&gt; implies "zero or more" of the &lt;em&gt;preceding character&lt;/em&gt; (&lt;code&gt;p[j-2]&lt;/code&gt;). Let's call this preceding character &lt;code&gt;prev_char_in_pattern = p[j-2]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We have two possibilities for how &lt;code&gt;*&lt;/code&gt; can be interpreted:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;*&lt;/code&gt; matches zero occurrences of &lt;code&gt;prev_char_in_pattern&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  In this case, &lt;code&gt;prev_char_in_pattern&lt;/code&gt; and the &lt;code&gt;*&lt;/code&gt; effectively disappear from the pattern.&lt;/li&gt;
&lt;li&gt;  So, we need to check if &lt;code&gt;s[0...i-1]&lt;/code&gt; matches &lt;code&gt;p[0...j-3]&lt;/code&gt;. This state is represented by &lt;code&gt;dp[i][j-2]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Thus, &lt;code&gt;dp[i][j] = dp[i][j-2]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;*&lt;/code&gt; matches one or more occurrences of &lt;code&gt;prev_char_in_pattern&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  For &lt;code&gt;*&lt;/code&gt; to match one or more times, &lt;code&gt;prev_char_in_pattern&lt;/code&gt; &lt;em&gt;must&lt;/em&gt; match the current character &lt;code&gt;s[i-1]&lt;/code&gt;. (i.e., &lt;code&gt;prev_char_in_pattern == s[i-1]&lt;/code&gt; or &lt;code&gt;prev_char_in_pattern == '.'&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  If they match, &lt;code&gt;s[i-1]&lt;/code&gt; is consumed by one instance of &lt;code&gt;prev_char_in_pattern&lt;/code&gt;. We then need &lt;code&gt;s[0...i-2]&lt;/code&gt; to match &lt;code&gt;p[0...j-1]&lt;/code&gt; (the &lt;code&gt;prev_char_in_pattern&lt;/code&gt; followed by &lt;code&gt;*&lt;/code&gt; is still active, potentially matching more characters).&lt;/li&gt;
&lt;li&gt;  This state is represented by &lt;code&gt;dp[i-1][j]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  So, if &lt;code&gt;prev_char_in_pattern&lt;/code&gt; matches &lt;code&gt;s[i-1]&lt;/code&gt;, then &lt;code&gt;dp[i][j]&lt;/code&gt; can also be &lt;code&gt;dp[i-1][j]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Combining these:&lt;/strong&gt; &lt;code&gt;dp[i][j]&lt;/code&gt; will be &lt;code&gt;True&lt;/code&gt; if either of these conditions holds.
&lt;code&gt;dp[i][j] = dp[i][j-2]&lt;/code&gt; (zero occurrences)
If &lt;code&gt;prev_char_in_pattern&lt;/code&gt; matches &lt;code&gt;s[i-1]&lt;/code&gt; (i.e., &lt;code&gt;p[j-2] == s[i-1]&lt;/code&gt; or &lt;code&gt;p[j-2] == '.'&lt;/code&gt;):
    &lt;code&gt;dp[i][j] = dp[i][j] or dp[i-1][j]&lt;/code&gt; (one or more occurrences)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: The Result
&lt;/h3&gt;

&lt;p&gt;After filling the entire &lt;code&gt;dp&lt;/code&gt; table, the final answer will be in &lt;code&gt;dp[m][n]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's walk through an example: &lt;code&gt;s = "aab"&lt;/code&gt;, &lt;code&gt;p = "c*a*b"&lt;/code&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;dp[i][j]&lt;/th&gt;
&lt;th&gt;""&lt;/th&gt;
&lt;th&gt;c&lt;/th&gt;
&lt;th&gt;*&lt;/th&gt;
&lt;th&gt;a&lt;/th&gt;
&lt;th&gt;*&lt;/th&gt;
&lt;th&gt;b&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;""&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;a&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;aa&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;aab&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;dp[0][0]&lt;/code&gt; is &lt;code&gt;T&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;dp[0][2]&lt;/code&gt; (for &lt;code&gt;c*&lt;/code&gt;): &lt;code&gt;p[1]&lt;/code&gt; is &lt;code&gt;*&lt;/code&gt;, so &lt;code&gt;dp[0][2] = dp[0][0]&lt;/code&gt; which is &lt;code&gt;T&lt;/code&gt;. (empty string matches &lt;code&gt;c*&lt;/code&gt; by &lt;code&gt;c&lt;/code&gt; repeating 0 times).&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;dp[0][4]&lt;/code&gt; (for &lt;code&gt;c*a*&lt;/code&gt;): &lt;code&gt;p[3]&lt;/code&gt; is &lt;code&gt;*&lt;/code&gt;, so &lt;code&gt;dp[0][4] = dp[0][2]&lt;/code&gt; which is &lt;code&gt;T&lt;/code&gt;. (empty string matches &lt;code&gt;c*a*&lt;/code&gt; by &lt;code&gt;a&lt;/code&gt; repeating 0 times).&lt;/li&gt;
&lt;li&gt;  Now, consider &lt;code&gt;dp[1][1]&lt;/code&gt; (&lt;code&gt;s="a"&lt;/code&gt;, &lt;code&gt;p="c"&lt;/code&gt;): &lt;code&gt;p[0]&lt;/code&gt; ('c') != &lt;code&gt;s[0]&lt;/code&gt; ('a'). So &lt;code&gt;F&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Consider &lt;code&gt;dp[1][4]&lt;/code&gt; (&lt;code&gt;s="a"&lt;/code&gt;, &lt;code&gt;p="c*a*"&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;p[3]&lt;/code&gt; is &lt;code&gt;*&lt;/code&gt;. Preceding char &lt;code&gt;p[2]&lt;/code&gt; is 'a'.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;dp[1][2]&lt;/code&gt; (zero 'a's for &lt;code&gt;a*&lt;/code&gt;) is &lt;code&gt;F&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Does &lt;code&gt;p[2]&lt;/code&gt; ('a') match &lt;code&gt;s[0]&lt;/code&gt; ('a')? Yes!&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;dp[0][4]&lt;/code&gt; (one or more 'a's) is &lt;code&gt;T&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  So &lt;code&gt;dp[1][4]&lt;/code&gt; becomes &lt;code&gt;F OR T = T&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  Finally, &lt;code&gt;dp[3][6]&lt;/code&gt; will be &lt;code&gt;T&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Code
&lt;/h2&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="nb"&gt;object&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;isMatch&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;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        :type s: str
        :type p: str
        :rtype: bool
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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;s&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;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# dp[i][j] will be True if s[0...i-1] matches p[0...j-1]
&lt;/span&gt;        &lt;span class="c1"&gt;# Dimensions: (m+1) x (n+1)
&lt;/span&gt;        &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;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;m&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;# Base case: Empty string matches empty pattern
&lt;/span&gt;        &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

        &lt;span class="c1"&gt;# Initialize the first row (s is empty)
&lt;/span&gt;        &lt;span class="c1"&gt;# An empty string 's' can only match patterns like "a*", "a*b*", etc.
&lt;/span&gt;        &lt;span class="c1"&gt;# This means the pattern must end with '*' and its preceding element can be skipped.
&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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;if&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# If p[j-1] is '*', it means zero occurrences of p[j-2].
&lt;/span&gt;                &lt;span class="c1"&gt;# So, dp[0][j] depends on whether p[0...j-3] matched an empty string.
&lt;/span&gt;                &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Fill the DP table for all other cells
&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&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;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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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;# Scenario 1: Current pattern character is a regular character or '.'
&lt;/span&gt;                &lt;span class="c1"&gt;# (p[j-1] is not '*')
&lt;/span&gt;                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;s&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="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# If current characters match, depend on the match of preceding substrings
&lt;/span&gt;                    &lt;span class="n"&gt;dp&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="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;dp&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;# Scenario 2: Current pattern character is '*'
&lt;/span&gt;                &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# Case A: '*' matches zero occurrences of the preceding element (p[j-2])
&lt;/span&gt;                    &lt;span class="c1"&gt;# We effectively ignore p[j-2] and p[j-1] (the '*')
&lt;/span&gt;                    &lt;span class="c1"&gt;# So, s[0...i-1] must match p[0...j-3]
&lt;/span&gt;                    &lt;span class="n"&gt;dp&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="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;dp&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="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

                    &lt;span class="c1"&gt;# Case B: '*' matches one or more occurrences of the preceding element (p[j-2])
&lt;/span&gt;                    &lt;span class="c1"&gt;# This is only possible if the preceding character (p[j-2]) matches s[i-1]
&lt;/span&gt;                    &lt;span class="c1"&gt;# (p[j-2] == s[i-1] or p[j-2] == '.')
&lt;/span&gt;                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&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;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;s&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="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;p&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;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="c1"&gt;# If they match, '*' consumes s[i-1], and we check if s[0...i-2] matches p[0...j-1]
&lt;/span&gt;                        &lt;span class="c1"&gt;# (where p[j-1] is still '*', allowing it to match further characters)
&lt;/span&gt;                        &lt;span class="n"&gt;dp&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="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;dp&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="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;dp&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="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Time and Space Complexity Analysis
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time Complexity:&lt;/strong&gt; &lt;code&gt;O(m * n)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We are filling an &lt;code&gt;m x n&lt;/code&gt; DP table. Each cell calculation takes constant time (a few comparisons and assignments). Therefore, the total time complexity is proportional to the product of the lengths of the string &lt;code&gt;s&lt;/code&gt; and pattern &lt;code&gt;p&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity:&lt;/strong&gt; &lt;code&gt;O(m * n)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We use a 2D &lt;code&gt;dp&lt;/code&gt; array of size &lt;code&gt;(m+1) x (n+1)&lt;/code&gt; to store our intermediate results. This contributes &lt;code&gt;O(m * n)&lt;/code&gt; to the space complexity.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Given the constraints &lt;code&gt;1 &amp;lt;= s.length &amp;lt;= 20&lt;/code&gt; and &lt;code&gt;1 &amp;lt;= p.length &amp;lt;= 20&lt;/code&gt;, an &lt;code&gt;O(m*n)&lt;/code&gt; solution is perfectly efficient for this problem. &lt;code&gt;20 * 20 = 400&lt;/code&gt; operations per test case is lightning fast!&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Dynamic Programming for String Matching:&lt;/strong&gt; Problems involving matching substrings, especially with wildcards or varying length matches, are prime candidates for DP.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Defining DP State:&lt;/strong&gt; Clearly defining &lt;code&gt;dp[i][j]&lt;/code&gt; as the match for prefixes &lt;code&gt;s[0...i-1]&lt;/code&gt; and &lt;code&gt;p[0...j-1]&lt;/code&gt; is crucial.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Handling Special Characters (&lt;code&gt;.&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt;):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;.&lt;/code&gt; is straightforward: it matches any single character.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;*&lt;/code&gt; requires careful consideration: it has two main interpretations ("zero occurrences" OR "one or more occurrences") that lead to combining results from different DP states.

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Zero occurrences&lt;/strong&gt;: The &lt;code&gt;*&lt;/code&gt; and its preceding character are skipped (&lt;code&gt;dp[i][j-2]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;One or more occurrences&lt;/strong&gt;: The &lt;code&gt;*&lt;/code&gt; matches the current character &lt;code&gt;s[i-1]&lt;/code&gt; (if the preceding char allows it), and the &lt;code&gt;*&lt;/code&gt; pattern remains active (&lt;code&gt;dp[i-1][j]&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Base Cases:&lt;/strong&gt; Correctly initializing &lt;code&gt;dp[0][0]&lt;/code&gt; and the first row (&lt;code&gt;dp[0][j]&lt;/code&gt;) for an empty string &lt;code&gt;s&lt;/code&gt; is vital for the DP to propagate correctly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This problem is a fantastic way to stretch your DP muscles and see how complex string operations can be broken down into manageable subproblems. Keep practicing, and you'll master these patterns in no time!&lt;/p&gt;




&lt;p&gt;Published by p1Hzd8mRM8 on 2026-05-21 16:52:13&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 10. Regular Expression Matching</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Thu, 21 May 2026 09:05:53 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-10-regular-expression-matching-3e3d</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-10-regular-expression-matching-3e3d</guid>
      <description>&lt;h1&gt;
  
  
  Cracking the Regex Code: LeetCode 10 - Regular Expression Matching (Beginner-Friendly DP!)
&lt;/h1&gt;

&lt;p&gt;Hey fellow coders! 👋&lt;/p&gt;

&lt;p&gt;Today, we're diving into a classic LeetCode problem that might seem daunting at first glance but becomes incredibly elegant with the right approach: &lt;strong&gt;10. Regular Expression Matching&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you've ever used regular expressions (regex) in your programming, you know how powerful they are. This problem asks us to implement a simplified version of that power from scratch! Don't worry, we'll break it down step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Regular Expression Matching 🤯
&lt;/h2&gt;

&lt;p&gt;We're given two strings: an &lt;code&gt;input string (s)&lt;/code&gt; and a &lt;code&gt;pattern (p)&lt;/code&gt;. Our mission? Determine if the pattern &lt;code&gt;p&lt;/code&gt; entirely matches the input string &lt;code&gt;s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The tricky part comes with two special characters in our pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;.&lt;/code&gt; (Dot)&lt;/strong&gt;: This little guy is a wildcard! It matches &lt;em&gt;any single character&lt;/em&gt;. Think of it as a Joker card in a deck.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;*&lt;/code&gt; (Asterisk)&lt;/strong&gt;: This one is a bit more complex. It matches &lt;em&gt;zero or more&lt;/em&gt; occurrences of the &lt;em&gt;preceding element&lt;/em&gt;. The "preceding element" could be a regular character (like &lt;code&gt;a&lt;/code&gt; in &lt;code&gt;a*&lt;/code&gt;) or even a dot (&lt;code&gt;.&lt;/code&gt; in &lt;code&gt;.*&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Crucial Note:&lt;/strong&gt; The match must cover the &lt;em&gt;entire&lt;/em&gt; input string &lt;code&gt;s&lt;/code&gt;, not just a part of it.&lt;/p&gt;

&lt;p&gt;Let's look at a few examples to make it super clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example 1:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;s = "aa"&lt;/code&gt;, &lt;code&gt;p = "a"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why?&lt;/strong&gt; The pattern "a" only matches the first 'a'. It doesn't cover the entire "aa".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;s = "aa"&lt;/code&gt;, &lt;code&gt;p = "a*"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why?&lt;/strong&gt; The &lt;code&gt;*&lt;/code&gt; means "zero or more of the preceding 'a'". If we repeat 'a' once, it becomes "aa", which matches &lt;code&gt;s&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;s = "ab"&lt;/code&gt;, &lt;code&gt;p = ".*"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Why?&lt;/strong&gt; &lt;code&gt;.&lt;/code&gt; matches "any single character". &lt;code&gt;*&lt;/code&gt; means "zero or more of the preceding element". So, &lt;code&gt;.*&lt;/code&gt; means "zero or more of any character". This can match "ab" (specifically, it matches &lt;code&gt;a&lt;/code&gt; once, then &lt;code&gt;b&lt;/code&gt; once).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt; are pretty short (length up to 20). This is a hint that solutions with complexity like &lt;code&gt;O(len(s) * len(p))&lt;/code&gt; might pass!&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;s&lt;/code&gt; only has lowercase English letters.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;p&lt;/code&gt; has lowercase English letters, &lt;code&gt;.&lt;/code&gt;, and &lt;code&gt;*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Every &lt;code&gt;*&lt;/code&gt; in &lt;code&gt;p&lt;/code&gt; is guaranteed to have a valid preceding character (no &lt;code&gt;*abc&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Intuition: "Aha!" - It's a Matching Game! 🎮
&lt;/h2&gt;

&lt;p&gt;When you see problems asking if one string "matches" another, especially with wildcards or characters that depend on previous elements, your brain should immediately start thinking about &lt;strong&gt;Dynamic Programming (DP)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why DP? Because matching involves checking if &lt;em&gt;sub-parts&lt;/em&gt; of &lt;code&gt;s&lt;/code&gt; match &lt;em&gt;sub-parts&lt;/em&gt; of &lt;code&gt;p&lt;/code&gt;. If &lt;code&gt;s[0...i]&lt;/code&gt; matches &lt;code&gt;p[0...j]&lt;/code&gt;, it likely depends on whether &lt;code&gt;s[0...i-1]&lt;/code&gt; matched &lt;code&gt;p[0...j-1]&lt;/code&gt;, or some other combination. We can build up our solution from smaller, simpler matches!&lt;/p&gt;

&lt;p&gt;Think of it like this: If you're trying to match &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt;, you look at their last characters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If they're simple characters and match, great! You just need to check if the &lt;em&gt;rest&lt;/em&gt; of &lt;code&gt;s&lt;/code&gt; matches the &lt;em&gt;rest&lt;/em&gt; of &lt;code&gt;p&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;p&lt;/code&gt; has a &lt;code&gt;.&lt;/code&gt; (dot), it's a free pass! It matches any character in &lt;code&gt;s&lt;/code&gt;. So again, check the rest.&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;p&lt;/code&gt; has a &lt;code&gt;*&lt;/code&gt; (asterisk), this is where it gets interesting. A &lt;code&gt;*&lt;/code&gt; can represent &lt;em&gt;zero&lt;/em&gt; occurrences, &lt;em&gt;one&lt;/em&gt; occurrence, or &lt;em&gt;multiple&lt;/em&gt; occurrences. This means we have choices, and DP is excellent for exploring choices efficiently!&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Approach: Building Our DP Table 🏗️
&lt;/h2&gt;

&lt;p&gt;Let's define our DP state:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dp[i][j]&lt;/code&gt; will be a boolean value, &lt;code&gt;true&lt;/code&gt; if the first &lt;code&gt;i&lt;/code&gt; characters of &lt;code&gt;s&lt;/code&gt; (i.e., &lt;code&gt;s[0...i-1]&lt;/code&gt;) match the first &lt;code&gt;j&lt;/code&gt; characters of &lt;code&gt;p&lt;/code&gt; (i.e., &lt;code&gt;p[0...j-1]&lt;/code&gt;), and &lt;code&gt;false&lt;/code&gt; otherwise.&lt;/p&gt;

&lt;p&gt;We'll create a &lt;code&gt;(m+1) x (n+1)&lt;/code&gt; 2D array (or list of lists in Python), where &lt;code&gt;m = len(s)&lt;/code&gt; and &lt;code&gt;n = len(p)&lt;/code&gt;. The extra row/column is for handling empty prefixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Initialization (Base Cases)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;dp[0][0] = true&lt;/code&gt;: An empty string &lt;code&gt;""&lt;/code&gt; always matches an empty pattern &lt;code&gt;""&lt;/code&gt;. This is our starting point!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;dp[i][0] = false&lt;/code&gt; for &lt;code&gt;i &amp;gt; 0&lt;/code&gt;: A non-empty string &lt;code&gt;s&lt;/code&gt; can never match an empty pattern &lt;code&gt;""&lt;/code&gt;. These will remain &lt;code&gt;false&lt;/code&gt; by default.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;dp[0][j]&lt;/code&gt; for &lt;code&gt;j &amp;gt; 0&lt;/code&gt;: An empty string &lt;code&gt;s&lt;/code&gt; can match patterns like &lt;code&gt;"a*"&lt;/code&gt; or &lt;code&gt;"a*b*"&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;p[j-1]&lt;/code&gt; is &lt;code&gt;*&lt;/code&gt;, then &lt;code&gt;dp[0][j]&lt;/code&gt; can be &lt;code&gt;true&lt;/code&gt; if &lt;code&gt;dp[0][j-2]&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;. This means the &lt;code&gt;X*&lt;/code&gt; part (where &lt;code&gt;X&lt;/code&gt; is &lt;code&gt;p[j-2]&lt;/code&gt;) is effectively skipped, matching zero occurrences of &lt;code&gt;X&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Example: For &lt;code&gt;s=""&lt;/code&gt;, &lt;code&gt;p="a*b*"&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;dp[0][0] = true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;p[1]&lt;/code&gt; is &lt;code&gt;*&lt;/code&gt;. &lt;code&gt;dp[0][2]&lt;/code&gt; (for &lt;code&gt;a*&lt;/code&gt;) = &lt;code&gt;dp[0][0]&lt;/code&gt; = &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;p[3]&lt;/code&gt; is &lt;code&gt;*&lt;/code&gt;. &lt;code&gt;dp[0][4]&lt;/code&gt; (for &lt;code&gt;a*b*&lt;/code&gt;) = &lt;code&gt;dp[0][2]&lt;/code&gt; = &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Filling the DP Table (Iterative Logic)
&lt;/h3&gt;

&lt;p&gt;We'll iterate &lt;code&gt;i&lt;/code&gt; from 1 to &lt;code&gt;m&lt;/code&gt; (for &lt;code&gt;s&lt;/code&gt;) and &lt;code&gt;j&lt;/code&gt; from 1 to &lt;code&gt;n&lt;/code&gt; (for &lt;code&gt;p&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For each &lt;code&gt;dp[i][j]&lt;/code&gt;, we consider &lt;code&gt;s[i-1]&lt;/code&gt; (the current character in &lt;code&gt;s&lt;/code&gt;) and &lt;code&gt;p[j-1]&lt;/code&gt; (the current character in &lt;code&gt;p&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1: &lt;code&gt;p[j-1]&lt;/code&gt; is NOT &lt;code&gt;*&lt;/code&gt; (it's a regular character or &lt;code&gt;.&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;p[j-1]&lt;/code&gt; is a regular letter OR &lt;code&gt;p[j-1]&lt;/code&gt; is &lt;code&gt;.&lt;/code&gt; (the wildcard):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We need &lt;code&gt;s[i-1]&lt;/code&gt; to match &lt;code&gt;p[j-1]&lt;/code&gt; (or &lt;code&gt;p[j-1]&lt;/code&gt; is &lt;code&gt;.&lt;/code&gt; which matches anything).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If they match, then &lt;code&gt;dp[i][j]&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt; if and only if the &lt;em&gt;previous parts&lt;/em&gt; also matched: &lt;code&gt;dp[i-1][j-1]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if p[j-1] == s[i-1] or p[j-1] == '.':&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dp[i][j] = dp[i-1][j-1]&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Case 2: &lt;code&gt;p[j-1]&lt;/code&gt; IS &lt;code&gt;*&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the most complex part, as &lt;code&gt;*&lt;/code&gt; gives us two main options for the preceding element &lt;code&gt;p[j-2]&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Option A: &lt;code&gt;*&lt;/code&gt; matches zero occurrences of &lt;code&gt;p[j-2]&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;*&lt;/code&gt; matches zero occurrences, it's like &lt;code&gt;p[j-2]&lt;/code&gt; and &lt;code&gt;p[j-1]&lt;/code&gt; (&lt;code&gt;*&lt;/code&gt;) aren't even there.&lt;/li&gt;
&lt;li&gt;  So, &lt;code&gt;dp[i][j]&lt;/code&gt; would be &lt;code&gt;true&lt;/code&gt; if &lt;code&gt;s[0...i-1]&lt;/code&gt; matches &lt;code&gt;p[0...j-3]&lt;/code&gt; (which is &lt;code&gt;dp[i][j-2]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;dp[i][j] = dp[i][j-2]&lt;/code&gt; (initial state for this cell)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Option B: &lt;code&gt;*&lt;/code&gt; matches one or more occurrences of &lt;code&gt;p[j-2]&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  This is only possible if &lt;code&gt;s[i-1]&lt;/code&gt; (the current character in &lt;code&gt;s&lt;/code&gt;) actually matches &lt;code&gt;p[j-2]&lt;/code&gt; (the character &lt;em&gt;before&lt;/em&gt; &lt;code&gt;*&lt;/code&gt;). Remember &lt;code&gt;.&lt;/code&gt; also counts as a match!&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;s[i-1]&lt;/code&gt; matches &lt;code&gt;p[j-2]&lt;/code&gt; (or &lt;code&gt;p[j-2]&lt;/code&gt; is &lt;code&gt;.&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;*&lt;/code&gt; matches one occurrence: &lt;code&gt;s[0...i-1]&lt;/code&gt; matches &lt;code&gt;p[0...j-1]&lt;/code&gt; if &lt;code&gt;s[0...i-2]&lt;/code&gt; matched &lt;code&gt;p[0...j-1]&lt;/code&gt; (meaning &lt;code&gt;s[i-1]&lt;/code&gt; is another occurrence of &lt;code&gt;p[j-2]&lt;/code&gt;). This is &lt;code&gt;dp[i-1][j]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  We combine this with Option A: &lt;code&gt;dp[i][j] = dp[i][j] OR dp[i-1][j]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;code&gt;if p[j-2] == s[i-1] or p[j-2] == '.':&lt;/code&gt;
&lt;code&gt;dp[i][j] = dp[i][j] or dp[i-1][j]&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Putting it all together for &lt;code&gt;*&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;elif p[j-1] == '*':&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dp[i][j] = dp[i][j-2]  # Option A: '*' matches zero preceding elements&lt;/code&gt;&lt;br&gt;
&lt;code&gt;if p[j-2] == s[i-1] or p[j-2] == '.':&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dp[i][j] = dp[i][j] or dp[i-1][j] # Option B: '*' matches one or more&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, after filling the entire table, our answer is simply &lt;code&gt;dp[m][n]&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Code ✨
&lt;/h2&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;isMatch&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;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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;s&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;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# dp[i][j] will be true if s[0...i-1] matches p[0...j-1]
&lt;/span&gt;        &lt;span class="c1"&gt;# (m+1) rows for string s, (n+1) columns for pattern p
&lt;/span&gt;        &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;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;m&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;# Base case: Empty string matches empty pattern
&lt;/span&gt;        &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

        &lt;span class="c1"&gt;# Handle patterns like "a*", "a*b*", etc., matching an empty string s
&lt;/span&gt;        &lt;span class="c1"&gt;# dp[i][0] for i &amp;gt; 0 will remain False as a non-empty string cannot match an empty pattern.
&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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;# If the current pattern character is '*', it might match zero occurrences
&lt;/span&gt;            &lt;span class="c1"&gt;# of the preceding element. So, dp[0][j] depends on dp[0][j-2].
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Fill the DP table
&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&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;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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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;# Case 1: Current pattern character is a letter or '.'
&lt;/span&gt;                &lt;span class="c1"&gt;# If s[i-1] matches p[j-1] (or p[j-1] is '.'), then the match depends on
&lt;/span&gt;                &lt;span class="c1"&gt;# whether the preceding parts (s[0...i-2] and p[0...j-2]) matched.
&lt;/span&gt;                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;s&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="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;dp&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="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;dp&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;# Case 2: Current pattern character is '*'
&lt;/span&gt;                &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# Option A: '*' matches zero occurrences of the preceding element p[j-2]
&lt;/span&gt;                    &lt;span class="c1"&gt;# In this scenario, we effectively ignore p[j-2] and p[j-1] ('*').
&lt;/span&gt;                    &lt;span class="c1"&gt;# So, dp[i][j] is true if dp[i][j-2] is true.
&lt;/span&gt;                    &lt;span class="n"&gt;dp&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="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;dp&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="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

                    &lt;span class="c1"&gt;# Option B: '*' matches one or more occurrences of the preceding element p[j-2]
&lt;/span&gt;                    &lt;span class="c1"&gt;# This is only possible if s[i-1] matches p[j-2] (or p[j-2] is '.').
&lt;/span&gt;                    &lt;span class="c1"&gt;# If it matches, then dp[i][j] can also be true if dp[i-1][j] is true.
&lt;/span&gt;                    &lt;span class="c1"&gt;# dp[i-1][j] means s[0...i-2] already matched p[0...j-1], and now s[i-1]
&lt;/span&gt;                    &lt;span class="c1"&gt;# is another instance matching p[j-2], so the '*' consumes s[i-1].
&lt;/span&gt;                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&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;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;s&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="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;p&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;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;dp&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="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;dp&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="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;dp&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="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Time &amp;amp; Space Complexity Analysis ⏱️
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time Complexity:&lt;/strong&gt; &lt;code&gt;O(m * n)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We are filling an &lt;code&gt;m x n&lt;/code&gt; DP table. Each cell calculation takes constant time (a few comparisons and lookups).&lt;/li&gt;
&lt;li&gt;  Given &lt;code&gt;m, n &amp;lt;= 20&lt;/code&gt;, this is &lt;code&gt;20 * 20 = 400&lt;/code&gt; operations, which is extremely fast!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity:&lt;/strong&gt; &lt;code&gt;O(m * n)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We use a 2D &lt;code&gt;dp&lt;/code&gt; array of size &lt;code&gt;(m+1) x (n+1)&lt;/code&gt; to store our results.&lt;/li&gt;
&lt;li&gt;  Similarly, for &lt;code&gt;m, n &amp;lt;= 20&lt;/code&gt;, this is &lt;code&gt;21 * 21 = 441&lt;/code&gt; booleans, a very small memory footprint.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Takeaways ✨
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Dynamic Programming (DP) for String Matching:&lt;/strong&gt; Many string-related problems, especially those involving subproblems and choices (like &lt;code&gt;*&lt;/code&gt; representing zero or more), are excellent candidates for DP.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Careful Base Cases:&lt;/strong&gt; Correctly initializing your DP table, especially for empty strings and patterns, is crucial.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Handling Wildcards:&lt;/strong&gt; Special characters like &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt; require breaking down their behavior into distinct cases (&lt;code&gt;.&lt;/code&gt; is simple, &lt;code&gt;*&lt;/code&gt; involves "zero occurrences" vs. "one or more occurrences").&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Building from Smaller Problems:&lt;/strong&gt; The beauty of DP is seeing how &lt;code&gt;dp[i][j]&lt;/code&gt; relies on previously computed &lt;code&gt;dp&lt;/code&gt; values, allowing us to build up the complete solution efficiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This problem is a fantastic way to solidify your understanding of DP and string manipulation. Keep practicing, and you'll be a regex master in no time!&lt;/p&gt;




&lt;p&gt;Author Account: p1Hzd8mRM8&lt;br&gt;
Published: 2026-05-21 14:35:24&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 7. Reverse Integer</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Sun, 17 May 2026 06:36:46 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-7-reverse-integer-1cl0</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-7-reverse-integer-1cl0</guid>
      <description>&lt;h1&gt;
  
  
  Unlocking LeetCode 7: Reverse Integer (A Beginner's Guide to Digital Flipping!)
&lt;/h1&gt;

&lt;p&gt;Hello Devs! Today, we're diving into a classic LeetCode problem that's perfect for honing your logical thinking and handling tricky integer constraints: &lt;strong&gt;Problem 7: Reverse Integer&lt;/strong&gt;. It sounds simple, but there's a neat catch!&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Explanation
&lt;/h2&gt;

&lt;p&gt;We're given a &lt;code&gt;signed 32-bit integer&lt;/code&gt; (that's a number that can be positive or negative, fitting within a specific range, roughly -2 billion to +2 billion). Our goal is to return this integer with its digits reversed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sounds easy, right? Here's the catch:&lt;/strong&gt; If reversing the digits causes the number to go &lt;em&gt;outside&lt;/em&gt; the valid 32-bit integer range, we must return &lt;code&gt;0&lt;/code&gt;. Also, we can't use 64-bit integers, which means we need to be careful with intermediate results if we were using a fixed-size integer language.&lt;/p&gt;

&lt;p&gt;Let's look at some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;x = 123&lt;/code&gt; becomes &lt;code&gt;321&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;x = -123&lt;/code&gt; becomes &lt;code&gt;-321&lt;/code&gt; (the sign stays!)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;x = 120&lt;/code&gt; becomes &lt;code&gt;21&lt;/code&gt; (leading zeros are dropped when reversing)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intuition
&lt;/h2&gt;

&lt;p&gt;The "aha!" moment for this problem often comes from realizing that dealing with individual digits of a number is much easier when it's &lt;em&gt;not&lt;/em&gt; a number. Think of it: how do you reverse "123"? You literally flip the order. What data type is great for flipping characters? &lt;strong&gt;Strings!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, our core idea is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Convert the integer to a string.&lt;/li&gt;
&lt;li&gt; Reverse the string.&lt;/li&gt;
&lt;li&gt; Convert it back to an integer.&lt;/li&gt;
&lt;li&gt; Perform the all-important range check.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;Let's break down the steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Handle the Sign:&lt;/strong&gt; Before reversing, we need to know if the original number &lt;code&gt;x&lt;/code&gt; was negative. If &lt;code&gt;x&lt;/code&gt; is negative, we'll reverse its positive counterpart (e.g., &lt;code&gt;123&lt;/code&gt; from &lt;code&gt;-123&lt;/code&gt;) and then apply the negative sign back at the end.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Convert and Reverse:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;x&lt;/code&gt; is negative, we first take its absolute value's string representation (&lt;code&gt;str(x)[1:]&lt;/code&gt; effectively removes the &lt;code&gt;-&lt;/code&gt; sign). Then, we reverse this substring using slicing (&lt;code&gt;[::-1]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;x&lt;/code&gt; is positive, we simply convert &lt;code&gt;x&lt;/code&gt; to a string (&lt;code&gt;str(x)&lt;/code&gt;) and reverse it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Convert Back to Integer:&lt;/strong&gt; After reversing the string, we convert it back to an integer using &lt;code&gt;int()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Apply Sign (if needed):&lt;/strong&gt; If the original &lt;code&gt;x&lt;/code&gt; was negative, multiply our &lt;code&gt;res&lt;/code&gt; by &lt;code&gt;-1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The Critical Overflow Check:&lt;/strong&gt; This is where many solutions fail! We need to check if our &lt;code&gt;res&lt;/code&gt; is now &lt;em&gt;outside&lt;/em&gt; the &lt;code&gt;[-2^31, 2^31 - 1]&lt;/code&gt; range.

&lt;ul&gt;
&lt;li&gt;  The maximum 32-bit signed integer is &lt;code&gt;2**31 - 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  The minimum 32-bit signed integer is &lt;code&gt;-2**31&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;res&lt;/code&gt; is too large or too small, return &lt;code&gt;0&lt;/code&gt;. Otherwise, return &lt;code&gt;res&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;Here's the Python implementation based on our approach:&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;reverse&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;x&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;# Define the 32-bit integer range boundaries
&lt;/span&gt;        &lt;span class="n"&gt;MAX_INT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;31&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;MIN_INT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;

        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# For negative numbers, remove the '-' sign, reverse, then re-apply '-'
&lt;/span&gt;            &lt;span class="c1"&gt;# Example: -123 -&amp;gt; "123" -&amp;gt; "321" -&amp;gt; -321
&lt;/span&gt;            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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="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="o"&gt;*&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;# For positive numbers, simply convert to string, reverse, convert back
&lt;/span&gt;            &lt;span class="c1"&gt;# Example: 123 -&amp;gt; "123" -&amp;gt; "321" -&amp;gt; 321
&lt;/span&gt;            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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="p"&gt;])&lt;/span&gt;

        &lt;span class="c1"&gt;# Check for 32-bit integer overflow
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_INT&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MIN_INT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time &amp;amp; Space Complexity Analysis
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Time Complexity: O(log |x|)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  The operations involve converting the integer to a string, reversing it, and converting it back. The number of digits in &lt;code&gt;x&lt;/code&gt; is proportional to &lt;code&gt;log10(|x|)&lt;/code&gt;. All these string operations take time proportional to the number of digits.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Space Complexity: O(log |x|)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  We create a string representation of &lt;code&gt;x&lt;/code&gt;, which uses space proportional to the number of digits in &lt;code&gt;x&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;String Magic:&lt;/strong&gt; For digit-based problems, converting integers to strings can often simplify reversal or digit manipulation.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Edge Cases are Crucial:&lt;/strong&gt; Always consider negative inputs and, most importantly, the integer overflow/underflow boundaries.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Understand Data Types:&lt;/strong&gt; Be aware of the maximum and minimum values your data types can hold, especially in competitive programming.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Author Account:&lt;/strong&gt; p1Hzd8mRM8&lt;br&gt;
&lt;strong&gt;Time Published:&lt;/strong&gt; 2026-05-17 12:06:31&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 5. Longest Palindromic Substring</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Sat, 16 May 2026 18:44:09 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-5-longest-palindromic-substring-454c</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-5-longest-palindromic-substring-454c</guid>
      <description>&lt;h1&gt;
  
  
  Longest Palindromic Substring: A Core String Algorithm Explained
&lt;/h1&gt;

&lt;p&gt;Welcome to another deep dive into a classic LeetCode problem! Today, we're tackling Problem 5: Longest Palindromic Substring. This problem is a fantastic way to sharpen your string manipulation and algorithmic thinking skills.&lt;/p&gt;




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

&lt;p&gt;Given a string &lt;code&gt;s&lt;/code&gt;, our goal is to find and return the longest substring within &lt;code&gt;s&lt;/code&gt; that is a palindrome.&lt;/p&gt;

&lt;p&gt;What's a palindrome? It's a sequence of characters that reads the same forwards and backward (e.g., "madam", "racecar", "level").&lt;br&gt;
What's a substring? It's a contiguous sequence of characters within a string (e.g., for "apple", "app" is a substring, but "ale" is not).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's look at the examples:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Example 1:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Input: &lt;code&gt;s = "babad"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Output: &lt;code&gt;"bab"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Explanation: &lt;code&gt;"aba"&lt;/code&gt; is also a valid answer of the same length.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;  Input: &lt;code&gt;s = "cbbd"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Output: &lt;code&gt;"bb"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The string &lt;code&gt;s&lt;/code&gt; will contain only digits and English letters, and its length will be between 1 and 1000 characters.&lt;/p&gt;




&lt;h3&gt;
  
  
  Intuition
&lt;/h3&gt;

&lt;p&gt;The core idea behind finding palindromes is that they expand symmetrically from a center point. Think about "racecar" – the 'e' is the center, and 'c' expands to 'r'. Or "abba" – the center is between the two 'b's, and 'a' expands to 'a'.&lt;/p&gt;

&lt;p&gt;This insight simplifies our search: instead of checking every single substring for palindromic properties (which is &lt;code&gt;O(N^3)&lt;/code&gt; or &lt;code&gt;O(N^2)&lt;/code&gt; with an &lt;code&gt;O(N)&lt;/code&gt; check), we can iterate through every possible "center" and try to expand outwards.&lt;/p&gt;

&lt;p&gt;There are two types of centers we need to consider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Single character center:&lt;/strong&gt; For palindromes with an odd length (e.g., "b*&lt;em&gt;a&lt;/em&gt;&lt;em&gt;b", "r&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;*cecar"). Here, &lt;code&gt;s[i]&lt;/code&gt; itself is the center.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Two character center:&lt;/strong&gt; For palindromes with an even length (e.g., "bb", "a*&lt;em&gt;bb&lt;/em&gt;*a"). Here, &lt;code&gt;s[i]&lt;/code&gt; and &lt;code&gt;s[i+1]&lt;/code&gt; form the center.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Approach
&lt;/h3&gt;

&lt;p&gt;We'll use an "Expand Around Center" approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Initialize:&lt;/strong&gt; Keep track of the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; indices of the longest palindrome found so far. Initialize them to &lt;code&gt;0, 0&lt;/code&gt; (assuming a single character is the shortest possible palindrome).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Iterate Through Centers:&lt;/strong&gt; Loop through each character in the string using an index &lt;code&gt;i&lt;/code&gt;. Each &lt;code&gt;i&lt;/code&gt; will serve as a potential center.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Expand for Odd Length Palindromes:&lt;/strong&gt; Call a helper function &lt;code&gt;expand_around_center(s, i, i)&lt;/code&gt;. This tries to expand a palindrome assuming &lt;code&gt;s[i]&lt;/code&gt; is its sole center.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Expand for Even Length Palindromes:&lt;/strong&gt; Call the helper function &lt;code&gt;expand_around_center(s, i, i + 1)&lt;/code&gt;. This tries to expand a palindrome assuming &lt;code&gt;s[i]&lt;/code&gt; and &lt;code&gt;s[i+1]&lt;/code&gt; are its two central characters.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Helper Function &lt;code&gt;expand_around_center(s, left, right)&lt;/code&gt;:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  This function takes the string &lt;code&gt;s&lt;/code&gt; and two indices, &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  It expands outwards: &lt;code&gt;left&lt;/code&gt; moves to the left (&lt;code&gt;left-1&lt;/code&gt;) and &lt;code&gt;right&lt;/code&gt; moves to the right (&lt;code&gt;right+1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  This expansion continues as long as &lt;code&gt;left&lt;/code&gt; is within bounds (&lt;code&gt;&amp;gt;= 0&lt;/code&gt;), &lt;code&gt;right&lt;/code&gt; is within bounds (&lt;code&gt;&amp;lt; len(s)&lt;/code&gt;), and the characters at &lt;code&gt;s[left]&lt;/code&gt; and &lt;code&gt;s[right]&lt;/code&gt; are equal.&lt;/li&gt;
&lt;li&gt;  Once the loop terminates (either due to bounds or mismatch), the length of the palindrome found is &lt;code&gt;right - left - 1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Update Longest Palindrome:&lt;/strong&gt; After getting &lt;code&gt;len1&lt;/code&gt; (odd center) and &lt;code&gt;len2&lt;/code&gt; (even center), determine &lt;code&gt;max_len = max(len1, len2)&lt;/code&gt;. If &lt;code&gt;max_len&lt;/code&gt; is greater than the length of our current longest palindrome (&lt;code&gt;end - start + 1&lt;/code&gt;), then update &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;  To calculate the new &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; from &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;max_len&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;start = i - (max_len - 1) // 2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;end = i + max_len // 2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Return Result:&lt;/strong&gt; After iterating through all possible centers, return the substring &lt;code&gt;s[start : end + 1]&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Code
&lt;/h3&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;longestPalindrome&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;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;

        &lt;span class="n"&gt;start&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;end&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;# Helper function to expand around a given center
&lt;/span&gt;        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expand_around_center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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="nb"&gt;int&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="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="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;s&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;s&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="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="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="c1"&gt;# When the loop finishes, left and right are one step beyond the palindrome boundaries.
&lt;/span&gt;            &lt;span class="c1"&gt;# So, the length is (right - 1) - (left + 1) + 1 = right - left - 1
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&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="c1"&gt;# Iterate through each character, treating it as a potential center
&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;s&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="c1"&gt;# Case 1: Odd length palindrome (center is s[i])
&lt;/span&gt;            &lt;span class="n"&gt;len1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;expand_around_center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&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="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Case 2: Even length palindrome (center is s[i] and s[i+1])
&lt;/span&gt;            &lt;span class="n"&gt;len2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;expand_around_center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&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="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="c1"&gt;# Get the maximum length found from these two expansions
&lt;/span&gt;            &lt;span class="n"&gt;max_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# If this palindrome is longer than our current longest
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;max_len&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&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;# Calculate the new start and end indices
&lt;/span&gt;                &lt;span class="c1"&gt;# For an odd length palindrome centered at i: start = i - (length-1)/2, end = i + (length-1)/2
&lt;/span&gt;                &lt;span class="c1"&gt;# For an even length palindrome centered between i and i+1: start = i - (length/2 - 1), end = i + length/2
&lt;/span&gt;                &lt;span class="c1"&gt;# The combined formula works for both:
&lt;/span&gt;                &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_len&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="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
                &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;max_len&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

        &lt;span class="c1"&gt;# Return the longest palindromic substring
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;end&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Time &amp;amp; Space Complexity Analysis
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time Complexity: O(N^2)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The main loop iterates &lt;code&gt;N&lt;/code&gt; times, where &lt;code&gt;N&lt;/code&gt; is the length of the string &lt;code&gt;s&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Inside the loop, &lt;code&gt;expand_around_center&lt;/code&gt; is called twice. In the worst case, &lt;code&gt;expand_around_center&lt;/code&gt; might traverse the entire string (e.g., for "aaaa...a").&lt;/li&gt;
&lt;li&gt;  Thus, each call to &lt;code&gt;expand_around_center&lt;/code&gt; takes &lt;code&gt;O(N)&lt;/code&gt; time.&lt;/li&gt;
&lt;li&gt;  Overall complexity: &lt;code&gt;N * O(N) = O(N^2)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We are only using a few variables (&lt;code&gt;start&lt;/code&gt;, &lt;code&gt;end&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;len1&lt;/code&gt;, &lt;code&gt;len2&lt;/code&gt;, &lt;code&gt;max_len&lt;/code&gt;, &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;) to store indices and lengths.&lt;/li&gt;
&lt;li&gt;  The space used does not grow with the input string size.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Palindromes and Symmetry:&lt;/strong&gt; The inherent symmetry of palindromes is key to efficient algorithms.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Expand Around Center:&lt;/strong&gt; This is a powerful technique for palindrome problems, allowing us to find palindromes by growing them from every possible middle point.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Handling Odd and Even Lengths:&lt;/strong&gt; Remember to consider both types of palindromes (odd-length with a single character center, and even-length with a two-character center).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This "Expand Around Center" approach is generally simpler to implement than dynamic programming solutions for this problem, while achieving the same &lt;code&gt;O(N^2)&lt;/code&gt; time complexity.&lt;/p&gt;




&lt;p&gt;Author Account: p1Hzd8mRM8&lt;br&gt;
Time Published: 2026-05-17 00:13:54&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 4. Median of Two Sorted Arrays</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Sat, 16 May 2026 18:42:44 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-4-median-of-two-sorted-arrays-1fc2</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-4-median-of-two-sorted-arrays-1fc2</guid>
      <description>&lt;h1&gt;
  
  
  Unlock the Median Magic: Diving into Two Sorted Arrays!
&lt;/h1&gt;

&lt;p&gt;Hey LeetCoders and aspiring developers! 👋&lt;/p&gt;

&lt;p&gt;Today, we're tackling a classic LeetCode challenge that often pops up in interviews: &lt;strong&gt;4. Median of Two Sorted Arrays&lt;/strong&gt;. Don't let the "Hard" tag intimidate you! While the optimal solution is quite advanced, we'll walk through a very intuitive, step-by-step approach that makes perfect sense for beginners. Let's conquer this one together!&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Problem Explanation: What are we actually doing?
&lt;/h2&gt;

&lt;p&gt;Imagine you have two separate lists of numbers, &lt;code&gt;nums1&lt;/code&gt; and &lt;code&gt;nums2&lt;/code&gt;, and here's the crucial part: &lt;strong&gt;both are already sorted!&lt;/strong&gt; Your mission is to find the &lt;strong&gt;median&lt;/strong&gt; of all the numbers if you were to combine these two lists into one big, sorted list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's a median?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If you have an &lt;strong&gt;odd&lt;/strong&gt; number of elements in a sorted list, the median is simply the middle element. For &lt;code&gt;[1, 2, 3]&lt;/code&gt;, the median is &lt;code&gt;2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  If you have an &lt;strong&gt;even&lt;/strong&gt; number of elements, the median is the average of the two middle elements. For &lt;code&gt;[1, 2, 3, 4]&lt;/code&gt;, the median is &lt;code&gt;(2 + 3) / 2 = 2.5&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem throws a curveball: it asks for an overall runtime complexity of &lt;code&gt;O(log(m+n))&lt;/code&gt;. We'll discuss this after exploring a more straightforward solution.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;nums1 = [1,3]&lt;/code&gt;, &lt;code&gt;nums2 = [2]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  If merged and sorted: &lt;code&gt;[1,2,3]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Median: &lt;code&gt;2&lt;/code&gt; (middle element)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;nums1 = [1,2]&lt;/code&gt;, &lt;code&gt;nums2 = [3,4]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  If merged and sorted: &lt;code&gt;[1,2,3,4]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Median: &lt;code&gt;(2+3)/2 = 2.5&lt;/code&gt; (average of two middle elements)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤔 Intuition: The "Aha!" Moment
&lt;/h2&gt;

&lt;p&gt;The simplest way to find the median of two sorted arrays is to just... merge them! If we combine &lt;code&gt;nums1&lt;/code&gt; and &lt;code&gt;nums2&lt;/code&gt; into a single, sorted array, finding the median becomes trivial.&lt;/p&gt;

&lt;p&gt;However, actually building a &lt;em&gt;new&lt;/em&gt; merged array takes &lt;code&gt;O(m+n)&lt;/code&gt; space and time. Can we do it without fully merging? Yes! We only need to find the element(s) at the median position(s). We can simulate the merge process by using two pointers, one for each array, and pick elements one by one until we reach the median position.&lt;/p&gt;

&lt;p&gt;Think of it like this: you're trying to find the &lt;code&gt;k&lt;/code&gt;-th smallest element in the combined list. Since the arrays are sorted, you can always compare the current smallest elements from &lt;code&gt;nums1&lt;/code&gt; and &lt;code&gt;nums2&lt;/code&gt; to find the overall next smallest element. We'll just keep doing this until we've "counted" up to our median position.&lt;/p&gt;




&lt;h2&gt;
  
  
  🪜 Approach: Simulating the Merge (O(m+n) Time)
&lt;/h2&gt;

&lt;p&gt;Let's break down the step-by-step logic for our beginner-friendly O(m+n) approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Calculate Total Length &amp;amp; Median Positions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Find the total number of elements: &lt;code&gt;total_len = len(nums1) + len(nums2)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Determine if we need one median element (odd &lt;code&gt;total_len&lt;/code&gt;) or two (even &lt;code&gt;total_len&lt;/code&gt;). We'll need to iterate enough times to identify these elements.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialize Pointers and Median Candidates:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Use two pointers, &lt;code&gt;i&lt;/code&gt; for &lt;code&gt;nums1&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; for &lt;code&gt;nums2&lt;/code&gt;, both starting at &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Introduce two variables, &lt;code&gt;m1&lt;/code&gt; and &lt;code&gt;m2&lt;/code&gt;. &lt;code&gt;m1&lt;/code&gt; will store the &lt;em&gt;current&lt;/em&gt; element identified as we iterate through the "merged" sequence. &lt;code&gt;m2&lt;/code&gt; will store the &lt;em&gt;previous&lt;/em&gt; &lt;code&gt;m1&lt;/code&gt; value. This is crucial for when we need to average two middle elements (even &lt;code&gt;total_len&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iterate to the Median Position(s):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We need to find elements up to &lt;code&gt;total_len // 2 + 1&lt;/code&gt;. This ensures that for an even &lt;code&gt;total_len&lt;/code&gt;, we capture both &lt;code&gt;(total_len // 2) - 1&lt;/code&gt; and &lt;code&gt;(total_len // 2)&lt;/code&gt; elements (0-indexed).&lt;/li&gt;
&lt;li&gt;  In each iteration:

&lt;ul&gt;
&lt;li&gt;  First, &lt;code&gt;m2 = m1&lt;/code&gt;. The current &lt;code&gt;m1&lt;/code&gt; becomes the "second to last" median candidate.&lt;/li&gt;
&lt;li&gt;  Then, compare the elements &lt;code&gt;nums1[i]&lt;/code&gt; and &lt;code&gt;nums2[j]&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;nums1[i]&lt;/code&gt; is smaller (or &lt;code&gt;nums2&lt;/code&gt; is exhausted), pick &lt;code&gt;nums1[i]&lt;/code&gt;, assign it to &lt;code&gt;m1&lt;/code&gt;, and increment &lt;code&gt;i&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Otherwise (if &lt;code&gt;nums2[j]&lt;/code&gt; is smaller or &lt;code&gt;nums1&lt;/code&gt; is exhausted), pick &lt;code&gt;nums2[j]&lt;/code&gt;, assign it to &lt;code&gt;m1&lt;/code&gt;, and increment &lt;code&gt;j&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Calculate and Return the Median:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  After the loop finishes, &lt;code&gt;m1&lt;/code&gt; will hold the element at &lt;code&gt;total_len // 2&lt;/code&gt; (0-indexed) and &lt;code&gt;m2&lt;/code&gt; will hold the element at &lt;code&gt;(total_len // 2) - 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;total_len&lt;/code&gt; is odd, &lt;code&gt;m1&lt;/code&gt; is our median.&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;total_len&lt;/code&gt; is even, the median is the average of &lt;code&gt;m1&lt;/code&gt; and &lt;code&gt;m2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach effectively "walks" through the merged sorted array without actually building it, stopping exactly when it finds the necessary median elements.&lt;/p&gt;




&lt;h2&gt;
  
  
  💻 Code: The O(m+n) Merge-Like Solution (Python)
&lt;/h2&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;findMedianSortedArrays&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;nums1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&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;nums2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&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;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&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;nums1&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;nums2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;total_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;

        &lt;span class="c1"&gt;# m1 will store the element at the current "median" position
&lt;/span&gt;        &lt;span class="c1"&gt;# m2 will store the element at the "median-1" position (for even total_len)
&lt;/span&gt;        &lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; 

        &lt;span class="n"&gt;i&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# Pointers for nums1 and nums2
&lt;/span&gt;
        &lt;span class="c1"&gt;# Iterate (m + n) // 2 + 1 times to find the median element(s)
&lt;/span&gt;        &lt;span class="c1"&gt;# We need to iterate one more time than total_len // 2 for even arrays
&lt;/span&gt;        &lt;span class="c1"&gt;# to capture both m1 and m2 correctly.
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;count&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;total_len&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&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;m2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m1&lt;/span&gt; &lt;span class="c1"&gt;# m2 takes the value m1 had in the previous iteration
&lt;/span&gt;
            &lt;span class="c1"&gt;# Logic to pick the next smallest element from either nums1 or nums2
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;and&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;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;nums1&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;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nums2&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="n"&gt;m1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nums1&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="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="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# j &amp;lt; n and (i &amp;gt;= m or nums2[j] &amp;lt;= nums1[i])
&lt;/span&gt;                &lt;span class="n"&gt;m1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nums2&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="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="c1"&gt;# Check if the sum of n and m is odd.
&lt;/span&gt;        &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&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;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⏱️ Time &amp;amp; Space Complexity Analysis
&lt;/h2&gt;

&lt;p&gt;For the O(m+n) solution we just explored:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Time Complexity: &lt;code&gt;O(m+n)&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  We iterate through the arrays up to &lt;code&gt;(m+n)/2 + 1&lt;/code&gt; times in the worst case. This is directly proportional to the total number of elements.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Space Complexity: &lt;code&gt;O(1)&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  We only use a few extra variables (&lt;code&gt;m1&lt;/code&gt;, &lt;code&gt;m2&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, &lt;code&gt;total_len&lt;/code&gt;). We don't create any new arrays proportional to the input size.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A Note on the &lt;code&gt;O(log(m+n))&lt;/code&gt; Requirement:&lt;/strong&gt;&lt;br&gt;
The problem statement &lt;em&gt;does&lt;/em&gt; ask for an &lt;code&gt;O(log(m+n))&lt;/code&gt; runtime complexity. This typically points to a more advanced solution involving &lt;strong&gt;binary search on partitions&lt;/strong&gt;. That approach is significantly more complex and often involves finding a "split point" in both arrays such that the elements to the left of the split form the lower half of the merged array, and elements to the right form the upper half.&lt;/p&gt;

&lt;p&gt;While our &lt;code&gt;O(m+n)&lt;/code&gt; solution is intuitive and a great starting point, mastering the &lt;code&gt;O(log(m+n))&lt;/code&gt; binary search approach is a fantastic next step once you're comfortable with this basic idea!&lt;/p&gt;




&lt;h2&gt;
  
  
  🌟 Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Simulate, Don't Always Build:&lt;/strong&gt; For problems involving sorted arrays and finding specific elements (like the median or k-th smallest), you often don't need to physically merge them. Simulating the merge with pointers is efficient.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Median Logic:&lt;/strong&gt; Remember the difference between odd and even total lengths for calculating the median. Keeping track of two "median candidate" variables (&lt;code&gt;m1&lt;/code&gt; and &lt;code&gt;m2&lt;/code&gt;) helps simplify this.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Complexity Matters:&lt;/strong&gt; Always be aware of the optimal time complexity required for a problem. While an &lt;code&gt;O(m+n)&lt;/code&gt; solution is often a good first step, understanding the &lt;code&gt;O(log(m+n))&lt;/code&gt; binary search approach for this specific problem is key for interviews.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding, and keep practicing! You're doing great!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Author Account: p1Hzd8mRM8&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Time Published: 2026-05-17 00:12:16&lt;/em&gt;&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LeetCode Solution: 3. Longest Substring Without Repeating Characters</title>
      <dc:creator>Hommies</dc:creator>
      <pubDate>Sat, 16 May 2026 17:38:35 +0000</pubDate>
      <link>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-3-longest-substring-without-repeating-characters-l9l</link>
      <guid>https://dev.to/hommies_fcbf2afe8ddb0c2a7/leetcode-solution-3-longest-substring-without-repeating-characters-l9l</guid>
      <description>&lt;h1&gt;
  
  
  Sliding into Success: Solving LeetCode 3 - Longest Substring Without Repeating Characters
&lt;/h1&gt;

&lt;p&gt;Hey there, aspiring competitive programmers and curious coders!&lt;/p&gt;

&lt;p&gt;Today, we're diving into a classic LeetCode problem that's a fantastic introduction to a super useful technique: the &lt;em&gt;Sliding Window&lt;/em&gt;. It's problem #3, "Longest Substring Without Repeating Characters," and it's a rite of passage for many!&lt;/p&gt;

&lt;p&gt;Don't let the name intimidate you. By the end of this post, you'll not only understand it but also appreciate the elegance of its solution.&lt;/p&gt;




&lt;h3&gt;
  
  
  Problem Explanation: What are we actually trying to find?
&lt;/h3&gt;

&lt;p&gt;The problem asks us to find the length of the longest &lt;strong&gt;substring&lt;/strong&gt; within a given string &lt;code&gt;s&lt;/code&gt; that doesn't have any repeating characters.&lt;/p&gt;

&lt;p&gt;Let's break down some keywords:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;String &lt;code&gt;s&lt;/code&gt;&lt;/strong&gt;: This is our input, like &lt;code&gt;"abcabcbb"&lt;/code&gt; or &lt;code&gt;"pwwkew"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Substring&lt;/strong&gt;: This is a &lt;em&gt;contiguous&lt;/em&gt; sequence of characters within a string. For example, in &lt;code&gt;"abc"&lt;/code&gt;, &lt;code&gt;"a"&lt;/code&gt;, &lt;code&gt;"ab"&lt;/code&gt;, &lt;code&gt;"bc"&lt;/code&gt;, &lt;code&gt;"abc"&lt;/code&gt; are substrings. &lt;code&gt;"ac"&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a substring because the characters aren't consecutive.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Without repeating characters&lt;/strong&gt;: Every character in our substring must be unique. If we see 'a', we can't have another 'a' in the same substring.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Let's look at the examples:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;s = "abcabcbb"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;"abc"&lt;/code&gt; is a substring without repeating characters (length 3).&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;"bca"&lt;/code&gt; is also a substring without repeating characters (length 3).&lt;/li&gt;
&lt;li&gt;  The longest such substring has a length of &lt;strong&gt;3&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;s = "bbbbb"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;"b"&lt;/code&gt; is the longest substring without repeating characters (length 1).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;s = "pwwkew"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;"pw"&lt;/code&gt; (length 2)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;"wke"&lt;/code&gt; (length 3) - This is our winner!&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;"kew"&lt;/code&gt; (length 3) - Another winner!&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;IMPORTANT&lt;/strong&gt;: &lt;code&gt;"pwke"&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a substring, it's a subsequence. Remember, substrings must be contiguous. &lt;code&gt;"wke"&lt;/code&gt; is valid because 'w', 'k', 'e' are consecutive.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Our goal is to return just the &lt;em&gt;length&lt;/em&gt; of this longest unique-character substring.&lt;/p&gt;




&lt;h3&gt;
  
  
  Intuition: The "Aha!" Moment
&lt;/h3&gt;

&lt;p&gt;Imagine you're looking at a street. You want to find the longest stretch of unique houses (characters). You start walking, adding each new house you see to your mental list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If you see a house you've already listed, you know your current unique stretch has ended &lt;em&gt;at or before&lt;/em&gt; this duplicate.&lt;/li&gt;
&lt;li&gt;  To continue, you can't just skip the duplicate. You need to "forget" houses from the &lt;em&gt;beginning&lt;/em&gt; of your current stretch until the duplicate is no longer in your list. Then, you can add the current house and keep walking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This "walking" and "forgetting" sounds like a &lt;strong&gt;Sliding Window&lt;/strong&gt;! We'll have two pointers: &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;right&lt;/code&gt; expands our window, bringing new characters in.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;left&lt;/code&gt; shrinks our window when we encounter a duplicate, removing characters from the start until the duplicate is gone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At each step, we'll keep track of the maximum length our window has ever achieved.&lt;/p&gt;




&lt;h3&gt;
  
  
  Approach: Building Our Sliding Window
&lt;/h3&gt;

&lt;p&gt;We'll use two pointers, &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt;, to define our current "window" (substring). We also need a way to quickly check if a character is already in our current window. A &lt;code&gt;Set&lt;/code&gt; (or &lt;code&gt;HashSet&lt;/code&gt; in some languages) is perfect for this, as it allows for O(1) average time complexity for add, remove, and check operations.&lt;/p&gt;

&lt;p&gt;Here's the step-by-step logic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialize&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;left = 0&lt;/code&gt;: This pointer marks the beginning of our current unique substring.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;max_length = 0&lt;/code&gt;: This will store the maximum length we've found so far.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;char_set = set()&lt;/code&gt;: An empty set to store characters currently within our window &lt;code&gt;[left, right]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iterate with &lt;code&gt;right&lt;/code&gt; pointer&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We'll use a &lt;code&gt;for&lt;/code&gt; loop, letting &lt;code&gt;right&lt;/code&gt; traverse the input string &lt;code&gt;s&lt;/code&gt; from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;len(s) - 1&lt;/code&gt;. This pointer expands our window to the right.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check for Duplicates&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Inside the loop, before adding &lt;code&gt;s[right]&lt;/code&gt; to our &lt;code&gt;char_set&lt;/code&gt;, we check if &lt;code&gt;s[right]&lt;/code&gt; is &lt;em&gt;already&lt;/em&gt; in &lt;code&gt;char_set&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;If &lt;code&gt;s[right]&lt;/code&gt; IS in &lt;code&gt;char_set&lt;/code&gt; (duplicate found)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  This means our current window &lt;code&gt;s[left...right-1]&lt;/code&gt; has a duplicate if &lt;code&gt;s[right]&lt;/code&gt; is added.&lt;/li&gt;
&lt;li&gt;  To resolve this, we need to shrink our window from the &lt;code&gt;left&lt;/code&gt; side.&lt;/li&gt;
&lt;li&gt;  We enter a &lt;code&gt;while&lt;/code&gt; loop:

&lt;ul&gt;
&lt;li&gt;  Remove &lt;code&gt;s[left]&lt;/code&gt; from &lt;code&gt;char_set&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Increment &lt;code&gt;left&lt;/code&gt; by 1.&lt;/li&gt;
&lt;li&gt;  Repeat this until &lt;code&gt;s[right]&lt;/code&gt; is no longer in &lt;code&gt;char_set&lt;/code&gt;. This ensures our window &lt;code&gt;s[left...right-1]&lt;/code&gt; is unique &lt;em&gt;before&lt;/em&gt; we add &lt;code&gt;s[right]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;If &lt;code&gt;s[right]&lt;/code&gt; IS NOT in &lt;code&gt;char_set&lt;/code&gt; (unique character)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  Great! We can safely add &lt;code&gt;s[right]&lt;/code&gt; to &lt;code&gt;char_set&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Update &lt;code&gt;max_length&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  After &lt;code&gt;s[right]&lt;/code&gt; has been added (and duplicates handled if any), our current window &lt;code&gt;s[left...right]&lt;/code&gt; is guaranteed to be unique.&lt;/li&gt;
&lt;li&gt;  The length of this current unique window is &lt;code&gt;right - left + 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Update &lt;code&gt;max_length = max(max_length, right - left + 1)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Return&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  After the &lt;code&gt;right&lt;/code&gt; pointer has traversed the entire string, &lt;code&gt;max_length&lt;/code&gt; will hold the length of the longest substring without repeating characters. Return &lt;code&gt;max_length&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's walk through &lt;code&gt;s = "abcabcbb"&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;right&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;s[right]&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;char_set&lt;/code&gt; (before add)&lt;/th&gt;
&lt;th&gt;Duplicate?&lt;/th&gt;
&lt;th&gt;Actions (if duplicate)&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;char_set&lt;/code&gt; (after add)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;left&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Current Length (&lt;code&gt;right - left + 1&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;max_length&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;'a'&lt;/td&gt;
&lt;td&gt;{}&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;{'a'}&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;'b'&lt;/td&gt;
&lt;td&gt;{'a'}&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;{'a', 'b'}&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;'c'&lt;/td&gt;
&lt;td&gt;{'a', 'b'}&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;{'a', 'b', 'c'}&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;'a'&lt;/td&gt;
&lt;td&gt;{'a', 'b', 'c'}&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;char_set.remove('a')&lt;/code&gt;, &lt;code&gt;left=1&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;{'b', 'c', 'a'}&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3 (&lt;code&gt;3 - 1 + 1&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;'b'&lt;/td&gt;
&lt;td&gt;{'b', 'c', 'a'}&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;char_set.remove('b')&lt;/code&gt;, &lt;code&gt;left=2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;{'c', 'a', 'b'}&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3 (&lt;code&gt;4 - 2 + 1&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;'c'&lt;/td&gt;
&lt;td&gt;{'c', 'a', 'b'}&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;char_set.remove('c')&lt;/code&gt;, &lt;code&gt;left=3&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;{'a', 'b', 'c'}&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3 (&lt;code&gt;5 - 3 + 1&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;'b'&lt;/td&gt;
&lt;td&gt;{'a', 'b', 'c'}&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;char_set.remove('a')&lt;/code&gt;, &lt;code&gt;left=4&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;{'b', 'c', 'b'}&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3 (&lt;code&gt;6 - 4 + 1&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;char_set.remove('b')&lt;/code&gt;, &lt;code&gt;left=5&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;{'c', 'b'}&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2 (&lt;code&gt;6 - 5 + 1&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Final &lt;code&gt;max_length&lt;/code&gt; is 3. This trace confirms the logic!&lt;/p&gt;




&lt;h3&gt;
  
  
  Code: Bringing it to life with Python
&lt;/h3&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;lengthOfLongestSubstring&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;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;# A set to keep track of characters in the current window
&lt;/span&gt;        &lt;span class="n"&gt;char_set&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="c1"&gt;# Left pointer of the sliding window
&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;# Variable to store the maximum length found so far
&lt;/span&gt;        &lt;span class="n"&gt;max_length&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;# Right pointer iterates through the string
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;right&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;s&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="c1"&gt;# If the character at 'right' is already in our set,
&lt;/span&gt;            &lt;span class="c1"&gt;# it means we have a duplicate within the current window.
&lt;/span&gt;            &lt;span class="c1"&gt;# We need to shrink the window from the 'left' until the duplicate is removed.
&lt;/span&gt;            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;s&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="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;char_set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;char_set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&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="c1"&gt;# Remove the character at 'left' from the set
&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="c1"&gt;# Move the 'left' pointer one step to the right
&lt;/span&gt;
            &lt;span class="c1"&gt;# Now that the current character s[right] is guaranteed to be unique
&lt;/span&gt;            &lt;span class="c1"&gt;# in the window [left...right-1], we can add it to our set.
&lt;/span&gt;            &lt;span class="n"&gt;char_set&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;s&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="c1"&gt;# Update the maximum length found.
&lt;/span&gt;            &lt;span class="c1"&gt;# The current window length is (right - left + 1).
&lt;/span&gt;            &lt;span class="n"&gt;max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&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="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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;

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

&lt;/div&gt;






&lt;h3&gt;
  
  
  Time &amp;amp; Space Complexity Analysis
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Time Complexity: O(N)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Both the &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt; pointers traverse the string &lt;code&gt;s&lt;/code&gt; at most once.&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;right&lt;/code&gt; pointer moves &lt;code&gt;N&lt;/code&gt; times.&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;left&lt;/code&gt; pointer also moves at most &lt;code&gt;N&lt;/code&gt; times across all iterations of the outer loop.&lt;/li&gt;
&lt;li&gt;  Set operations (add, remove, check &lt;code&gt;in&lt;/code&gt;) take O(1) average time.&lt;/li&gt;
&lt;li&gt;  Therefore, the total time complexity is linear, O(N), where &lt;code&gt;N&lt;/code&gt; is the length of the string &lt;code&gt;s&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity: O(min(M, N))&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We use a &lt;code&gt;char_set&lt;/code&gt; to store unique characters within the window.&lt;/li&gt;
&lt;li&gt;  In the worst case, if all characters in the string are unique (e.g., "abcdefg"), the set will store &lt;code&gt;N&lt;/code&gt; characters.&lt;/li&gt;
&lt;li&gt;  However, if the character set is limited (e.g., lowercase English letters, &lt;code&gt;M=26&lt;/code&gt;), the set will store at most &lt;code&gt;M&lt;/code&gt; characters.&lt;/li&gt;
&lt;li&gt;  So, the space complexity is bounded by the smaller of the string's length &lt;code&gt;N&lt;/code&gt; and the size of the character set &lt;code&gt;M&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Sliding Window Technique&lt;/strong&gt;: This problem is a prime example of the "sliding window" pattern, which is incredibly useful for array/string problems involving a contiguous subsegment. It helps optimize solutions from O(N^2) (e.g., checking every possible substring) to O(N).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;Set&lt;/code&gt; for Uniqueness Checks&lt;/strong&gt;: Using a hash set (&lt;code&gt;set&lt;/code&gt; in Python) is crucial for efficient O(1) average-time lookups, insertions, and deletions, which allows the sliding window to perform optimally.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Two Pointers (Left and Right)&lt;/strong&gt;: The &lt;code&gt;left&lt;/code&gt; pointer helps shrink the window when a condition is violated (duplicate found), while the &lt;code&gt;right&lt;/code&gt; pointer expands it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep practicing, and you'll master these patterns in no time! Happy coding!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Author Account: p1Hzd8mRM8&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Time Published: 2026-05-16 23:08:20&lt;/em&gt;&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>dsa</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
