<?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: Nishant Gaurav </title>
    <description>The latest articles on DEV Community by Nishant Gaurav  (@im_nishant).</description>
    <link>https://dev.to/im_nishant</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3755207%2Fccfc2018-a401-48be-ac00-4b0aed7027c9.jpeg</url>
      <title>DEV Community: Nishant Gaurav </title>
      <link>https://dev.to/im_nishant</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/im_nishant"/>
    <language>en</language>
    <item>
      <title>Every API in This Series Was Built for Speed. SOAP Was Built for Trust.</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Sat, 19 Sep 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/every-api-in-this-series-was-built-for-speed-soap-was-built-for-trust-1eda</link>
      <guid>https://dev.to/im_nishant/every-api-in-this-series-was-built-for-speed-soap-was-built-for-trust-1eda</guid>
      <description>&lt;p&gt;REST is flexible. GraphQL is precise. gRPC is fast. WebSockets are persistent. Webhooks are reactive. Every API type you've learned in this series optimises for developer convenience or performance.&lt;/p&gt;

&lt;p&gt;SOAP optimises for something different: airtight security, strict contracts, and zero ambiguity. That's why it was built in 1998, why most developers think it's dead, and why banks and insurance companies still run billions of transactions through it every single day.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why SOAP Still Exists
&lt;/h2&gt;

&lt;p&gt;When you transfer money between banks, send an insurance claim, or file a government tax return through software, the stakes of a malformed or tampered message are severe. A missing field isn't a bug to fix in the next deploy. It's a financial error with legal consequences.&lt;/p&gt;

&lt;p&gt;REST doesn't enforce message structure. You can send whatever JSON you want and the server has to validate it manually. SOAP enforces structure at the protocol level. If the message doesn't match the defined schema exactly, it is rejected before it ever reaches application code.&lt;/p&gt;

&lt;p&gt;That strictness is not a limitation. For industries where every message must be verifiable, auditable, and tamper-proof, it's the entire point.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  What a SOAP Message Looks Like
&lt;/h2&gt;

&lt;p&gt;Every SOAP message is XML wrapped in a strict four-part envelope. There are no exceptions to this structure.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Every SOAP message follows this exact envelope structure, no exceptions --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;soap:Envelope&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:soap=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/envelope/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;soap:Header&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Authentication and security tokens live here --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;wsse:Security&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;wsse:UsernameToken&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wsse:Username&amp;gt;&lt;/span&gt;bankuser&lt;span class="nt"&gt;&amp;lt;/wsse:Username&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wsse:Password&amp;gt;&lt;/span&gt;hashedpassword&lt;span class="nt"&gt;&amp;lt;/wsse:Password&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/wsse:UsernameToken&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/wsse:Security&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/soap:Header&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;soap:Body&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- The actual request payload --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GetAccountBalance&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;AccountId&amp;gt;&lt;/span&gt;ACC123456&lt;span class="nt"&gt;&amp;lt;/AccountId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Currency&amp;gt;&lt;/span&gt;INR&lt;span class="nt"&gt;&amp;lt;/Currency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/GetAccountBalance&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/soap:Body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/soap:Envelope&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where REST lets you structure your JSON however you want, SOAP's XML schema is defined in advance in a &lt;strong&gt;WSDL file&lt;/strong&gt; (Web Services Description Language). The WSDL is a machine-readable contract that describes every operation the service supports, every field each message must contain, and every data type each field must be. Both sides must conform to it exactly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Security Layer That Sets SOAP Apart
&lt;/h2&gt;

&lt;p&gt;Every other API type in this series relies on HTTPS for transport security. SOAP goes further with &lt;strong&gt;WS-Security&lt;/strong&gt;, a standard that operates at the message level rather than the transport level.&lt;/p&gt;

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

&lt;p&gt;This distinction matters in regulated industries. HTTPS secures the connection between two points. If there is a proxy, a load balancer, or any intermediary in the chain, the message is decrypted and re-encrypted at each hop. WS-Security encrypts the message body itself, so it stays protected end-to-end regardless of how many systems it passes through.&lt;/p&gt;




&lt;h2&gt;
  
  
  SOAP vs REST: The Real Trade-off
&lt;/h2&gt;

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




&lt;h2&gt;
  
  
  When to Use SOAP, When Not To
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use SOAP when&lt;/strong&gt; you are integrating with a banking API, a government tax system, a healthcare records platform, or any legacy enterprise system that exposes a SOAP endpoint. You will rarely choose SOAP for a new greenfield project, but in regulated industries, the compliance requirements often mandate it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skip SOAP when&lt;/strong&gt; you control both sides of the integration and have no legacy or compliance constraints. The verbosity of XML, the complexity of WSDL files, and the lack of caching support make SOAP slower to build and harder to debug than REST for modern applications.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;SOAP is not a relic that survived by accident. It survived because the industries that adopted it have requirements that REST genuinely cannot meet: message-level encryption, digital signatures embedded in every payload, and machine-enforced schemas with no room for variation.&lt;/p&gt;

&lt;p&gt;You've now completed the full API picture. REST for standard web communication. GraphQL for flexible data fetching. WebSockets for real-time two-way connections. Webhooks for event-driven server notifications. gRPC for high-speed internal service communication. SOAP for strict, secure, enterprise-grade integration.&lt;/p&gt;

&lt;p&gt;Every tool exists because a specific problem made the previous tools insufficient. That's the pattern worth carrying forward.&lt;/p&gt;

</description>
      <category>api</category>
      <category>soap</category>
      <category>restapi</category>
      <category>rest</category>
    </item>
    <item>
      <title>Count Subsets With a Given Difference: Two Equations, One DP Problem</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Sat, 19 Sep 2026 10:28:48 +0000</pubDate>
      <link>https://dev.to/im_nishant/count-subsets-with-a-given-difference-two-equations-one-dp-problem-5hhb</link>
      <guid>https://dev.to/im_nishant/count-subsets-with-a-given-difference-two-equations-one-dp-problem-5hhb</guid>
      <description>&lt;p&gt;Chapter 5 reduced a two-subset problem to a one-number search using algebra. This chapter does the same thing, but this time the algebra hands you a direct answer instead of a search range.&lt;/p&gt;

&lt;p&gt;The last chapter asked: which subset sum &lt;code&gt;S1&lt;/code&gt; minimises &lt;code&gt;|R - 2S1|&lt;/code&gt;? This chapter asks: given that &lt;code&gt;S1 - S2 = D&lt;/code&gt;, how many ways can that partition happen?&lt;/p&gt;

&lt;p&gt;Different question. Same two equations. Same Count Subset Sum DP you already know.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Given an array and a difference &lt;code&gt;D&lt;/code&gt;, count the number of ways to divide the array into two subsets &lt;code&gt;S1&lt;/code&gt; and &lt;code&gt;S2&lt;/code&gt; such that &lt;code&gt;S1 - S2 = D&lt;/code&gt;.&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="n"&gt;arr&lt;/span&gt; &lt;span class="o"&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;D&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;Find&lt;/span&gt; &lt;span class="nb"&gt;all&lt;/span&gt; &lt;span class="n"&gt;partitions&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;difference&lt;/span&gt; &lt;span class="n"&gt;between&lt;/span&gt; &lt;span class="n"&gt;subset&lt;/span&gt; &lt;span class="n"&gt;sums&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;exactly&lt;/span&gt; &lt;span class="mf"&gt;1.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Algebra (Again)
&lt;/h2&gt;

&lt;p&gt;You've seen this setup before. Every element goes into either &lt;code&gt;S1&lt;/code&gt; or &lt;code&gt;S2&lt;/code&gt;, so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S1 + S2 = R     (R = total sum)
S1 - S2 = D     (given)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add both equations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S1 + S2 = R
S1 - S2 = D
───────────────
2S1     = R + D

S1 = (R + D) / 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to find both subsets. Find one subset whose sum equals &lt;code&gt;(R + D) / 2&lt;/code&gt;. Count how many such subsets exist. That count is your answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Count Subsets With Given Difference just became Count Subset Sum.&lt;/strong&gt;&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Two Checks Before You Touch the DP
&lt;/h2&gt;

&lt;p&gt;Both of these need to pass before computing &lt;code&gt;S1 = (R + D) / 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check 1: &lt;code&gt;|D| &amp;lt;= R&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The maximum difference between two subsets is the total sum itself (one subset gets everything, the other gets nothing). If &lt;code&gt;D&lt;/code&gt; exceeds &lt;code&gt;R&lt;/code&gt;, the partition is impossible.&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;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&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;total&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Check 2: &lt;code&gt;(R + D)&lt;/code&gt; must be even&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;S1 = (R + D) / 2&lt;/code&gt; must be an integer because subset sums are always integers. If &lt;code&gt;R + D&lt;/code&gt; is odd, no valid partition exists.&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="nf"&gt;if &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;diff&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;0&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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




&lt;h2&gt;
  
  
  The DP: Count Subset Sum (Returning Again)
&lt;/h2&gt;

&lt;p&gt;The transition is identical to Chapter 4. Store the count of subsets, combine with &lt;code&gt;+&lt;/code&gt;, initialise only &lt;code&gt;T[0][0] = 1&lt;/code&gt;, and loop &lt;code&gt;j&lt;/code&gt; from &lt;code&gt;0&lt;/code&gt; not &lt;code&gt;1&lt;/code&gt;.&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;subsetSum&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subset&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;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# T[i][j] = number of subsets using first i elements
&lt;/span&gt;        &lt;span class="c1"&gt;# whose sum is exactly j
&lt;/span&gt;        &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subset&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;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;# Only base case: one way to make sum 0
&lt;/span&gt;        &lt;span class="c1"&gt;# with zero elements — the empty subset
&lt;/span&gt;        &lt;span class="n"&gt;T&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="mi"&gt;1&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;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;# Start from 0 — zeros must flow through
&lt;/span&gt;            &lt;span class="c1"&gt;# the transition naturally
&lt;/span&gt;            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subset&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;arr&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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# Count ways from both choices
&lt;/span&gt;                    &lt;span class="n"&gt;T&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="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="n"&gt;arr&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;# include
&lt;/span&gt;                        &lt;span class="o"&gt;+&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="c1"&gt;# exclude
&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="c1"&gt;# Element too large — must exclude
&lt;/span&gt;                    &lt;span class="n"&gt;T&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;T&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;T&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="n"&gt;subset&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;countPartitions&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;diff&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="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Partition is impossible if difference exceeds total
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&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;total&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="c1"&gt;# S1 = (R+D)/2 must be an integer
&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;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;diff&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;0&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="c1"&gt;# Directly calculated — no searching needed
&lt;/span&gt;        &lt;span class="n"&gt;subset&lt;/span&gt; &lt;span class="o"&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;diff&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subsetSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Target Sum: The Same Problem in Disguise
&lt;/h2&gt;

&lt;p&gt;LeetCode's Target Sum problem asks something that looks completely different: given an array of numbers, assign a &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; sign to every element. Count the ways to reach a specific target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nums = [1, 1, 2, 3]
target = 1

+1 -1 -2 +3 = 1  ✓
+1 +1 +2 -3 = 1  ✓
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It feels like a sign-assignment problem. It isn't. It's two subsets in disguise.&lt;/p&gt;

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

&lt;p&gt;Every element with a &lt;code&gt;+&lt;/code&gt; sign belongs to &lt;code&gt;S1&lt;/code&gt;. Every element with a &lt;code&gt;-&lt;/code&gt; sign belongs to &lt;code&gt;S2&lt;/code&gt;. The final expression &lt;code&gt;S1 - S2&lt;/code&gt; must equal &lt;code&gt;target&lt;/code&gt;. That gives you:&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="n"&gt;S1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;S2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
&lt;span class="n"&gt;S1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;S2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;

&lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;S1&lt;/span&gt; &lt;span class="o"&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;target&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Count the subsets with sum &lt;code&gt;S1&lt;/code&gt;. You're done.&lt;/p&gt;




&lt;h2&gt;
  
  
  Target Sum Code
&lt;/h2&gt;

&lt;p&gt;The logic is identical to Count Partitions. Only the variable names change.&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;subsetSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subset&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="c1"&gt;# T[i][j] = number of subsets using first i elements
&lt;/span&gt;        &lt;span class="c1"&gt;# whose sum is exactly j
&lt;/span&gt;        &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subset&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;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;# One way to make sum 0: empty subset
&lt;/span&gt;        &lt;span class="n"&gt;T&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="mi"&gt;1&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;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;# Start from 0 for correct zero handling
&lt;/span&gt;            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subset&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;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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# Count both choices
&lt;/span&gt;                    &lt;span class="n"&gt;T&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="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="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="c1"&gt;# include
&lt;/span&gt;                        &lt;span class="o"&gt;+&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="c1"&gt;# exclude
&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;T&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;T&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;T&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="n"&gt;subset&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;findTargetSumWays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&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="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# target cannot exceed the total range
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;total&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="c1"&gt;# S1 = (total + target)/2 must be an integer
&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;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;0&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="c1"&gt;# Same conversion as Count Partitions
&lt;/span&gt;        &lt;span class="n"&gt;subset&lt;/span&gt; &lt;span class="o"&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;target&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subsetSum&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;subset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why These Two Problems Are Identical
&lt;/h2&gt;

&lt;p&gt;Look at them side by side.&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Count Partitions&lt;/th&gt;
&lt;th&gt;Target Sum&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Equation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;S1 - S2 = D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;S1 - S2 = target&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total&lt;/td&gt;
&lt;td&gt;&lt;code&gt;S1 + S2 = R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;S1 + S2 = R&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(R + D) / 2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(R + target) / 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check 1&lt;/td&gt;
&lt;td&gt;`\&lt;/td&gt;
&lt;td&gt;D\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check 2&lt;/td&gt;
&lt;td&gt;{% raw %}&lt;code&gt;(R + D)&lt;/code&gt; even&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(R + target)&lt;/code&gt; even&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DP used&lt;/td&gt;
&lt;td&gt;Count Subset Sum&lt;/td&gt;
&lt;td&gt;Count Subset Sum&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The difference is semantic, not structural. One problem uses the word "difference," the other uses "target." The algebra is identical. The DP is identical.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full Knapsack Pattern Chain
&lt;/h2&gt;

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




&lt;h2&gt;
  
  
  Quick Revision
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Count Partitions With Given Difference&lt;/strong&gt;&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="n"&gt;S1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;S2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;D&lt;/span&gt;
&lt;span class="n"&gt;S1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;S2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;
&lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;S1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;D&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;Check&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;D&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;R&lt;/span&gt;        &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;Check&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;D&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;0&lt;/span&gt;   &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="n"&gt;subset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;D&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;countSubsetSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subset&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;Target Sum&lt;/strong&gt;&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;S1&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;S2&lt;/span&gt;
&lt;span class="n"&gt;S1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;S2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
&lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;S1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="n"&gt;Check&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;
&lt;span class="n"&gt;Check&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;0&lt;/span&gt;

&lt;span class="n"&gt;subset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;countSubsetSum&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;subset&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;Both reduce to Count Subset Sum with &lt;code&gt;T[0][0] = 1&lt;/code&gt; and loop starting from &lt;code&gt;j = 0&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;Six problems deep. The Knapsack chain is now complete for the 0/1 pattern. Every problem reused either Subset Sum or Count Subset Sum with one mathematical step in front of it. The algebra was the same twice: two equations, one variable, one direct target.&lt;/p&gt;

&lt;p&gt;The pattern to carry forward is simple. When you see two subsets and a given difference, write &lt;code&gt;S1 - S2 = D&lt;/code&gt; and &lt;code&gt;S1 + S2 = R&lt;/code&gt;, add them, and you'll have the subset sum you need to count. The two checks (&lt;code&gt;|D| &amp;lt;= R&lt;/code&gt; and &lt;code&gt;(R + D)&lt;/code&gt; is even) guard against edge cases before the DP even starts.&lt;/p&gt;

&lt;p&gt;The next part of the series moves into Unbounded Knapsack, where the structure shifts: instead of each item being available at most once, an item can be chosen as many times as needed. The choice diagram changes. The table direction changes. The core thinking stays exactly the same.&lt;/p&gt;

</description>
      <category>dsa</category>
      <category>programming</category>
      <category>dp</category>
      <category>knapsack</category>
    </item>
    <item>
      <title>Minimum Subset Sum Difference &amp; Target Sum</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Fri, 18 Sep 2026 11:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/minimum-subset-sum-difference-target-sum-2hj3</link>
      <guid>https://dev.to/im_nishant/minimum-subset-sum-difference-target-sum-2hj3</guid>
      <description>&lt;p&gt;Every chapter in this series has followed the same move: take the Knapsack structure, ask a different question, change one operation. Chapter 3 changed &lt;code&gt;max()&lt;/code&gt; to &lt;code&gt;or&lt;/code&gt;. Chapter 4 changed &lt;code&gt;or&lt;/code&gt; to &lt;code&gt;+&lt;/code&gt;. This chapter doesn't change the operation at all.&lt;/p&gt;

&lt;p&gt;Instead, it adds a layer of mathematics on top of Subset Sum that reduces a problem about two subsets into a problem about one number on a number line.&lt;/p&gt;

&lt;p&gt;Once the math clicks, the code is almost nothing new. You've already written it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Divide an array into two subsets &lt;code&gt;S1&lt;/code&gt; and &lt;code&gt;S2&lt;/code&gt; such that the absolute difference between their sums is as small as possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [1, 6, 11, 5]

One possible partition:
  S1 = [6, 5]  → sum = 11
  S2 = [1, 11] → sum = 12

  |11 - 12| = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The answer for this array is &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Mathematics That Unlocks the Problem
&lt;/h2&gt;

&lt;p&gt;Before touching any DP, work out the algebra.&lt;/p&gt;

&lt;p&gt;Every element goes into either &lt;code&gt;S1&lt;/code&gt; or &lt;code&gt;S2&lt;/code&gt;. So:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S1 + S2 = R     (R = total sum of the array)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want to minimise &lt;code&gt;|S1 - S2|&lt;/code&gt;. Substitute &lt;code&gt;S2 = R - S1&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|S1 - S2|
= |S1 - (R - S1)|
= |2S1 - R|
= |R - 2S1|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is now: &lt;strong&gt;find a possible subset sum &lt;code&gt;S1&lt;/code&gt; that minimises &lt;code&gt;|R - 2S1|&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don't need to explicitly construct either subset. You don't need to know which elements go where. You just need to know which values &lt;code&gt;S1&lt;/code&gt; can take. And that is exactly what Subset Sum answers.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  The Number Line Intuition
&lt;/h2&gt;

&lt;p&gt;Look at &lt;code&gt;|R - 2S1|&lt;/code&gt;. As &lt;code&gt;S1&lt;/code&gt; increases from &lt;code&gt;0&lt;/code&gt; toward &lt;code&gt;R&lt;/code&gt;, the expression &lt;code&gt;2S1&lt;/code&gt; moves from &lt;code&gt;0&lt;/code&gt; toward &lt;code&gt;2R&lt;/code&gt;. The difference &lt;code&gt;|R - 2S1|&lt;/code&gt; is smallest when &lt;code&gt;S1&lt;/code&gt; is closest to &lt;code&gt;R/2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 ─────────────── R/2 ─────────────── R
                   ↑
              Ideal S1
         (difference = 0 here)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The further &lt;code&gt;S1&lt;/code&gt; moves from the centre, the larger the difference grows. So the problem reduces to: among all possible subset sums, find the one closest to &lt;code&gt;R/2&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjm9hcmkdpgeaiwiakkat.png" alt=" " width="800" height="533"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why You Only Check Half the Number Line
&lt;/h2&gt;

&lt;p&gt;This is the part that confused earlier, so it gets its own section.&lt;/p&gt;

&lt;p&gt;Suppose &lt;code&gt;R = 22&lt;/code&gt; and &lt;code&gt;S1 = 8&lt;/code&gt; is a possible subset sum. Then &lt;code&gt;S2 = 14&lt;/code&gt;. The difference is &lt;code&gt;|8 - 14| = 6&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now flip the perspective. If instead you call the 14-element group &lt;code&gt;S1&lt;/code&gt;, you get &lt;code&gt;S1 = 14&lt;/code&gt; and &lt;code&gt;S2 = 8&lt;/code&gt;. The difference is still &lt;code&gt;|14 - 8| = 6&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every subset sum above &lt;code&gt;R/2&lt;/code&gt; is the mirror of a subset sum below &lt;code&gt;R/2&lt;/code&gt;. They produce identical differences. Checking both is redundant.&lt;/p&gt;

&lt;p&gt;So: run Subset Sum only up to &lt;code&gt;target = R // 2&lt;/code&gt;. This is a &lt;strong&gt;search-space limit&lt;/strong&gt;, not a claim that the answer must have a subset summing to exactly &lt;code&gt;R/2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target = R // 2

This means: "calculate possible sums from 0 to R//2 only."
It does NOT mean: "the answer must be R//2."

If no subset sums to exactly R//2, that's fine.
You want the closest possible value.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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




&lt;h2&gt;
  
  
  The Connection to Subset Sum
&lt;/h2&gt;

&lt;p&gt;The complete reduction:&lt;/p&gt;

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




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

&lt;p&gt;The Subset Sum function returns the entire last row of the DP table — every possible subset sum up to &lt;code&gt;target&lt;/code&gt; — rather than a single boolean. The minimum difference function uses that row to find the best &lt;code&gt;S1&lt;/code&gt;.&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;subsetSum&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="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;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# T[i][j] = True if sum j is achievable
&lt;/span&gt;        &lt;span class="c1"&gt;# using first i elements
&lt;/span&gt;        &lt;span class="n"&gt;T&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;target&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;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;# Sum 0 is always possible — empty subset
&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="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;T&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="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="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;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;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;target&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;arr&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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# Include OR exclude current element
&lt;/span&gt;                    &lt;span class="n"&gt;T&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="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="n"&gt;arr&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;T&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="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="c1"&gt;# Can't include — must exclude
&lt;/span&gt;                    &lt;span class="n"&gt;T&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;T&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="c1"&gt;# Return the last row — all possible sums for n elements
&lt;/span&gt;        &lt;span class="c1"&gt;# up to target
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;T&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;minDifference&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;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="c1"&gt;# Total sum R
&lt;/span&gt;        &lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Only need subset sums up to R//2
&lt;/span&gt;        &lt;span class="c1"&gt;# (mirror symmetry makes the other half redundant)
&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;R&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;# Get all possible subset sums from 0 to target
&lt;/span&gt;        &lt;span class="n"&gt;possible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subsetSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;minimum&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Check every possible S1 from 0 to R//2
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;S1&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;target&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;possible&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;S1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="c1"&gt;# S2 = R - S1
&lt;/span&gt;                &lt;span class="c1"&gt;# |S1 - S2| = |R - 2*S1|
&lt;/span&gt;                &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&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="n"&gt;S1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;minimum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;diff&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;minimum&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Walking Through the Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [1, 6, 11, 5]

R = 1 + 6 + 11 + 5 = 23

target = 23 // 2 = 11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running Subset Sum up to 11, the possible row looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sum:      0   1   2   3   4   5   6   7   8   9   10  11
possible: T   T   F   F   F   T   T   T   F   F   F   T
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now check each possible &lt;code&gt;S1&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S1 = 0  → |23 - 0|  = 23
S1 = 1  → |23 - 2|  = 21
S1 = 5  → |23 - 10| = 13
S1 = 6  → |23 - 12| = 11
S1 = 7  → |23 - 14| = 9
S1 = 11 → |23 - 22| = 1   ← minimum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Answer: &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The subset summing to 11 is &lt;code&gt;[11]&lt;/code&gt;. The remaining elements &lt;code&gt;[1, 6, 5]&lt;/code&gt; sum to 12. Difference is 1.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  The One Mistake to Avoid
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;target = R // 2&lt;/code&gt; is easy to misread. Here is what it does and does not mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target = R // 2

DOES mean: "only calculate subset sums from 0 to R//2."
           This is a search-space optimisation.

DOES NOT mean: "there must exist a subset whose sum is R//2."
               There might be no such subset — that's fine.
               You're looking for the closest possible value.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;R = 23&lt;/code&gt; and no subset sums to &lt;code&gt;11&lt;/code&gt;, you simply check all the sums that do exist (say &lt;code&gt;10&lt;/code&gt; and &lt;code&gt;7&lt;/code&gt;) and return the minimum difference among those. The &lt;code&gt;//&lt;/code&gt; is integer division because subset sums are always integers. &lt;code&gt;R/2 = 11.5&lt;/code&gt; is unreachable so &lt;code&gt;11&lt;/code&gt; is the highest integer worth checking.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full Chain So Far
&lt;/h2&gt;

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




&lt;h2&gt;
  
  
  Quick Revision
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The core math&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S1 + S2 = R
|S1 - S2| = |R - 2S1|
Goal: find S1 that minimises |R - 2S1|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The DP strategy&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Run Subset Sum up to target = R // 2
Get all possible S1 values
For each possible S1: compute |R - 2S1|
Return the minimum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The target clarification&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target = R // 2 is a search-space limit
It is NOT the required subset sum
The closest achievable S1 to R/2 is the answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to recognise this pattern&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Divide into two subsets, minimise difference"
        ↓
S1 + S2 = R
        ↓
|R - 2S1|
        ↓
Subset Sum DP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;Five problems into the Knapsack chain. Each one reused the structure from the previous chapter and added one idea: a different operation, a mathematical trick, or a search-space insight. Minimum Subset Sum Difference added the algebra that collapses a two-subset problem into a one-number search.&lt;/p&gt;

&lt;p&gt;Chapter 6 continues with Target Sum, where the question changes again: instead of minimising a difference, you assign &lt;code&gt;+&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; signs to elements and count the ways to reach a specific target. The Subset Sum table returns, and a new mathematical reduction makes it possible.&lt;/p&gt;

&lt;p&gt;The pattern keeps building. The new code keeps shrinking.&lt;/p&gt;

</description>
      <category>dp</category>
      <category>dsa</category>
      <category>algorithms</category>
      <category>knapsack</category>
    </item>
    <item>
      <title>Count of Subsets: One Word Changed. Everything Followed.</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Thu, 17 Sep 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/count-of-subsets-one-word-changed-everything-followed-4ejb</link>
      <guid>https://dev.to/im_nishant/count-of-subsets-one-word-changed-everything-followed-4ejb</guid>
      <description>&lt;p&gt;Chapter 3 ended with a hint. The shift from Knapsack to Subset Sum was a one-word change: &lt;code&gt;max()&lt;/code&gt; became &lt;code&gt;or&lt;/code&gt;. The structure stayed identical. Only the question changed.&lt;/p&gt;

&lt;p&gt;This chapter makes the next one-word change. Subset Sum asks "is it possible?" Count of Subsets asks "how many ways?" The answer shifts from a boolean to an integer. The DP table changes what it stores. And &lt;code&gt;or&lt;/code&gt; becomes &lt;code&gt;+&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's the entire difference. Everything else is the same pattern you've already seen twice.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Given an array and a target sum, count the number of subsets whose elements add up to exactly that target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [2, 3, 5]
sum = 5

Subsets that make 5:
  [5]       → 5
  [2, 3]    → 2 + 3 = 5

Answer = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Subset Sum would have returned &lt;code&gt;True&lt;/code&gt; here. Count of Subsets returns &lt;code&gt;2&lt;/code&gt;. Same array. Same target. Different question.&lt;/p&gt;




&lt;h2&gt;
  
  
  The One Change That Separates These Two Problems
&lt;/h2&gt;

&lt;p&gt;The choice diagram is identical. For every element, you include it or exclude it.&lt;/p&gt;

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

&lt;p&gt;What changes is only the combining step:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Combine with&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0/1 Knapsack&lt;/td&gt;
&lt;td&gt;Maximum value?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;max()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subset Sum&lt;/td&gt;
&lt;td&gt;Is it possible?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;or&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Count of Subsets&lt;/td&gt;
&lt;td&gt;How many ways?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The same choice diagram. Three different questions. Three different one-word operations.&lt;/p&gt;




&lt;h2&gt;
  
  
  The DP State
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T[i][j] = number of subsets using the first i elements
           whose sum is exactly j
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;T[3][5]&lt;/code&gt; means: using only the first three elements, how many different subsets add up to 5?&lt;/p&gt;

&lt;p&gt;The final answer sits at &lt;code&gt;T[n][sum]&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Initialisation: Where This Problem Gets Subtle
&lt;/h2&gt;

&lt;p&gt;Here's where Count of Subsets needs more care than its predecessors.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;T[0][0]&lt;/code&gt; represents zero elements and required sum zero. Exactly one subset achieves this: the empty subset &lt;code&gt;{}&lt;/code&gt;. So:&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="n"&gt;T&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="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For positive sums with zero elements, no subset is possible:&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="n"&gt;T&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="mf"&gt;1.&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;]&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;# handled automatically by initialising the table to zero
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The trap:&lt;/strong&gt; In previous chapters, the base case was:&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;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="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;T&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="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;# Subset Sum
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't carry this into Count of Subsets. Do not write:&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;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="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;T&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="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="mi"&gt;1&lt;/span&gt;   &lt;span class="c1"&gt;# WRONG for arrays that contain zeros
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only initialise &lt;code&gt;T[0][0] = 1&lt;/code&gt; and let the normal transition fill the rest. Here is why.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Zero Problem
&lt;/h2&gt;

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

&lt;p&gt;When the array contains zeros, the initialisation above produces wrong answers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [0]
sum = 0

Subsets with sum 0:
  {}    → empty subset
  {0}   → includes the zero element

Answer = 2, not 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [0, 0]
sum = 0

Subsets with sum 0:
  {}
  {first 0}
  {second 0}
  {first 0, second 0}

Answer = 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every zero doubles the count. Because a zero element has two valid choices, include it (sum unchanged) or exclude it (sum unchanged), and both choices are valid.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Transition
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;If&lt;/span&gt; &lt;span class="n"&gt;arr&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="o"&gt;&amp;lt;=&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;T&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;T&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="n"&gt;arr&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;T&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="err"&gt;↑&lt;/span&gt;                  &lt;span class="err"&gt;↑&lt;/span&gt;
                  &lt;span class="n"&gt;include&lt;/span&gt;             &lt;span class="n"&gt;exclude&lt;/span&gt;

&lt;span class="n"&gt;If&lt;/span&gt; &lt;span class="n"&gt;arr&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="o"&gt;&amp;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;T&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;T&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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




&lt;h2&gt;
  
  
  The Bottom-Up Solution
&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;perfectSum&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="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;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# T[i][j] = number of subsets from first i elements
&lt;/span&gt;        &lt;span class="c1"&gt;# whose sum equals j
&lt;/span&gt;        &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&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;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;# Only base case: empty subset makes sum 0 in exactly one way
&lt;/span&gt;        &lt;span class="n"&gt;T&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="mi"&gt;1&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;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;# Loop from 0 — zero elements must flow through
&lt;/span&gt;            &lt;span class="c1"&gt;# the transition naturally, not be hard-coded
&lt;/span&gt;            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&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;arr&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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# Count all ways from both choices
&lt;/span&gt;                    &lt;span class="n"&gt;T&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="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="n"&gt;arr&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;# include
&lt;/span&gt;                        &lt;span class="o"&gt;+&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="c1"&gt;# exclude
&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="c1"&gt;# Element too large — must exclude
&lt;/span&gt;                    &lt;span class="n"&gt;T&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;T&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;T&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="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice &lt;code&gt;j&lt;/code&gt; starts from &lt;code&gt;0&lt;/code&gt; in the inner loop, not from &lt;code&gt;1&lt;/code&gt;. In Subset Sum it started from &lt;code&gt;1&lt;/code&gt; because &lt;code&gt;T[i][0] = True&lt;/code&gt; was already set. Here it starts from &lt;code&gt;0&lt;/code&gt; so zero-valued elements get processed through the transition correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Memoization Version
&lt;/h2&gt;

&lt;p&gt;The same placeholder issue from Chapter 3 returns, with a new twist. You cannot use &lt;code&gt;0&lt;/code&gt; as the "not yet computed" marker because &lt;code&gt;0&lt;/code&gt; is a valid count.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;None → state not yet calculated
0    → calculated, no valid subsets exist
1+   → calculated, this many valid subsets exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3b7mcp4zpjiuyq6t6o4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3b7mcp4zpjiuyq6t6o4m.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&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;perfectSum&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="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;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# None = not yet calculated
&lt;/span&gt;        &lt;span class="c1"&gt;# 0 is a valid answer, so cannot use 0 as placeholder
&lt;/span&gt;        &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="bp"&gt;None&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;target&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;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;def&lt;/span&gt; &lt;span class="nf"&gt;solve&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

            &lt;span class="c1"&gt;# Base cases
&lt;/span&gt;            &lt;span class="k"&gt;if&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;0&lt;/span&gt; &lt;span class="ow"&gt;and&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;0&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;1&lt;/span&gt;   &lt;span class="c1"&gt;# empty subset is one valid way
&lt;/span&gt;            &lt;span class="k"&gt;if&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;0&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="c1"&gt;# no elements left, positive sum impossible
&lt;/span&gt;
            &lt;span class="c1"&gt;# Return stored answer if already calculated
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&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;T&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="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;arr&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="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="c1"&gt;# Count ways from both choices
&lt;/span&gt;                &lt;span class="n"&gt;T&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="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="p"&gt;(&lt;/span&gt;
                    &lt;span class="nf"&gt;solve&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="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;arr&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;# include
&lt;/span&gt;                    &lt;span class="o"&gt;+&lt;/span&gt;
                    &lt;span class="nf"&gt;solve&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="c1"&gt;# exclude
&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;T&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="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="nf"&gt;solve&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;# must exclude
&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;k&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;solve&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="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Mental Model You Should Carry Forward
&lt;/h2&gt;

&lt;p&gt;This is the most important thing in this chapter. Not the code. Not the zero catch. This mental model.&lt;/p&gt;

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

&lt;p&gt;Every time you see an include/exclude problem, ask one question first: what is the problem storing? The answer tells you the operation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum value → &lt;code&gt;max()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Possibility → &lt;code&gt;or&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Count → &lt;code&gt;+&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't memorise three formulas. You memorise one structure and three questions.&lt;/p&gt;




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




&lt;h2&gt;
  
  
  Quick Revision
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DP State&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T[i][j] = number of subsets using first i elements with sum j
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialisation&lt;/strong&gt;&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="n"&gt;T&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="mi"&gt;1&lt;/span&gt;    &lt;span class="c1"&gt;# only this — let zeros flow through the transition
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt;&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="c1"&gt;# If current element fits:
&lt;/span&gt;&lt;span class="n"&gt;T&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;T&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="n"&gt;arr&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;T&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="c1"&gt;# If it doesn't fit:
&lt;/span&gt;&lt;span class="n"&gt;T&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;T&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The zero catch&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [0]       → 2 subsets with sum 0
arr = [0, 0]    → 4 subsets with sum 0
arr = [0, 0, 0] → 8 subsets with sum 0

Every zero doubles the count.
Don't hard-code T[i][0] = 1.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The memoization placeholder&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;None → not calculated
0    → calculated, zero ways
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;Four problems deep in the Knapsack pattern. The choices never changed. The structure never changed. What changed each time was a single operation: &lt;code&gt;max()&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;. Those three operations cover almost every variant of this pattern you'll encounter.&lt;/p&gt;

&lt;p&gt;Chapter 5 continues with Minimum Subset Sum Difference, where the question shifts again: instead of finding a specific target, you want to minimise the gap between two subsets. The Subset Sum table you built here is exactly the tool that makes it possible.&lt;/p&gt;

</description>
      <category>dp</category>
      <category>dsa</category>
      <category>knapsack</category>
      <category>leetcode</category>
    </item>
    <item>
      <title>Subset Sum and Equal Sum Partition: Same Pattern, Different Question</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Wed, 16 Sep 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/subset-sum-and-equal-sum-partition-same-pattern-different-question-46i</link>
      <guid>https://dev.to/im_nishant/subset-sum-and-equal-sum-partition-same-pattern-different-question-46i</guid>
      <description>&lt;p&gt;Chapter 2 ended with a promise: the 0/1 Knapsack pattern unlocks a chain of problems that all look different on the surface but share the same structure underneath. Subset Sum is the first link in that chain.&lt;/p&gt;

&lt;p&gt;When you first read the Subset Sum problem, it doesn't look like Knapsack at all. There's no value array. There's nothing to maximise. It just asks: can you find a subset that adds up to a target?&lt;/p&gt;

&lt;p&gt;But look at the choices. For every element, you either include it or you don't. That's the same fork from Knapsack. The only thing that changed is what you're storing in the table and how you combine the two choices. Once you see that, Subset Sum takes about five minutes to understand. And Equal Sum Partition takes about two minutes after that.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Subset Sum Problem
&lt;/h2&gt;

&lt;p&gt;Given an array of positive integers and a target sum, does any subset of the array add up to exactly that target?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [3, 3, 4, 12, 5, 2]
sum = 9

Possible: 3 + 4 + 2 = 9 → True

arr = [3, 34, 4, 12, 5, 2]
sum = 30

No subset adds to 30 → False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The answer is a boolean, not a number. That single difference is what separates it from Knapsack.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Subset Sum Connects to 0/1 Knapsack
&lt;/h2&gt;

&lt;p&gt;The choice diagram is identical. For every element, you have two options:&lt;/p&gt;

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

&lt;p&gt;The structural difference comes at the combining step.&lt;/p&gt;

&lt;p&gt;In Knapsack, you take the &lt;code&gt;max()&lt;/code&gt; of the two choices because you want the best possible value.&lt;/p&gt;

&lt;p&gt;In Subset Sum, you use &lt;code&gt;or&lt;/code&gt; because you're asking a yes/no question. If either choice can produce the target sum, the answer is &lt;code&gt;True&lt;/code&gt;. You don't need both to work. You just need one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Knapsack:    max(take, skip)     → find the maximum value
Subset Sum:  take OR skip        → find any path that works
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one-word change (&lt;code&gt;max&lt;/code&gt; to &lt;code&gt;or&lt;/code&gt;) is the entire difference between the two problems.&lt;/p&gt;




&lt;h2&gt;
  
  
  The DP State
&lt;/h2&gt;

&lt;p&gt;The table is defined the same way as Knapsack, adapted for the new question.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T[i][j] = Can I make sum j using the first i elements?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;T[3][5]&lt;/code&gt; means: using only the first three elements of the array, is there any subset that adds up to 5?&lt;/p&gt;

&lt;p&gt;The final answer lives at &lt;code&gt;T[n][sum]&lt;/code&gt;.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Initialisation: The Base Cases
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sum = 0:&lt;/strong&gt; An empty subset always makes sum zero. So every cell in column 0 is &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No elements:&lt;/strong&gt; If you have zero elements and need a positive sum, it's impossible. Every cell in row 0 (except &lt;code&gt;T[0][0]&lt;/code&gt;) is &lt;code&gt;False&lt;/code&gt;.&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="c1"&gt;# Sum 0 is always achievable with an empty subset
&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="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;T&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="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;# No elements means no positive sum is possible
# T[0][0] stays True from the loop above
# T[0][1...sum] defaults to False from table initialisation
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Transition
&lt;/h2&gt;

&lt;p&gt;For every cell &lt;code&gt;T[i][j]&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;If the current element fits (&lt;code&gt;arr[i-1] &amp;lt;= j&lt;/code&gt;): check both choices. Include it (reduce the target by &lt;code&gt;arr[i-1]&lt;/code&gt;, look one row up) or exclude it (same target, look one row up). If either is &lt;code&gt;True&lt;/code&gt;, this cell is &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the current element doesn't fit (&lt;code&gt;arr[i-1] &amp;gt; j&lt;/code&gt;): only exclusion is possible. Copy the answer from the row above.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  The Bottom-Up Solution
&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;isSubsetSum&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="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;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# T[i][j] = can we make sum j using first i elements?
&lt;/span&gt;        &lt;span class="n"&gt;T&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;target&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;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;# Base case: sum 0 is always possible
&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="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;T&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="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="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;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;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;target&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;arr&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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;# Include OR exclude the current element
&lt;/span&gt;                    &lt;span class="n"&gt;T&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="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="n"&gt;arr&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;# include
&lt;/span&gt;                        &lt;span class="ow"&gt;or&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="c1"&gt;# exclude
&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="c1"&gt;# Element too large — must exclude
&lt;/span&gt;                    &lt;span class="n"&gt;T&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;T&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;T&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="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Memoization Version
&lt;/h2&gt;

&lt;p&gt;One important detail when writing the memoized version: you cannot use &lt;code&gt;False&lt;/code&gt; as the "not yet calculated" placeholder. &lt;code&gt;False&lt;/code&gt; is also a valid answer. The cache needs a third state that means "not computed yet."&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;None&lt;/code&gt; instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;None  → state not yet calculated
True  → calculated, sum is possible
False → calculated, sum is not possible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;isSubsetSum&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="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;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# None = not calculated yet
&lt;/span&gt;        &lt;span class="c1"&gt;# Cannot use False — False is a valid answer
&lt;/span&gt;        &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="bp"&gt;None&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;target&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;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;def&lt;/span&gt; &lt;span class="nf"&gt;solve&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

            &lt;span class="c1"&gt;# Base cases
&lt;/span&gt;            &lt;span class="k"&gt;if&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;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
            &lt;span class="k"&gt;if&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;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

            &lt;span class="c1"&gt;# Return stored answer if already calculated
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&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;T&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="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;arr&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="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;T&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="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="p"&gt;(&lt;/span&gt;
                    &lt;span class="nf"&gt;solve&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="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;arr&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;# include
&lt;/span&gt;                    &lt;span class="ow"&gt;or&lt;/span&gt;
                    &lt;span class="nf"&gt;solve&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="c1"&gt;# exclude
&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;T&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="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="nf"&gt;solve&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;# must exclude
&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;k&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;solve&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="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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




&lt;h2&gt;
  
  
  Equal Sum Partition: One Observation Away
&lt;/h2&gt;

&lt;p&gt;The problem: divide an array into two subsets such that both have equal sums.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [1, 5, 11, 5]

S1 = [1, 5, 5] → sum = 11
S2 = [11]       → sum = 11

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

&lt;/div&gt;



&lt;p&gt;At first glance this looks like a new problem. It isn't. Here's the key observation.&lt;/p&gt;

&lt;p&gt;If the total sum of the array is &lt;code&gt;R&lt;/code&gt;, and you want two equal subsets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S1 + S2 = R
S1 = S2

→ S1 + S1 = R
→ 2 × S1  = R
→ S1      = R / 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to find both subsets. Find one subset that sums to &lt;code&gt;R/2&lt;/code&gt;. The remaining elements automatically form the second subset with the same sum.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Equal Sum Partition just became a Subset Sum problem.&lt;/strong&gt;&lt;/p&gt;

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




&lt;h2&gt;
  
  
  The Odd Total Check
&lt;/h2&gt;

&lt;p&gt;If the total sum is odd, equal partition is immediately impossible. You cannot split an integer array into two subsets each summing to a non-integer.&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;if&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;2&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;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always check this first. It avoids running the entire DP on an input that can't possibly work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Equal Sum Partition 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;subsetSum&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="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;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;T&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;target&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;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;# Base case: sum 0 always possible
&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="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;T&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="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="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;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;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;target&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;arr&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="o"&gt;&amp;lt;=&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;T&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="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;T&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="n"&gt;arr&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;T&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="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;T&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;T&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;T&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="n"&gt;target&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;equalPartition&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;arr&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="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Odd total → equal partition is impossible
&lt;/span&gt;        &lt;span class="k"&gt;if&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;2&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;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

        &lt;span class="c1"&gt;# Find one subset that sums to half the total
&lt;/span&gt;        &lt;span class="c1"&gt;# The remaining elements form the second subset automatically
&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;total&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subsetSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Full Pattern So Far
&lt;/h2&gt;

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




&lt;h2&gt;
  
  
  Quick Revision
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Subset Sum&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T[i][j] = can I make sum j using first i elements?

If arr[i-1] &amp;lt;= j:
    T[i][j] = T[i-1][j-arr[i-1]] or T[i-1][j]

If arr[i-1] &amp;gt; j:
    T[i][j] = T[i-1][j]

Combine with OR, not max()
Use None (not False) as the memoization placeholder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Equal Sum Partition&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;total = sum(arr)

If total is odd → False

target = total // 2

Return SubsetSum(arr, target)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;Two problems down in the Knapsack pattern chain. The structure stays the same: include or exclude, smaller subproblem, DP state, transition. What changes each time is the question being asked and the one-line operation that combines the two choices.&lt;/p&gt;

&lt;p&gt;Knapsack asks for the maximum. Subset Sum asks for possibility. Equal Sum Partition asks for possibility after one mathematical reduction. The DP mechanics are nearly identical across all three.&lt;/p&gt;

&lt;p&gt;Chapter 4 continues the chain with Count of Subsets: instead of asking "is it possible?", it asks "how many ways?" That shift from &lt;code&gt;or&lt;/code&gt; to &lt;code&gt;+&lt;/code&gt; is the next small change that opens the next set of problems.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>beginners</category>
      <category>computerscience</category>
      <category>learning</category>
    </item>
    <item>
      <title>0/1 Knapsack: The Pattern That Unlocks Half of All DP Problems</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Tue, 15 Sep 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/01-knapsack-the-pattern-that-unlocks-half-of-all-dp-problems-2ii9</link>
      <guid>https://dev.to/im_nishant/01-knapsack-the-pattern-that-unlocks-half-of-all-dp-problems-2ii9</guid>
      <description>&lt;p&gt;In Chapter 1, we built the DP mindset: recognise choices, find repeated subproblems, store answers instead of recomputing them. We didn't write a single DP table. We didn't touch a 2D array. We just learned how to think.&lt;/p&gt;

&lt;p&gt;Chapter 2 is where that thinking meets its first real problem.&lt;/p&gt;

&lt;p&gt;0/1 Knapsack is not just one problem. It's a pattern. Once you understand it deeply, a whole family of problems: Subset Sum, Equal Partition, Count of Subsets, Target Sum, Minimum Subset Difference — start looking like variations of the same idea. That's why we start here.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is the 0/1 Knapsack Problem?
&lt;/h2&gt;

&lt;p&gt;You have a bag with a weight capacity &lt;code&gt;W&lt;/code&gt;. You have &lt;code&gt;n&lt;/code&gt; items, each with a weight and a value. You want to fill the bag to maximise total value without exceeding the capacity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Weight:  [1, 3, 4, 5]
Value:   [1, 4, 5, 7]
Capacity W = 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The critical constraint: each item can either be taken once or not taken at all. No fractions. No repeats. That's the 0/1 part.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 → skip the item
1 → take the item
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an optimisation problem (you want maximum value) where you have choices at every step (take or skip). Both conditions together are the first signal that DP is the right approach.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Step 1: Identify the Choices
&lt;/h2&gt;

&lt;p&gt;Before writing any code, draw the choices.&lt;/p&gt;

&lt;p&gt;At each item, you face exactly two options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Current Item
    /       \
 TAKE       SKIP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;If you TAKE it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You gain &lt;code&gt;val[n-1]&lt;/code&gt; value&lt;/li&gt;
&lt;li&gt;Your remaining capacity becomes &lt;code&gt;W - wt[n-1]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You move to the next item: &lt;code&gt;n-1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you SKIP it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You gain nothing&lt;/li&gt;
&lt;li&gt;Capacity stays &lt;code&gt;W&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You still move to the next item: &lt;code&gt;n-1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's one constraint on the TAKE branch: you can only take the item if it actually fits. If &lt;code&gt;wt[n-1] &amp;gt; W&lt;/code&gt;, the TAKE option disappears entirely and you can only skip.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Step 2: Identify the Base Case
&lt;/h2&gt;

&lt;p&gt;Ask: what is the smallest valid input, and what does it return?&lt;/p&gt;

&lt;p&gt;Two situations stop the recursion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;n == 0&lt;/code&gt;: no items left to consider&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;W == 0&lt;/code&gt;: no capacity remaining&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In both cases, the maximum value you can achieve is zero.&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;if&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;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;W&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;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Base case identified. Now write the recursion.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Write the Recursive Solution
&lt;/h2&gt;

&lt;p&gt;The base case and choice diagram translate directly into code. This is the whole point of drawing the choice diagram first.&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;def&lt;/span&gt; &lt;span class="nf"&gt;knapsack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wt&lt;/span&gt;&lt;span class="p"&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;W&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;# Base Case — no items or no capacity
&lt;/span&gt;    &lt;span class="k"&gt;if&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;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;W&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;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# Choice Diagram — item fits, so two choices exist
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wt&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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;W&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;max&lt;/span&gt;&lt;span class="p"&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;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="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;knapsack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wt&lt;/span&gt;&lt;span class="p"&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;W&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;wt&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="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;# TAKE
&lt;/span&gt;            &lt;span class="nf"&gt;knapsack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wt&lt;/span&gt;&lt;span class="p"&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;W&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;# SKIP
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Item doesn't fit — only one choice
&lt;/span&gt;    &lt;span class="k"&gt;else&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;knapsack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wt&lt;/span&gt;&lt;span class="p"&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;W&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;# forced SKIP
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is not something you memorised. It came directly from the choice diagram. That's the connection to hold onto.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Find the Repeated States
&lt;/h2&gt;

&lt;p&gt;The recursive solution works correctly but does redundant work. The same subproblem can appear multiple times across different branches of the recursion tree.&lt;/p&gt;

&lt;p&gt;The state of any call is completely defined by two values: &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;W&lt;/code&gt;. Everything else (the arrays &lt;code&gt;wt&lt;/code&gt; and &lt;code&gt;val&lt;/code&gt;) never changes. So if &lt;code&gt;Knapsack(3, 5)&lt;/code&gt; appears twice in the recursion tree, both calls would return the exact same answer.&lt;/p&gt;

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

&lt;p&gt;This repeated work is exactly what DP eliminates. Instead of recomputing &lt;code&gt;Knapsack(2, 2)&lt;/code&gt; twice, compute it once, store the answer, and return it when the state appears again.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Add Memoization (Top-Down DP)
&lt;/h2&gt;

&lt;p&gt;Since the state is defined by &lt;code&gt;(n, W)&lt;/code&gt;, we need a matrix of size &lt;code&gt;(n+1) × (W+1)&lt;/code&gt; to store every possible state.&lt;/p&gt;

&lt;p&gt;Why &lt;code&gt;n+1&lt;/code&gt; and &lt;code&gt;W+1&lt;/code&gt;? Because &lt;code&gt;n&lt;/code&gt; ranges from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;W&lt;/code&gt; ranges from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;W&lt;/code&gt;. We need a slot for every value including zero.&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="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-1&lt;/code&gt; means "not yet computed." Once a state is computed, its answer replaces the &lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The recursive code changes in exactly one place: before computing anything, check if the answer is already stored.&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;knapsack&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;W&lt;/span&gt;&lt;span class="p"&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;wt&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;wt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&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;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;def&lt;/span&gt; &lt;span class="nf"&gt;solve&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="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

            &lt;span class="c1"&gt;# Base Case
&lt;/span&gt;            &lt;span class="k"&gt;if&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;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;W&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;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

            &lt;span class="c1"&gt;# Already computed? Return stored answer
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;W&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="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

            &lt;span class="c1"&gt;# Choice Diagram
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;wt&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="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;T&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="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;]&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;val&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="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;solve&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="n"&gt;W&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;wt&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;# TAKE
&lt;/span&gt;                    &lt;span class="nf"&gt;solve&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="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                           &lt;span class="c1"&gt;# SKIP
&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;T&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="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;solve&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="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                    &lt;span class="c1"&gt;# forced SKIP
&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;W&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;solve&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="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diff from pure recursion to memoization is genuinely small: create the table, check before computing, store after computing. The structure of the solution doesn't change at all.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Step 6: Convert to Bottom-Up Tabulation
&lt;/h2&gt;

&lt;p&gt;Memoization starts from the top and recurses down. Tabulation starts from the bottom and builds up. Both arrive at the same answer.&lt;/p&gt;

&lt;p&gt;The connection between the two is direct:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The base cases from recursion become the initial values of the table&lt;/li&gt;
&lt;li&gt;The recursive calls become table lookups&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;W&lt;/code&gt; parameters become loop indices &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since our base case was &lt;code&gt;n == 0 or W == 0 → return 0&lt;/code&gt;, we initialise the entire table with zeros. Both base cases are handled in one line.&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="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then fill the table row by row, left to right, using the same transition from the recursive solution:&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;knapsack&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;W&lt;/span&gt;&lt;span class="p"&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;wt&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;wt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Initialise with zeros — base cases already handled
&lt;/span&gt;        &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;W&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;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;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;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;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;W&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;wt&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="o"&gt;&amp;lt;=&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;T&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="nf"&gt;max&lt;/span&gt;&lt;span class="p"&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;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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;wt&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;# TAKE
&lt;/span&gt;                        &lt;span class="n"&gt;T&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="c1"&gt;# SKIP
&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;T&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;T&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="c1"&gt;# forced SKIP
&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;T&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="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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




&lt;h2&gt;
  
  
  The Complete Flow in One Picture
&lt;/h2&gt;

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




&lt;h2&gt;
  
  
  What the Table Cell Actually Means
&lt;/h2&gt;

&lt;p&gt;This is the part worth pausing on because it makes every future DP table easier to read.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;T[i][j]&lt;/code&gt; means: the maximum value achievable using the &lt;strong&gt;first &lt;code&gt;i&lt;/code&gt; items&lt;/strong&gt; with a bag capacity of exactly &lt;code&gt;j&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;T[3][5]&lt;/code&gt; answers: "what's the best I can do with items 1, 2, and 3, if my bag holds 5 kg?" The final answer &lt;code&gt;T[n][W]&lt;/code&gt; answers the original question: best value using all &lt;code&gt;n&lt;/code&gt; items with full capacity &lt;code&gt;W&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every DP table you'll ever see has a similar interpretation. The indices represent the "state" of the problem at that point. Understanding what the indices mean is more important than knowing how to fill the table mechanically.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Pattern Unlocks
&lt;/h2&gt;

&lt;p&gt;The 0/1 Knapsack pattern is not just one problem. It's a template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0/1 Knapsack
      ↓
Subset Sum          — can we reach exactly a target weight?
      ↓
Equal Sum Partition — can we split into two equal subsets?
      ↓
Count of Subsets    — how many ways to reach a target sum?
      ↓
Min Subset Diff     — minimise the difference between two subsets
      ↓
Target Sum          — assign + and − to reach a target
      ↓
Count Subsets with Given Difference
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every problem in this list uses the same foundation: items, binary choices (take or skip), a state defined by the remaining items and remaining capacity, and a transition that combines answers from smaller states.&lt;/p&gt;

&lt;p&gt;The surface details change. The underlying structure doesn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;The 0/1 Knapsack solution was never about memorising a 2D array. It came from a choice diagram (take or skip), a base case (no items or no capacity), and a transition that said "take the maximum of both options."&lt;/p&gt;

&lt;p&gt;Memoization stored the answers to avoid repeating work. Tabulation filled those same answers bottom-up without recursion. Both used the exact same transition.&lt;/p&gt;

&lt;p&gt;Chapter 3 applies this pattern to Subset Sum, where the same take-or-skip logic solves a completely different-looking problem. If the pattern clicks here, Subset Sum will feel like a variation rather than something new.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Dynamic Programming Isn't Hard. You've Just Been Introduced to It Wrong.</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Mon, 14 Sep 2026 10:34:42 +0000</pubDate>
      <link>https://dev.to/im_nishant/dynamic-programming-isnt-hard-youve-just-been-introduced-to-it-wrong-g8h</link>
      <guid>https://dev.to/im_nishant/dynamic-programming-isnt-hard-youve-just-been-introduced-to-it-wrong-g8h</guid>
      <description>&lt;p&gt;Most people meet Dynamic Programming through a problem that looks like this: a 2D array, a nested loop, indices everywhere, and code that somehow produces a correct answer with no obvious explanation of why. They memorize the pattern, pass the interview, and still have no idea what DP actually is.&lt;/p&gt;

&lt;p&gt;That's the wrong way in.&lt;/p&gt;

&lt;p&gt;DP is not a coding pattern. It's a thinking pattern. And once you see what it's actually doing, the arrays and indices stop looking like magic and start looking like a natural consequence of a simple idea.&lt;/p&gt;

&lt;p&gt;This is Chapter 1 of a series that builds DP from scratch. No tables yet. No 2D arrays. Just the mindset, the mental model, and the exact thinking process you'll use for every DP problem that follows.&lt;/p&gt;




&lt;h2&gt;
  
  
  The One Idea Behind All of DP
&lt;/h2&gt;

&lt;p&gt;Dynamic Programming has one core insight:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you've already solved a smaller version of a problem, don't solve it again. Store the answer and reuse it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's it. Everything else, the tables, the recursion, the memoization, is just machinery built around that idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkdgc98g0ombf49zala6p.png" alt=" " width="800" height="533"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How to Recognise a DP Problem
&lt;/h2&gt;

&lt;p&gt;This is the question that matters most when you're starting out. Before worrying about tables or recursion, you need to know: is this even a DP problem?&lt;/p&gt;

&lt;p&gt;Look for three things.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choices.&lt;/strong&gt; At some point in the problem, you face a decision. Take the item or skip it. Go left or go right. Cut here or cut somewhere else. The exact choices vary by problem, but there's always a fork.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overlapping subproblems.&lt;/strong&gt; When you draw out the recursion tree, the same smaller problem appears more than once. This is the signal that matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimal substructure.&lt;/strong&gt; The best answer to the big problem is built from the best answers to its smaller pieces.&lt;/p&gt;

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

&lt;p&gt;When you see a problem, ask yourself these questions in order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Are there choices at each step?
        ↓
Can the problem be broken into smaller versions of itself?
        ↓
Do the same smaller versions appear more than once?
        ↓
Is the answer based on finding the best / count / possibility?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the answer to these is yes, you're in DP territory.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Learning Path We'll Follow
&lt;/h2&gt;

&lt;p&gt;A lot of DP tutorials start with the table. That's like learning to drive by studying the engine. We're going the other way.&lt;/p&gt;

&lt;p&gt;Every DP problem in this series will follow the same order:&lt;/p&gt;

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

&lt;p&gt;We never jump to the table. We always start with the recursive thinking, identify where the wasted work is, and then apply DP to eliminate it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two Components That Drive Every Recursive Solution
&lt;/h2&gt;

&lt;p&gt;Before you can convert recursion to DP, you need to write good recursion. Every recursive solution is built from exactly two things.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Base Case
&lt;/h3&gt;

&lt;p&gt;The base case answers one question: when do I stop?&lt;/p&gt;

&lt;p&gt;More precisely: what is the smallest valid input for this problem, and what is its answer?&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;if&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;0&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;n == 0&lt;/code&gt; is the smallest problem we've decided to handle directly, and &lt;code&gt;0&lt;/code&gt; is its answer. Before writing a single line of recursive logic, always ask: what is the smallest version of this problem, and what does it return?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Choice Diagram
&lt;/h3&gt;

&lt;p&gt;After the base case, ask: at the current step, what options do I have?&lt;/p&gt;

&lt;p&gt;Take the classic 0/1 Knapsack problem. You're at item &lt;code&gt;i&lt;/code&gt; with remaining capacity &lt;code&gt;W&lt;/code&gt;. You have exactly two choices:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcatniuqtj83b84pkbvu5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcatniuqtj83b84pkbvu5.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&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="n"&gt;If&lt;/span&gt; &lt;span class="n"&gt;wt&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;W&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;Choice&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;TAKE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nc"&gt;Knapsack&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;W&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;wt&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;Choice&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;SKIP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nc"&gt;Knapsack&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;W&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;If&lt;/span&gt; &lt;span class="n"&gt;wt&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;gt;&lt;/span&gt; &lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;Only&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;SKIP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Knapsack&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;W&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The recursion is simply exploring these choices and returning the best result. Once you draw the choice diagram for any problem, the recursive code almost writes itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Recursion to DP: Two Roads
&lt;/h2&gt;

&lt;p&gt;Once you have a recursive solution, and you've confirmed the same subproblems are being solved repeatedly, you have two ways to fix it.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Top-Down (Memoization)&lt;/strong&gt; keeps the recursive structure intact but adds a cache. Before computing a state, check if it's already been solved. If yes, return the stored answer. If no, compute it, store it, and return it.&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="c1"&gt;# Conceptual memoization pattern
&lt;/span&gt;&lt;span class="k"&gt;if&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;state&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&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;state&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# compute the answer
&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;state&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="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;state&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;Bottom-Up (Tabulation)&lt;/strong&gt; flips the direction entirely. Instead of starting from the big problem and recursing down, you start from the smallest problems and build upward, filling a table until you reach the answer you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T[0][...] → T[1][...] → T[2][...] → ... → T[n][W]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both approaches produce the same answer. Which one to use depends on the problem. We'll see both in action across the problems that follow in this series.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Mental Model That Replaces Memorisation
&lt;/h2&gt;

&lt;p&gt;Don't memorise: "DP means a 2D array."&lt;br&gt;
Don't memorise: "Two recursive calls means DP."&lt;/p&gt;

&lt;p&gt;Instead, carry this one flowchart in your head:&lt;/p&gt;

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

&lt;p&gt;The table is just how you store answers. The real work is in recognising the repeated subproblems and drawing the choice diagram clearly before you write a single line of code.&lt;/p&gt;


&lt;h2&gt;
  
  
  What's Coming in This Series
&lt;/h2&gt;

&lt;p&gt;This chapter covered the mindset. Everything that follows builds on it.&lt;/p&gt;

&lt;p&gt;The series will move through problems in a deliberate order, starting simple and adding complexity layer by layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recursion and Base Cases
        ↓
Memoization
        ↓
Tabulation
        ↓
0/1 Knapsack Pattern
        ↓
Subset Sum, Equal Partition, Count Subsets
        ↓
Unbounded Knapsack — Rod Cutting, Coin Change
        ↓
LCS, LIS, Kadane's Algorithm
        ↓
Interval DP, DP on Trees
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each problem in the series will follow the same nine-step order: understand the problem, identify choices, draw the choice diagram, find the base case, write recursion, find repeated states, add memoization, convert to tabulation, optimise if possible.&lt;/p&gt;

&lt;p&gt;We never skip to step eight. That's the whole point.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;DP is not about arrays or patterns you memorise before an interview. It's about recognising that you've seen a subproblem before and refusing to solve it twice.&lt;/p&gt;

&lt;p&gt;The choices tell you the recursive structure. The base case tells you when to stop. The repeated states tell you where DP saves work. Everything else follows from those three things.&lt;/p&gt;

&lt;p&gt;Chapter 2 starts with recursion problems that build the muscle for spotting choices and base cases before we introduce any DP optimisation at all. If recursion still feels shaky, that's exactly the right place to start.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>You Use UPI Every Day. Here Is What Actually Happens in Those Two Seconds.</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Tue, 23 Jun 2026 14:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/you-use-upi-every-day-here-is-what-actually-happens-in-those-two-seconds-33ca</link>
      <guid>https://dev.to/im_nishant/you-use-upi-every-day-here-is-what-actually-happens-in-those-two-seconds-33ca</guid>
      <description>&lt;p&gt;You scan a QR code. You enter your PIN. Two seconds later, the shopkeeper's phone buzzes. Money moved from your bank account to theirs, instantly, across potentially two completely different banks, with no cash, no card swipe, no delay.&lt;/p&gt;

&lt;p&gt;Most people treat this as magic. It isn't. It's one of the most well-engineered payment infrastructures on the planet, and understanding how it works makes you appreciate both how clever the design is and why it occasionally fails the way it does.&lt;/p&gt;

&lt;p&gt;This article walks through the full system: why UPI was invented, what the architecture looks like, which players are involved, and exactly what happens from the moment you scan a QR code to the moment that payment confirmation appears on screen.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem UPI Was Built to Solve
&lt;/h2&gt;

&lt;p&gt;Before UPI, sending money digitally in India was a painful chore. You had to juggle account numbers and IFSC codes, choosing between slow systems that took hours or fast ones that still required a long list of bank details, and making it way too frustrating for simple things like paying a street vendor or splitting a dinner bill.&lt;br&gt;
&amp;nbsp;UPI changed everything by replacing that entire mess with a single, easy-to-remember ID (like yourname@bankhandle) that sends money instantly. Turning that simple idea into something that works reliably for millions of people across hundreds of banks was the massive engineering challenge handed to the NPCI.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Layers of the UPI Architecture
&lt;/h2&gt;

&lt;p&gt;Before tracing a transaction, you need to understand who the players are. UPI has four distinct layers, each with a specific role.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Layer 1: The PSP App (Payment Service Provider)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the app on your phone. Google Pay, PhonePe, Paytm, and every other UPI app falls into this category. Their job is to provide the user interface: the screen where you scan the QR, enter the VPA, type the amount, and confirm with your PIN. They are the front end of the entire system.&lt;/p&gt;

&lt;p&gt;What most people don't realise is that these apps have zero direct connection to the payment network. Google Pay cannot move money on its own. It has no banking license. It cannot talk to NPCI. To enter the actual payment network, each PSP app must partner with a bank.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2: The PSP Partner Bank&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every PSP app is backed by a partner bank that holds its UPI license and acts as the gateway into NPCI's network. Google Pay partners with Axis Bank, ICICI, HDFC, and SBI. PhonePe partners with Yes Bank, ICICI, and Axis. Paytm Payments Bank is its own entity.&lt;/p&gt;

&lt;p&gt;When you initiate a payment in Google Pay, the app doesn't talk to NPCI. It talks to its partner bank, and that bank talks to NPCI. This distinction is important: NPCI trusts only licensed banks, not apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3: NPCI (National Payments Corporation of India)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NPCI is the backbone. It's not a payment gateway and not a bank. It is the infrastructure layer that makes the entire system possible. NPCI operates a closed, trusted network that only communicates with licensed member banks. No public API access. No direct integration for third parties. Every transaction flows through NPCI, and NPCI alone decides whether a transaction goes through.&lt;/p&gt;

&lt;p&gt;Think of NPCI as the air traffic control system for money. It doesn't fly the planes, but nothing moves without its coordination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 4: The Issuing and Acquiring Banks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The issuing bank is where the sender's money lives. The acquiring bank is where the receiver's money goes. These are your regular banks: SBI, HDFC, ICICI, Kotak, and every other bank that has joined the UPI network. They hold the actual accounts and execute the debit and credit instructions that NPCI sends them.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a VPA Actually Is
&lt;/h2&gt;

&lt;p&gt;Before tracing the transaction flow, it helps to understand the VPA more concretely.&lt;/p&gt;

&lt;p&gt;A VPA like &lt;code&gt;john@oksbi&lt;/code&gt; or &lt;code&gt;merchant@ybl&lt;/code&gt; is a pointer. It maps to a real bank account behind the scenes, but the sender never needs to know which account. NPCI maintains the mapping between VPAs and actual bank account details internally.&lt;/p&gt;

&lt;p&gt;When you scan a QR code, you're not scanning anything exotic. A UPI QR code is just a VPA encoded in a standard format. Scanning it is the same as typing the VPA manually. The QR format exists purely to reduce the chance of typos.&lt;/p&gt;

&lt;p&gt;Your VPA is registered when you set up UPI on any app. The app links your phone number, your bank account, and creates a VPA for you. The &lt;code&gt;@handle&lt;/code&gt; part (like &lt;code&gt;@oksbi&lt;/code&gt;, &lt;code&gt;@ybl&lt;/code&gt;, &lt;code&gt;@axl&lt;/code&gt;) identifies which PSP partner bank manages that VPA.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  The Full Transaction Flow: What Happens When You Pay
&lt;/h2&gt;

&lt;p&gt;Let's trace a complete transaction. You are paying a shopkeeper ₹500. You use PhonePe. Your account is at HDFC. The shopkeeper uses Google Pay and their account is at SBI.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Step 1: You create the payment intent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You open PhonePe and scan the shopkeeper's QR code. The app reads the VPA encoded in the QR, say &lt;code&gt;shopkeeper@oksbi&lt;/code&gt;. You enter ₹500 and confirm. At this point, a payment intent is created inside the app: from your VPA, to &lt;code&gt;shopkeeper@oksbi&lt;/code&gt;, amount ₹500.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: PhonePe forwards the request to its partner bank&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PhonePe cannot touch NPCI directly. So it sends this payment intent to its PSP partner bank, which in this scenario is Yes Bank. The request includes your VPA, the destination VPA, the amount, and a unique transaction reference ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Yes Bank forwards to NPCI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes Bank is a licensed member of NPCI's network. It takes PhonePe's payment request and forwards it to NPCI over the secure trusted network. NPCI now knows a payment has been initiated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: NPCI resolves the VPAs and checks balance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NPCI looks up both VPAs internally. It identifies that your VPA points to an HDFC account and the shopkeeper's VPA points to an SBI account. NPCI then sends a request to HDFC asking: does this account have at least ₹500 available?&lt;/p&gt;

&lt;p&gt;HDFC responds: yes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Authentication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NPCI sends back a challenge through the chain. Yes Bank passes it back to PhonePe, and PhonePe shows you the PIN entry screen. This is where you enter your UPI PIN. That PIN is not stored in the app. It is encrypted and sent back through the same chain to HDFC, which is the only entity that can verify it.&lt;/p&gt;

&lt;p&gt;This is a critical security design. The PSP app, including Google Pay and PhonePe, never sees your actual PIN. It only passes the encrypted value through. Only your issuing bank (HDFC in this case) has the key to verify it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: HDFC debits your account&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once HDFC validates your PIN, it debits ₹500 from your account and sends an acknowledgment back to NPCI confirming the debit was successful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7: NPCI credits the receiver's account&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the debit confirmed, NPCI instructs SBI to credit ₹500 to the shopkeeper's account. SBI does this and sends back an acknowledgment to NPCI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8: Both parties get notified&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only when NPCI receives acknowledgment from both banks (debit confirmed, credit confirmed) does it mark the transaction as complete. NPCI notifies Yes Bank, which notifies PhonePe, which shows you the success screen. Simultaneously, SBI notifies Google Pay (via ICICI, the shopkeeper's PSP partner bank), and the shopkeeper's phone buzzes.&lt;/p&gt;

&lt;p&gt;The entire sequence takes roughly one to three seconds under normal conditions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Transactions Fail (And Why Money Sometimes Comes Back)
&lt;/h2&gt;

&lt;p&gt;The failure mode you've experienced: you pay, your account is debited, but the receiver says the money didn't arrive. This feels alarming, but the system handles it deliberately.&lt;/p&gt;

&lt;p&gt;The transaction is only marked complete when NPCI receives acknowledgments from both the issuing bank (debit) and the acquiring bank (credit). If the acquiring bank's server is busy, overloaded, or temporarily unreachable, the credit acknowledgment never comes.&lt;/p&gt;

&lt;p&gt;When NPCI doesn't receive acknowledgment within a timeout window, it initiates a rollback. It instructs the issuing bank to reverse the debit. Your money comes back. This is the reconciliation mechanism working correctly.&lt;/p&gt;

&lt;p&gt;The delay between the debit and the reversal, sometimes minutes, sometimes a few hours for edge cases, is why it feels broken even when it isn't. The system is designed to never lose money in transit. Either both sides complete or neither side completes.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Why NPCI Exists Instead of Banks Talking Directly
&lt;/h2&gt;

&lt;p&gt;You might reasonably ask: why not just have HDFC and SBI talk to each other directly? Why the intermediary?&lt;/p&gt;

&lt;p&gt;Direct bank-to-bank integration doesn't scale. India has over 200 banks on the UPI network. If each bank had to maintain direct integrations with every other bank, that's potentially thousands of bilateral agreements, security audits, API contracts, and reconciliation systems. Every new bank joining the network would require bilateral connections with every existing member.&lt;/p&gt;

&lt;p&gt;NPCI solves this with a hub-and-spoke model. Every bank integrates once with NPCI. NPCI handles the routing. When HDFC needs to send money to SBI, it doesn't need to know anything about SBI's systems. It just tells NPCI, and NPCI handles the rest.&lt;/p&gt;

&lt;p&gt;This also centralises regulation and fraud detection. NPCI can monitor the entire transaction graph in real time, flag suspicious patterns, and enforce rules uniformly across the network without each bank building its own detection systems from scratch.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scale That Makes This Impressive
&lt;/h2&gt;

&lt;p&gt;NPCI processed over 13 billion UPI transactions in a single month in 2024. That's roughly 5,000 transactions per second at peak load, with real-time settlement requirements, across hundreds of banks, with fault tolerance built in.&lt;/p&gt;

&lt;p&gt;Building a system that handles that load while maintaining consistency (no double spends, no money lost in transit, no transaction completed partially) is a genuinely hard distributed systems problem. Every transaction requires coordinated state changes across at least two banks and NPCI simultaneously. If any one of them fails mid-transaction, the system has to roll back cleanly.&lt;/p&gt;

&lt;p&gt;The fact that UPI works as reliably as it does, with failure rates that are low enough to be occasional annoyances rather than a reason to avoid the system, is a significant engineering achievement. Most of the internal implementation details of how NPCI manages this at scale are not publicly documented, which is both frustrating from a learning perspective and understandable from a security perspective.&lt;/p&gt;




</description>
      <category>systemdesign</category>
      <category>fintech</category>
      <category>stripe</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Your Code Runs Locally. GitHub Actions Makes It Run Everywhere, Automatically.</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Tue, 16 Jun 2026 14:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/your-code-runs-locally-github-actions-makes-it-run-everywhere-automatically-13bc</link>
      <guid>https://dev.to/im_nishant/your-code-runs-locally-github-actions-makes-it-run-everywhere-automatically-13bc</guid>
      <description>&lt;p&gt;You've pushed code to GitHub before. You know the drill: write something, commit it, push it, then manually do whatever comes next. Run the tests. Deploy the site. Update the docs. Every time, by hand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt; is the answer to "what if that next step just happened on its own?" It lets you define automated workflows that trigger whenever something happens in your repository. A push, a pull request, a schedule, even a manual button click. The workflow runs on GitHub's servers, not yours. You define the steps in a YAML file, commit it to your repo, and GitHub takes it from there.&lt;/p&gt;

&lt;p&gt;This article walks through exactly how that works, using a real project as the example throughout: &lt;strong&gt;&lt;a href="//nishant05gaurav.github.io/recLog/"&gt;recLog&lt;/a&gt;&lt;/strong&gt;, an automated pipeline that fetches articles from Dev.to and injects them into a portfolio's HTML without any manual update.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Manual Steps After Every Push Don't Scale
&lt;/h2&gt;

&lt;p&gt;Here's the situation that &lt;strong&gt;&lt;a href="//nishant05gaurav.github.io/recLog/"&gt;recLog&lt;/a&gt;&lt;/strong&gt; was built to solve.&lt;/p&gt;

&lt;p&gt;You write an article on Dev.to. You publish it. Now your portfolio is out of date because it lists your articles as static HTML that you maintain by hand. So you open your portfolio repo, copy in a new article card, adjust the HTML, commit, and push. Every. Single. Time.&lt;/p&gt;

&lt;p&gt;This is fine once. It's annoying at ten articles. By twenty, you've already stopped doing it, which means your portfolio is quietly going stale while your actual writing keeps going.&lt;/p&gt;

&lt;p&gt;The broader pattern is everywhere in software development. You push code and need to run tests before merging. You merge to main and need to deploy. You update a dependency and need to check if anything breaks. These are predictable, repeatable steps. Doing them manually introduces delay, inconsistency, and the very human tendency to skip them when you're in a hurry.&lt;/p&gt;

&lt;p&gt;GitHub Actions turns these steps into automated workflows that live inside your repository. When the trigger fires, GitHub spins up a fresh machine, runs your defined steps in order, and reports back what happened. No server to maintain, no third-party CI tool to configure separately, no deploy keys to manage outside the repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  How GitHub Actions Actually Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The mental model
&lt;/h3&gt;

&lt;p&gt;GitHub Actions is built around four concepts you need to understand before writing a single line of YAML: &lt;strong&gt;workflows&lt;/strong&gt;, &lt;strong&gt;events&lt;/strong&gt;, &lt;strong&gt;jobs&lt;/strong&gt;, and &lt;strong&gt;steps&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;workflow&lt;/strong&gt; is the top-level automation unit. It's a single YAML file that lives in &lt;code&gt;.github/workflows/&lt;/code&gt; inside your repository. One repo can have multiple workflow files, and each one is independent.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;event&lt;/strong&gt; is what triggers the workflow. Push to main, open a pull request, publish a release, or run on a cron schedule. You define which events activate a given workflow in the &lt;code&gt;on:&lt;/code&gt; block at the top of the file.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;job&lt;/strong&gt; is a collection of steps that run together on the same machine. By default, jobs in the same workflow run in parallel. If one job depends on another, you declare that explicitly and GitHub sequences them accordingly.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;step&lt;/strong&gt; is a single action within a job. It's either a shell command you write directly, or a pre-built action from the GitHub Actions marketplace that someone else wrote and you call by name.&lt;/p&gt;

&lt;p&gt;Every job runs on a fresh virtual machine, called a &lt;strong&gt;runner&lt;/strong&gt;, that GitHub provisions and discards after the job completes. This means each run starts from a clean state. Anything you need (dependencies, credentials, files from your repo) has to be explicitly set up within the workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  The workflow file
&lt;/h3&gt;

&lt;p&gt;Here's the recLog workflow file, which is the actual file that keeps the portfolio in sync automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/main.yml&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sync Dev.to Articles&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;          &lt;span class="c1"&gt;# runs whenever code is pushed to main&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*/6&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;    &lt;span class="c1"&gt;# also runs every 6 hours automatically&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sync&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;    &lt;span class="c1"&gt;# GitHub provisions a fresh Ubuntu machine for this job&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Step 1: check out the repository so the runner has access to the code&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 2: install Python on the runner&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 3: install the project's dependencies&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 4: run the pipeline (fetch, deduplicate, inject)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run sync pipeline&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python main.py&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;DEVTO_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DEVTO_API_KEY }}&lt;/span&gt;  &lt;span class="c1"&gt;# pulled from repo secrets, never hardcoded&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 5: commit and push the updated index.html back to the repo&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit updated portfolio&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;git config user.name "github-actions[bot]"&lt;/span&gt;
          &lt;span class="s"&gt;git config user.email "github-actions[bot]@users.noreply.github.com"&lt;/span&gt;
          &lt;span class="s"&gt;git add index.html&lt;/span&gt;
          &lt;span class="s"&gt;git diff --staged --quiet || git commit -m "chore: sync articles $(date -u +%Y-%m-%dT%H:%M:%SZ)"&lt;/span&gt;
          &lt;span class="s"&gt;git push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Walk through what this does. When code is pushed to main or when the 6-hour cron fires, GitHub provisions a fresh Ubuntu machine. It checks out the repository, installs Python 3.11, installs the dependencies from &lt;code&gt;requirements.txt&lt;/code&gt;, runs &lt;code&gt;main.py&lt;/code&gt; (which calls the Dev.to API, deduplicates articles against the existing HTML, and injects new cards), and then commits the updated &lt;code&gt;index.html&lt;/code&gt; back to the repo. The portfolio updates without anyone touching it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;git diff --staged --quiet ||&lt;/code&gt; before the commit is worth noting. If &lt;code&gt;main.py&lt;/code&gt; ran but found no new articles, &lt;code&gt;index.html&lt;/code&gt; won't have changed. Without that check, the workflow would fail trying to commit a file with no changes. The &lt;code&gt;||&lt;/code&gt; means: if the diff is empty (exit code 0), skip the commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  How &lt;code&gt;uses&lt;/code&gt; and &lt;code&gt;run&lt;/code&gt; differ
&lt;/h3&gt;

&lt;p&gt;You'll notice two kinds of steps in the file above.&lt;/p&gt;

&lt;p&gt;Steps with &lt;code&gt;uses:&lt;/code&gt; call a pre-built action. &lt;code&gt;actions/checkout@v3&lt;/code&gt; is maintained by GitHub and handles cloning your repo onto the runner correctly, including dealing with authentication. &lt;code&gt;actions/setup-python@v4&lt;/code&gt; installs Python and adds it to the runner's PATH. These are reusable building blocks from the Actions marketplace, versioned with the &lt;code&gt;@v3&lt;/code&gt; syntax so your workflow doesn't silently break when the action gets updated.&lt;/p&gt;

&lt;p&gt;Steps with &lt;code&gt;run:&lt;/code&gt; execute shell commands directly. This is where your own logic lives. Anything you'd type into a terminal, you can write here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets
&lt;/h3&gt;

&lt;p&gt;Notice &lt;code&gt;${{ secrets.DEVTO_API_KEY }}&lt;/code&gt; in the workflow. This is how GitHub Actions handles credentials. You store the actual key value in your repository's Settings under Secrets and Variables, and reference it in the workflow using the &lt;code&gt;${{ secrets.NAME }}&lt;/code&gt; syntax. The value is never written to the workflow file, never visible in logs, and never committed to source control.&lt;/p&gt;

&lt;p&gt;For recLog, this is where the Dev.to API key lives. The workflow reads it at runtime, passes it to the Python script as an environment variable, and the script uses it to authenticate against the Dev.to REST API.&lt;/p&gt;

&lt;h3&gt;
  
  
  The cron trigger
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;schedule:&lt;/code&gt; event uses standard cron syntax. &lt;code&gt;0 */6 * * *&lt;/code&gt; means "at minute 0 of every 6th hour." GitHub runs this on UTC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;┌──── &lt;span class="n"&gt;minute&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;-&lt;span class="m"&gt;59&lt;/span&gt;)
│  ┌─── &lt;span class="n"&gt;hour&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;-&lt;span class="m"&gt;23&lt;/span&gt;)
│  │   ┌── &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt; (&lt;span class="m"&gt;1&lt;/span&gt;-&lt;span class="m"&gt;31&lt;/span&gt;)
│  │   │  ┌─ &lt;span class="n"&gt;month&lt;/span&gt; (&lt;span class="m"&gt;1&lt;/span&gt;-&lt;span class="m"&gt;12&lt;/span&gt;)
│  │   │  │  ┌ &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;week&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;-&lt;span class="m"&gt;7&lt;/span&gt;, &lt;span class="n"&gt;Sunday&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;)
│  │   │  │  │
&lt;span class="m"&gt;0&lt;/span&gt;  */&lt;span class="m"&gt;6&lt;/span&gt;  *  *  *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For recLog, this means the portfolio checks for new articles four times a day without any manual trigger. If you publish at 2am, the site reflects it by 8am at the latest.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Where It Gets Tricky
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The runner starts empty every time
&lt;/h3&gt;

&lt;p&gt;The runner GitHub provisions do not know your previous runs. It doesn't have your dependencies cached, it doesn't have your environment variables set, it doesn't have any state from the last time the workflow ran. This catches beginners every time.&lt;/p&gt;

&lt;p&gt;If your script writes a file during one run and expects that file to exist on the next run, it won't. Everything ephemeral needs to either be committed back to the repo (like recLog does with &lt;code&gt;index.html&lt;/code&gt;), stored in an external service, or regenerated each run.&lt;/p&gt;

&lt;p&gt;For recLog this was a deliberate design choice. The deduplication logic reads the &lt;em&gt;current state of index.html in the repo&lt;/em&gt; to know which articles already exist. The runner checks out the repo fresh each time, runs the diff, and commits only changes. The repo itself is the state store.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow permissions for committing back
&lt;/h3&gt;

&lt;p&gt;By default, the &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; that GitHub provides to each workflow run has read-only access to the repository contents. If your workflow tries to &lt;code&gt;git push&lt;/code&gt; without the right permissions, it will fail with a 403.&lt;/p&gt;

&lt;p&gt;To fix this, go to your repository Settings, then Actions, then General, and set "Workflow permissions" to "Read and write permissions." Alternatively, you can set it per-workflow in the YAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of the most common silent failure points for beginners writing their first workflow that commits back to the repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cron schedules aren't guaranteed
&lt;/h3&gt;

&lt;p&gt;GitHub's documentation states that scheduled workflows may be delayed during periods of high load on their infrastructure. A workflow scheduled for 6:00 UTC might run at 6:07, or occasionally later. For most use cases, this is fine. For anything where exact timing matters, scheduled Actions aren't the right tool.&lt;/p&gt;

&lt;p&gt;There's also a lesser-known behaviour: GitHub will disable scheduled workflows on repositories that have had no activity for 60 days. If your portfolio repo goes quiet for two months, the sync stops. The fix is either to push something (anything) to keep the repo active, or to trigger the workflow manually from the Actions tab when you notice it's stopped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets in forks and pull requests
&lt;/h3&gt;

&lt;p&gt;If someone forks your repo and opens a pull request, workflows triggered by that PR will not have access to your repository secrets. This is a security measure, not a bug. It means a fork-based PR can't exfiltrate your API keys. But it also means if your workflow requires a secret to run, it will fail on PRs from forks. Keep this in mind if you ever open-source a project that has required secrets in its workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building recLog's Pipeline Step by Step
&lt;/h2&gt;

&lt;p&gt;Here's how to set up a workflow like recLog's from scratch, assuming you have a repository with a Python project that you want to automate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: create the workflow directory&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .github/workflows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: write the workflow file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;.github/workflows/main.yml&lt;/code&gt; and start with the trigger and job definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sync Dev.to Articles&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*/6&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sync&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: add the checkout and Python setup steps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These two steps appear in nearly every Python-based workflow. The checkout action clones the repo onto the runner. Without it, the runner has no access to your code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: install dependencies and run your script&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run sync pipeline&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python main.py&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;DEVTO_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DEVTO_API_KEY }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5: add the secret to your repository&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to your repository on GitHub. Settings, then Secrets and variables, then Actions, then "New repository secret." Name it &lt;code&gt;DEVTO_API_KEY&lt;/code&gt; and paste in your Dev.to API key. The workflow will now have access to it at runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: commit and push if the output changed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the step that closes the loop. The &lt;code&gt;git diff --staged --quiet ||&lt;/code&gt; guard ensures the commit only runs when there's actually something new to commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit updated portfolio&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;git config user.name "github-actions[bot]"&lt;/span&gt;
          &lt;span class="s"&gt;git config user.email "github-actions[bot]@users.noreply.github.com"&lt;/span&gt;
          &lt;span class="s"&gt;git add index.html&lt;/span&gt;
          &lt;span class="s"&gt;git diff --staged --quiet || git commit -m "chore: sync articles $(date -u +%Y-%m-%dT%H:%M:%SZ)"&lt;/span&gt;
          &lt;span class="s"&gt;git push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this file is committed and pushed to main, GitHub picks it up automatically. You'll see the workflow appear in the Actions tab of your repository. Every run shows the status of each step, the logs, and how long it took.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;A GitHub Actions workflow is not magic. It's a YAML file that tells GitHub: when this event happens, spin up a machine, run these steps in order, and report back. Every concept in that sentence is something you now have a working mental model of: events, runners, steps, secrets, and how to commit results back to the repo.&lt;/p&gt;

&lt;p&gt;The recLog pipeline is a clean example of the pattern in its simplest useful form: trigger on push and on schedule, run Python, commit the output. That structure applies directly to dozens of other automation problems: syncing data, running tests, publishing packages, and generating reports.&lt;/p&gt;

&lt;p&gt;Your next step is to open the Actions tab on any of your existing GitHub repositories and look at the starter workflows GitHub suggests. Pick the simplest one that applies to your stack, read through it line by line against what you've learned here, and run it. Seeing a green checkmark on your first workflow is how the mental model becomes a reflex.&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubactions</category>
      <category>automation</category>
      <category>devops</category>
    </item>
    <item>
      <title>GitHub Already Knows When You Push. It Can Do a Lot More Than Just Watch.</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Wed, 10 Jun 2026 14:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/github-already-knows-when-you-push-it-can-do-a-lot-more-than-just-watch-bh7</link>
      <guid>https://dev.to/im_nishant/github-already-knows-when-you-push-it-can-do-a-lot-more-than-just-watch-bh7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fte0jt4x0bkt4l4nux7rl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fte0jt4x0bkt4l4nux7rl.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time you push code to GitHub, something happens on their end. A record is created, your repo updates, collaborators can see the change. GitHub is already reacting to your push. The question is whether you want it to stop there, or do something useful with that event.&lt;/p&gt;

&lt;p&gt;That's the idea behind GitHub Actions. It's GitHub's built-in automation layer. When something happens in your repository, a workflow runs. That workflow can test your code, deploy your app, send a notification, sync data, or do anything else a computer can do. No external service required. No separate CI tool to configure. It lives inside your repo, runs on GitHub's infrastructure, and triggers off the same events your repository already produces.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why GitHub Built This When AWS Already Exists
&lt;/h2&gt;

&lt;p&gt;This is a fair question. AWS CodePipeline, Jenkins, CircleCI, and a dozen other tools already handle CI/CD. Why did GitHub build their own?&lt;/p&gt;

&lt;p&gt;The honest answer is friction. Every existing tool required you to leave GitHub, set up an account somewhere else, connect it to your repo via webhooks or API tokens, configure a pipeline in a separate interface, and then debug failures across two different platforms. For large engineering teams with dedicated DevOps engineers, that cost is manageable. For an individual developer or a small team, it's enough friction to skip automation entirely.&lt;/p&gt;

&lt;p&gt;GitHub Actions removes the "leave GitHub" part. Your workflow file lives in &lt;code&gt;.github/workflows/&lt;/code&gt; inside your repo. It's version-controlled alongside your code. You see the results in the same tab where you see your commits and pull requests. When something breaks, the logs are right there.&lt;/p&gt;

&lt;p&gt;AWS and other cloud platforms are still the right choice when you need deep infrastructure control, complex deployment pipelines across multiple environments, or tight integration with AWS-specific services. GitHub Actions is not trying to replace that. It's solving a different problem: making basic automation accessible to anyone who already uses GitHub, without requiring infrastructure expertise to get started.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Actually Works
&lt;/h2&gt;

&lt;p&gt;GitHub Actions is built on four concepts. Understand these and everything else is just syntax.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflows&lt;/strong&gt; are the top-level unit. Each workflow is a YAML file in &lt;code&gt;.github/workflows/&lt;/code&gt;. One repository can have multiple workflows, and each one is completely independent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Events&lt;/strong&gt; are what trigger a workflow. A push to main, a pull request being opened, a release being published, or a scheduled time. You define which events activate a workflow in the &lt;code&gt;on:&lt;/code&gt; block at the top of the file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jobs&lt;/strong&gt; are groups of steps that run together on the same machine. Multiple jobs in a workflow run in parallel by default. If one job needs the output of another, you declare that dependency explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps&lt;/strong&gt; are individual tasks within a job. A step is either a shell command you write directly using &lt;code&gt;run:&lt;/code&gt;, or a pre-built action from the marketplace that you call using &lt;code&gt;uses:&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every job runs on a fresh virtual machine that GitHub provisions for the duration of the job and discards afterward. This machine is called a &lt;strong&gt;runner&lt;/strong&gt;. The most common choice is &lt;code&gt;ubuntu-latest&lt;/code&gt;. The runner starts with nothing except a base OS, so anything your workflow needs (Python, Node, dependencies, credentials) has to be set up explicitly within the steps.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your First Workflow
&lt;/h2&gt;

&lt;p&gt;Here's a minimal workflow that runs your Python tests automatically every time code is pushed to the main branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/ci.yml&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Tests&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;      &lt;span class="c1"&gt;# triggers on every push to main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;      &lt;span class="c1"&gt;# clones your repo onto the runner&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.11'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pytest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use this, create the file at &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt; in your repo, commit it, and push. GitHub picks it up automatically. Go to the Actions tab in your repository and you'll see the workflow run in real time.&lt;/p&gt;

&lt;p&gt;That's it. No external accounts. No webhooks to configure. The workflow file being in the right directory is all GitHub needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Secrets: Credentials Without Hardcoding
&lt;/h2&gt;

&lt;p&gt;Almost every real workflow needs a credential of some kind: an API key, a deploy token, a database password. You should never write these directly in your workflow file, because workflow files are committed to your repository and potentially public.&lt;/p&gt;

&lt;p&gt;GitHub solves this with &lt;strong&gt;secrets&lt;/strong&gt;. You store the value in your repository settings (Settings, then Secrets and variables, then Actions), and reference it in the workflow using &lt;code&gt;${{ secrets.YOUR_SECRET_NAME }}&lt;/code&gt;. The value is masked in logs and never exposed in the workflow file itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Call external API&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python sync.py&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.API_KEY }}&lt;/span&gt;    &lt;span class="c1"&gt;# injected at runtime, never hardcoded&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Where GitHub Actions Fits (and Where It Doesn't)
&lt;/h2&gt;

&lt;p&gt;GitHub Actions handles most automation needs for individual projects and small teams well: running tests on pull requests, deploying static sites, syncing data on a schedule, publishing packages on release. The setup cost is low and the integration with GitHub is tight.&lt;/p&gt;

&lt;p&gt;It starts showing limits when you need long-running jobs (there's a 6-hour cap per job), complex multi-environment deployments with approval gates, or workloads that need dedicated infrastructure rather than ephemeral runners. For those cases, dedicated platforms like AWS CodePipeline or a self-hosted Jenkins instance are still the right tool.&lt;/p&gt;

&lt;p&gt;For most projects, though, GitHub Actions covers what you need without requiring you to leave the platform you're already using.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up Your First Workflow: The Short Version
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;In your repository, create the directory &lt;code&gt;.github/workflows/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a YAML file inside it (the name can be anything, e.g. &lt;code&gt;ci.yml&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Define your trigger in the &lt;code&gt;on:&lt;/code&gt; block&lt;/li&gt;
&lt;li&gt;Define a job with &lt;code&gt;runs-on: ubuntu-latest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add steps using &lt;code&gt;uses:&lt;/code&gt; for marketplace actions and &lt;code&gt;run:&lt;/code&gt; for shell commands&lt;/li&gt;
&lt;li&gt;Commit and push. Check the Actions tab.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Any secrets your workflow needs go in Settings, then Secrets and variables, then Actions, referenced in the workflow as &lt;code&gt;${{ secrets.NAME }}&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;Once this mental model is solid, the natural next step is building a workflow that actually does something specific to your project: runs your test suite, deploys on merge, or automates a repetitive task you currently do by hand.&lt;/p&gt;

&lt;p&gt;A deeper walkthrough of a complete real-world pipeline (fetching data, transforming it, committing the result back to the repo automatically) is covered in the follow-up article: &lt;strong&gt;&lt;a href="https://dev.to/im_nishant/your-code-runs-locally-github-actions-makes-it-run-everywhere-automatically-13bc?preview=54224baa9871f67acc26e87612edacfbfef9b326eb72f75b3de0ba1d05216be1e795344fe360101b5e59f801899ee6229f231fe11167f258c53dcd35"&gt;Building an Automated Content Pipeline with GitHub Actions&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The foundation is what this article covered. The follow-up shows what it looks like when you apply it to a production project from start to finish.&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubactions</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>You Don't Have a "Works on My Machine" Problem. You Have a Dependency Problem.</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Mon, 08 Jun 2026 05:53:48 +0000</pubDate>
      <link>https://dev.to/im_nishant/you-dont-have-a-works-on-my-machine-problem-you-have-a-dependency-problem-349l</link>
      <guid>https://dev.to/im_nishant/you-dont-have-a-works-on-my-machine-problem-you-have-a-dependency-problem-349l</guid>
      <description>&lt;p&gt;Every developer has said it. You write code, it runs perfectly on your laptop, you push it to a server or hand it to a teammate, and something breaks. Wrong Python version. A library installed globally that you forgot about. An environment variable that was set in your shell profile but nowhere else.&lt;/p&gt;

&lt;p&gt;Docker doesn't fix your code. It fixes the gap between the environment where you wrote your code and the environment where it runs. That's the whole job. And once you see that clearly, everything else about Docker follows logically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Environments Are Invisible Dependencies
&lt;/h2&gt;

&lt;p&gt;Here's a scenario that plays out constantly on engineering teams.&lt;/p&gt;

&lt;p&gt;A developer builds a data processing script. It works on their machine. They hand it to a teammate. The teammate runs it and it crashes because a library is the wrong version, or isn't installed at all. So they spend an hour aligning their setups. Two weeks later, it's deployed to production. It crashes again because the server is running a different OS version, and a native dependency that compiled fine locally doesn't compile there.&lt;/p&gt;

&lt;p&gt;None of this is a code problem. The code is fine. The problem is that every machine carries hidden state: installed packages, runtime versions, system libraries, OS quirks. And your application depends on all of it, invisibly.&lt;/p&gt;

&lt;p&gt;The traditional solutions are painful. You write a &lt;code&gt;requirements.txt&lt;/code&gt; or a &lt;code&gt;package.json&lt;/code&gt; and hope everyone runs it. You write a setup script. You document the expected environment in a README that gets out of date. You use a virtual environment, which helps for language-level dependencies but doesn't capture system-level ones. You use a VM, which captures everything but is heavy, slow to start, and awkward to share.&lt;/p&gt;

&lt;p&gt;Docker solves this by packaging the application &lt;em&gt;and&lt;/em&gt; its entire environment (OS libraries, runtime, config, dependencies) into a single portable unit. That unit runs the same way everywhere Docker is installed.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Docker Actually Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The core idea: containers vs virtual machines
&lt;/h3&gt;

&lt;p&gt;The most common misconception about Docker is that it's a lightweight virtual machine. It isn't, and the difference matters.&lt;/p&gt;

&lt;p&gt;A virtual machine emulates hardware. When you run a VM, your computer pretends to be a different computer, running a full operating system on top of fake hardware. That's expensive. A VM typically takes seconds to minutes to start and consumes gigabytes of RAM just for the OS layer.&lt;/p&gt;

&lt;p&gt;Docker uses a different mechanism called &lt;strong&gt;containerisation&lt;/strong&gt;. Containers don't emulate hardware. They run as isolated processes directly on your actual OS kernel, using two Linux features to create the illusion of separation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Namespaces&lt;/strong&gt; give each container its own view of the system. A container has its own process list, its own network interfaces, its own filesystem tree. From inside the container, it looks like it's the only thing running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cgroups (control groups)&lt;/strong&gt; limit how much CPU, memory, and I/O a container can consume. This is how Docker prevents one container from starving others.&lt;/p&gt;

&lt;p&gt;Because containers share the host kernel rather than running their own, they start in milliseconds and use a fraction of the memory a VM would. A container running a Python web app might consume 50MB of RAM. A VM running the same app would consume 50MB for the app &lt;em&gt;plus&lt;/em&gt; roughly 500MB for the guest OS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2si1f77frhlfase5uzml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2si1f77frhlfase5uzml.png" alt="VM Architecture vs Docker Container Architecture" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Images and containers
&lt;/h3&gt;

&lt;p&gt;Docker has two concepts you need to keep straight: &lt;strong&gt;images&lt;/strong&gt; and &lt;strong&gt;containers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;image&lt;/strong&gt; is a read-only template. It describes an environment: which OS layer to use, which packages to install, which files to include, which command to run on startup. An image is not running anything. It's a blueprint, like a class definition in code.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;container&lt;/strong&gt; is a running instance of an image. When you tell Docker to run an image, it creates a container: a live, isolated process using that image as its starting state. You can run ten containers from the same image simultaneously and each will be isolated from the others. This is the class-vs-object analogy made literal.&lt;/p&gt;

&lt;p&gt;Images are built in layers. Every instruction in your image definition adds a layer on top of the previous one: start with a base OS layer, add a Python layer, add your application code. Docker caches each layer separately. If you rebuild an image after changing only your application code, Docker reuses the OS and Python layers from cache and only rebuilds the final layer. This makes rebuilds fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Dockerfile
&lt;/h3&gt;

&lt;p&gt;You define an image with a &lt;code&gt;Dockerfile&lt;/code&gt;, a plain text file that lists the build instructions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start from an official Python base image (OS + Python bundled together)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.11-slim&lt;/span&gt;

&lt;span class="c"&gt;# Set the working directory inside the container&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy and install dependencies first so this layer gets cached&lt;/span&gt;
&lt;span class="c"&gt;# as long as requirements.txt doesn't change&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Now copy your application code (this layer rebuilds on every code change)&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Tell Docker what to run when the container starts&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "app.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ordering here is deliberate. &lt;code&gt;requirements.txt&lt;/code&gt; is copied and installed &lt;em&gt;before&lt;/em&gt; the application code. Because Docker caches layers, if you change your code but not your dependencies, Docker will reuse the cached dependency layer and only redo the final &lt;code&gt;COPY&lt;/code&gt;. If you put &lt;code&gt;COPY . .&lt;/code&gt; first, every code change would invalidate the dependency cache and reinstall everything, turning a two-second rebuild into a two-minute one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Docker Hub and base images
&lt;/h3&gt;

&lt;p&gt;You don't build images from scratch. You start &lt;code&gt;FROM&lt;/code&gt; an existing image, usually an official one from Docker Hub, which is a public registry of images. &lt;code&gt;python:3.11-slim&lt;/code&gt; is an image that includes Debian Linux and Python 3.11, maintained by the Python team. There are official base images for nearly every language runtime, database, and common tool.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;slim&lt;/code&gt; suffix is a convention for smaller variants that strip out documentation and tools you don't need at runtime. For production use, smaller images mean faster deploys and a smaller attack surface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker Compose
&lt;/h3&gt;

&lt;p&gt;A real application is rarely just one container. You have your app, a database, maybe a caching layer. &lt;strong&gt;Docker Compose&lt;/strong&gt; lets you define and manage multiple containers as a single unit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yml defines a web app and its database together&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;                    &lt;span class="c1"&gt;# build from the Dockerfile in this directory&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8000:8000"&lt;/span&gt;             &lt;span class="c1"&gt;# map port 8000 on your machine to port 8000 in the container&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;                      &lt;span class="c1"&gt;# don't start web until db is running&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres://user:pass@db:5432/mydb&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15&lt;/span&gt;          &lt;span class="c1"&gt;# use the official Postgres image directly&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pass&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mydb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this file in your project, &lt;code&gt;docker compose up&lt;/code&gt; starts both containers with the right configuration. A new developer on your team clones the repo and runs one command. No database installation required.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where It Gets Complicated
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Persistence: containers are ephemeral by default
&lt;/h3&gt;

&lt;p&gt;A container's filesystem is disposable. When you delete a container, anything written inside it is gone. For a stateless web app that's fine because you rebuild and redeploy. For a database, it's a disaster.&lt;/p&gt;

&lt;p&gt;Docker handles this with &lt;strong&gt;volumes&lt;/strong&gt;: directories on your host machine (or a managed storage backend) that get mounted into containers. Anything the container writes to the volume path persists even after the container is removed.&lt;/p&gt;

&lt;p&gt;Beginners consistently skip volumes when running databases locally, then wonder why their data disappears every time they restart. Add this to your Compose file for the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres_data:/var/lib/postgresql/data&lt;/span&gt;   &lt;span class="c1"&gt;# named volume for persistence&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;postgres_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="c1"&gt;# declare the named volume&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Image size creep
&lt;/h3&gt;

&lt;p&gt;The single most common mistake when writing Dockerfiles is producing images that are far larger than they need to be. A Python image built naively can easily reach 1-2GB. The production version of the same app can be under 100MB with &lt;strong&gt;multi-stage builds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Multi-stage builds let you use one image to &lt;em&gt;build&lt;/em&gt; your application (with compilers, test tools, all of it) and a separate, leaner image to &lt;em&gt;run&lt;/em&gt; it. The final image only contains what the runtime needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: build stage with full tooling&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;python:3.11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/install &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Stage 2: runtime stage, slim and minimal&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.11-slim&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /install /usr/local   # copy only the installed packages&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "app.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Secrets and environment variables
&lt;/h3&gt;

&lt;p&gt;Don't put secrets in your Dockerfile. If you write &lt;code&gt;ENV API_KEY=abc123&lt;/code&gt; in a Dockerfile and push it to a registry, that key is baked into every layer of the image and visible to anyone who pulls it.&lt;/p&gt;

&lt;p&gt;Pass secrets at runtime using environment variables, Docker secrets, or a tool like Vault. Your Compose file can reference variables from a &lt;code&gt;.env&lt;/code&gt; file that you never commit to source control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Networking between containers
&lt;/h3&gt;

&lt;p&gt;Containers on the same Docker network can reach each other by service name. In the Compose example above, the web app connects to &lt;code&gt;db:5432&lt;/code&gt;. The name &lt;code&gt;db&lt;/code&gt; is not a hostname you configured anywhere. Docker's internal DNS resolves it to the database container automatically. This trips up beginners who try to use &lt;code&gt;localhost&lt;/code&gt; inside a container and can't reach a sibling container. Inside a container, &lt;code&gt;localhost&lt;/code&gt; refers to &lt;em&gt;that container&lt;/em&gt;, not the host machine or anything running alongside it.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Concrete Scenario: Onboarding Without the Setup Tax
&lt;/h2&gt;

&lt;p&gt;Here's where the value becomes tangible. You're working on a team building a backend API in Python. The app needs Python 3.11, PostgreSQL 15, and Redis. Without Docker, onboarding a new engineer means installing Python 3.11 (maybe using pyenv, maybe not), installing and configuring PostgreSQL, installing Redis, setting a dozen environment variables, and running migrations. This takes anywhere from 30 minutes to half a day, and something always breaks on someone's machine.&lt;/p&gt;

&lt;p&gt;With Docker, the repository contains a &lt;code&gt;docker-compose.yml&lt;/code&gt; and a &lt;code&gt;.env.example&lt;/code&gt;. The onboarding instruction is two commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first run downloads base images, which takes a few minutes once. Every subsequent run starts in under five seconds. The entire environment (exact Python version, exact Postgres version, exact Redis version, correct config) is encoded in files that live in version control alongside the application code.&lt;/p&gt;

&lt;p&gt;When you upgrade from PostgreSQL 15 to 16, you change one line in &lt;code&gt;docker-compose.yml&lt;/code&gt; and commit it. Every developer on the team gets the upgrade on their next pull. No announcement in Slack. No "make sure you've upgraded your local Postgres" in the README.&lt;/p&gt;

&lt;p&gt;This is Docker's most underrated value for teams. The environment becomes a first-class artifact of the project, versioned, reproducible, and reviewable just like the code.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Now Understand
&lt;/h2&gt;

&lt;p&gt;The phrase "it works on my machine" describes a configuration management failure, not a code problem. Docker's answer is to make the environment part of the artifact, not documented alongside it but included inside it.&lt;/p&gt;

&lt;p&gt;That's the shift. Not "write better setup instructions." Bundle the setup into something that runs.&lt;/p&gt;

&lt;p&gt;Your concrete next step: take an existing project, a simple web app or a script, and write a Dockerfile for it. Don't worry about making it production-perfect. Get it building and running locally. The feedback loop of seeing what breaks and why is how this becomes intuition rather than theory.&lt;/p&gt;

&lt;p&gt;Once you're comfortable with that, the natural next steps are multi-stage builds for smaller production images, volumes for stateful workloads, and eventually Kubernetes for running containers across multiple machines. But those are layers built on top of this foundation. Get the foundation first.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Build a Portfolio Website From Scratch – A Complete Journey</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Fri, 13 Feb 2026 20:22:01 +0000</pubDate>
      <link>https://dev.to/im_nishant/how-to-build-a-portfolio-website-from-scratch-a-complete-journey-2mj3</link>
      <guid>https://dev.to/im_nishant/how-to-build-a-portfolio-website-from-scratch-a-complete-journey-2mj3</guid>
      <description>&lt;h2&gt;
  
  
  PART 1: The Full Journey
&lt;/h2&gt;




&lt;h3&gt;
  
  
  Preview: Light Mode
&lt;/h3&gt;

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




&lt;h2&gt;
  
  
  1. When I Started Building My Portfolio
&lt;/h2&gt;

&lt;p&gt;When I decided to build my portfolio, I knew I didn’t want it to look like a “template-based” website. I wanted my site to show who I was as a developer: organized, clean, and systematic.&lt;/p&gt;

&lt;p&gt;So long before I wrote even one line of code, I planned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The sections I wanted to show on my portfolio.&lt;/li&gt;
&lt;li&gt;How do recruiters view portfolios?&lt;/li&gt;
&lt;li&gt;What is shown at the top of my portfolio (above the fold).&lt;/li&gt;
&lt;li&gt;How to balance content with images on my portfolio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final structure is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navbar&lt;/li&gt;
&lt;li&gt;Hero / About&lt;/li&gt;
&lt;li&gt;Projects&lt;/li&gt;
&lt;li&gt;Skills&lt;/li&gt;
&lt;li&gt;Achievements &amp;amp; Certifications&lt;/li&gt;
&lt;li&gt;Contact&lt;/li&gt;
&lt;li&gt;Footer&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;br&gt;
“If someone spends 30 seconds on my site, they should be able to identify who I am technically.”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Structuring the HTML Layout
&lt;/h2&gt;

&lt;p&gt;I built everything using &lt;strong&gt;semantic HTML + Bootstrap grid&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each section was wrapped inside a &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"projects"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"skills"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allowed me to achieve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anchor navigation&lt;/li&gt;
&lt;li&gt;SEO-friendly structure&lt;/li&gt;
&lt;li&gt;Clean scroll targeting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Layout scaffolding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bootstrap handled responsiveness, while custom CSS handled visual identity.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Designing the Navbar
&lt;/h2&gt;

&lt;p&gt;Since the navbar is the first thing people see when they enter the application, it was important for me to keep it in the following ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixed at the top&lt;/li&gt;
&lt;li&gt;Minimal&lt;/li&gt;
&lt;li&gt;Navigation-focused&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logo + Name branding&lt;/li&gt;
&lt;li&gt;Anchor navigation links&lt;/li&gt;
&lt;li&gt;Theme toggle switch
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar navbar-expand-lg fixed-top custom-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hover animation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.navbar-nav&lt;/span&gt; &lt;span class="nc"&gt;.nav-link&lt;/span&gt;&lt;span class="nd"&gt;::after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;ease&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;
  
  
  4. Building the Hero / About Section
&lt;/h2&gt;

&lt;p&gt;This section had to communicate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who I am&lt;/li&gt;
&lt;li&gt;What I do&lt;/li&gt;
&lt;li&gt;What I’ve achieved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two-column layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row align-items-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Image&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-7"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Content&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UI decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rounded profile image&lt;/li&gt;
&lt;li&gt;Shadow wrapper&lt;/li&gt;
&lt;li&gt;Using GIFs for accents.&lt;/li&gt;
&lt;li&gt;Using bold text for highlights.&lt;/li&gt;
&lt;li&gt;Resume links
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.about_img--wrapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.1&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;
  
  
  5. Projects Section: Card Architecture
&lt;/h2&gt;

&lt;p&gt;I designed projects as product tiles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-6 col-lg-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"project-card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;25px radius&lt;/li&gt;
&lt;li&gt;Muted teal background&lt;/li&gt;
&lt;li&gt;Hover lift
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.project-card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5px&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. Skills Section: Visualizing Competence
&lt;/h2&gt;

&lt;p&gt;Custom progress bars:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"skill-bar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"skill-fill"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:85%"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.skill-bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#7c8d8f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.skill-fill&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1f2022&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;Split into two columns for balance.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Achievements &amp;amp; Certifications:
&lt;/h2&gt;

&lt;p&gt;Image-driven proof cards.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.achievement-img-wrapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;260px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&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;Hover zoom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.achievement-card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="nc"&gt;.achievement-img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.05&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;
  
  
  8. Contact Section:
&lt;/h2&gt;

&lt;p&gt;Two layers:&lt;br&gt;
&lt;strong&gt;Quick Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn&lt;/li&gt;
&lt;li&gt;Email&lt;/li&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Contact Form&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;textarea&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hover elevation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.contact-card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5px&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;
  
  
  9. Footer: Closing Identity
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Logo&lt;/li&gt;
&lt;li&gt;Copyright&lt;/li&gt;
&lt;li&gt;Social icons
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.footer-icon&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.1&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;
  
  
  10. Dark &amp;amp; Light Mode Implementation:
&lt;/h2&gt;

&lt;p&gt;Theme toggle via JS &amp;amp; Persistence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;toggleBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark-mode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Dark Mode
&lt;/h2&gt;

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




&lt;h3&gt;
  
  
  Dark-Mode Decisions:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.dark-mode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0f1115&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#e6e6e6&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;Adjustments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gradient cards&lt;/li&gt;
&lt;li&gt;Teal skill bars&lt;/li&gt;
&lt;li&gt;Dark inputs&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Goal: Reduce eye strain.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  11. Layout Engineering:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Bootstrap Grid → Structure&lt;/li&gt;
&lt;li&gt;Flexbox → Alignment
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;display&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;flex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;align-items&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;center&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  12. Color &amp;amp; Typography:
&lt;/h2&gt;

&lt;p&gt;Palette:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;#7eaeb4&lt;/code&gt; Accent&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#393E46&lt;/code&gt; Dark&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#f4f5f7&lt;/code&gt; Light
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card-title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Courier New'&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;
  
  
  13. Responsiveness:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;767px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.skill-bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&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;
  
  
  14. Challenges:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dark mode contrast&lt;/li&gt;
&lt;li&gt;Card consistency&lt;/li&gt;
&lt;li&gt;Image scaling&lt;/li&gt;
&lt;li&gt;Navbar shadows&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  15. Micro-UI Decisions:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hover lifts&lt;/li&gt;
&lt;li&gt;Underline nav animation&lt;/li&gt;
&lt;li&gt;Skill transitions&lt;/li&gt;
&lt;li&gt;Icon scaling&lt;/li&gt;
&lt;li&gt;Section accents&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  PART 2: What I Learned
&lt;/h1&gt;

&lt;h3&gt;
  
  
  HTML Semantics
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"projects"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CSS Positioning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;fixed&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Flexbox
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;display&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;flex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Grid
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Responsive Design
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&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;h3&gt;
  
  
  Media Queries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;768px&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;h3&gt;
  
  
  Theme Switching
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clean UI Principles
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Spacing&lt;/li&gt;
&lt;li&gt;Contrast&lt;/li&gt;
&lt;li&gt;Hierarchy&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Reflection
&lt;/h2&gt;

&lt;p&gt;This portfolio became more than a website.&lt;/p&gt;

&lt;p&gt;It taught me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI architecture&lt;/li&gt;
&lt;li&gt;Theme systems&lt;/li&gt;
&lt;li&gt;Responsive thinking&lt;/li&gt;
&lt;li&gt;Developer storytelling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it represents me better than any resume.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>css</category>
      <category>portfolio</category>
    </item>
  </channel>
</rss>
