<?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>INSERT, SELECT, UPDATE, DELETE: PostgreSQL</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Wed, 14 Oct 2026 17:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/insert-select-update-delete-postgresql-1l8f</link>
      <guid>https://dev.to/im_nishant/insert-select-update-delete-postgresql-1l8f</guid>
      <description>&lt;p&gt;At some point you stop thinking about SQL as "a language" and it just becomes muscle memory — you know what an &lt;code&gt;UPDATE&lt;/code&gt; without a &lt;code&gt;WHERE&lt;/code&gt; clause does before you even finish typing it, because you've either done it once by accident or heard someone else's horror story about it. That's basically what this article is about. Not anything exotic, just the four commands that make up most of what you actually do day to day, and the handful of ways each one bites people early on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is worth slowing down for
&lt;/h2&gt;

&lt;p&gt;It's tempting to skim past CRUD because it feels like the "easy" part of SQL — everyone's written a &lt;code&gt;SELECT&lt;/code&gt; before. But most of the actual production incidents I've read about, and a couple I've caused myself in test databases on purpose just to see what happens, come from these four commands specifically. Not from window functions or CTEs. From a missing &lt;code&gt;WHERE&lt;/code&gt; clause, or a &lt;code&gt;SELECT *&lt;/code&gt; that broke when someone renamed a column six months later.&lt;/p&gt;

&lt;p&gt;The syntax is simple. The discipline around using it correctly is the part that takes longer to build.&lt;/p&gt;

&lt;h2&gt;
  
  
  INSERT: getting data in
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Van Vihar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2237&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3910&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- multiple rows in one call — fewer round trips, faster&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Upper Lake'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2415&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3550&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'DB Mall'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4340&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The multi-row version is worth using whenever you're inserting more than one row at a time, even for something small. It's not just a style preference — one round trip to the database instead of several actually adds up, especially if you're populating a table with anything more than a handful of rows.&lt;/p&gt;

&lt;p&gt;Here's a detail that connects back to how Postgres works internally: every &lt;code&gt;INSERT&lt;/code&gt; creates a brand new row version. Postgres doesn't have a concept of "editing in place" the way you might picture it. That's tied directly to MVCC, which is a much bigger topic I'll get into properly later in this series — for now it's enough to know that even &lt;code&gt;INSERT&lt;/code&gt; isn't as simple under the hood as "write these bytes to a table."&lt;/p&gt;

&lt;h2&gt;
  
  
  SELECT: the one you'll use more than everything else combined
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;is_closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;FALSE&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;OFFSET&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;WHERE&lt;/code&gt; filters rows before anything gets grouped or aggregated. &lt;code&gt;ORDER BY&lt;/code&gt; sorts whatever's left. &lt;code&gt;LIMIT&lt;/code&gt;/&lt;code&gt;OFFSET&lt;/code&gt; handle pagination, though &lt;code&gt;OFFSET&lt;/code&gt; gets slow once a table grows large — that's a topic for the indexing article later on, but it's worth knowing it exists as a limitation now.&lt;/p&gt;

&lt;p&gt;The thing that trips people up early, and that I did plenty myself when I was starting out, is reaching for &lt;code&gt;SELECT *&lt;/code&gt; out of habit. It's fine while you're exploring data in &lt;code&gt;psql&lt;/code&gt;. It's a problem in application code, for a few reasons that aren't obvious until they bite you: it breaks silently if someone adds or renames a column later, it pulls back data you don't actually need, and it can block certain optimizations — like an index-only scan, where Postgres could answer a query using just the index without touching the table at all, but only if it knows exactly which columns you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  UPDATE: changing what's already there
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;is_closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one rule here that actually matters: never run an &lt;code&gt;UPDATE&lt;/code&gt; without a &lt;code&gt;WHERE&lt;/code&gt; clause unless you genuinely mean to update every row in the table. This is one of those things that sounds obvious written down, and then someone runs a query against production instead of the staging environment they meant to be in, and every row silently gets the same value. It happens more than you'd think, usually from copy-pasting a query and forgetting to re-add the &lt;code&gt;WHERE&lt;/code&gt; at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  DELETE: same warning, different verb
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;is_closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same logic as &lt;code&gt;UPDATE&lt;/code&gt; — no &lt;code&gt;WHERE&lt;/code&gt; means "delete everything," and Postgres will do exactly that without complaining, because as far as it's concerned that's a perfectly valid instruction. If you're ever testing a &lt;code&gt;DELETE&lt;/code&gt; on something you're not 100% sure about, wrapping it in a transaction first (&lt;code&gt;BEGIN&lt;/code&gt;, run the delete, check the result, then &lt;code&gt;COMMIT&lt;/code&gt; or &lt;code&gt;ROLLBACK&lt;/code&gt;) is a cheap habit that saves you from this exact situation.&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%2F9ukizwfetyauv0ua9xqk.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%2F9ukizwfetyauv0ua9xqk.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it actually gets interesting: UPSERT
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Van Vihar National Park'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2237&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3910&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;CONFLICT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;DO&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXCLUDED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is Postgres's answer to "insert this row, but if it already exists, update it instead" — a pattern that comes up constantly in real projects. Syncing data from an external API is the most common case: you're pulling venue data from some third-party source on a schedule, and you don't know ahead of time whether a given venue is already in your table or not. Instead of writing a &lt;code&gt;SELECT&lt;/code&gt; to check first and then branching into either an &lt;code&gt;INSERT&lt;/code&gt; or an &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;ON CONFLICT&lt;/code&gt; handles both in one statement.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EXCLUDED&lt;/code&gt; refers to the row that would have been inserted if there hadn't been a conflict — so &lt;code&gt;EXCLUDED.name&lt;/code&gt; means "the name value from the row I was trying to insert." If you just want to skip duplicates entirely without updating anything, &lt;code&gt;ON CONFLICT DO NOTHING&lt;/code&gt; does that.&lt;/p&gt;

&lt;p&gt;If you get asked how to handle duplicate key inserts gracefully, this is the expected answer, and it's worth mentioning &lt;code&gt;DO NOTHING&lt;/code&gt; alongside &lt;code&gt;DO UPDATE&lt;/code&gt; since they solve slightly different problems — one is deduplication, the other is a real upsert.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together: syncing venue data from an external source
&lt;/h2&gt;

&lt;p&gt;Say your dashboard pulls venue data from a city API once a day, and venues can be added, renamed, or marked closed on their end. Here's roughly how that sync would actually look, combining a few of these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_closed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Central Park Cafe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2510&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;CONFLICT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;DO&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXCLUDED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;is_closed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EXCLUDED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_closed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run once per venue returned from the API, this single statement handles both new venues and updates to existing ones, without you needing to check which case you're in first. Compare that to the naive version — a &lt;code&gt;SELECT&lt;/code&gt; to check existence, then an &lt;code&gt;if/else&lt;/code&gt; in application code choosing between &lt;code&gt;INSERT&lt;/code&gt; and &lt;code&gt;UPDATE&lt;/code&gt; — and it's not just shorter, it also avoids a race condition where two sync jobs running close together could both decide the row doesn't exist yet and both try to insert it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves you
&lt;/h2&gt;

&lt;p&gt;These four commands, plus &lt;code&gt;ON CONFLICT&lt;/code&gt;, cover most of what you'll actually type against a database in a normal week. The syntax isn't the hard part — the discipline of always including &lt;code&gt;WHERE&lt;/code&gt; on anything destructive, and reaching for &lt;code&gt;ON CONFLICT&lt;/code&gt; instead of a manual check-then-branch pattern, is what actually separates code that survives contact with real data from code that doesn't.&lt;/p&gt;

&lt;p&gt;Next up: constraints — how to make bad data structurally impossible to insert in the first place, instead of relying on catching it after the fact.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PostgreSQL Data Types:</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Tue, 13 Oct 2026 17:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/postgresql-data-types-36em</link>
      <guid>https://dev.to/im_nishant/postgresql-data-types-36em</guid>
      <description>&lt;p&gt;There's a specific kind of bug that doesn't show up right away. A &lt;code&gt;latitude&lt;/code&gt; column stored as &lt;code&gt;FLOAT&lt;/code&gt;, and months later your distance calculations are just slightly off in a way that's hard to pin down. Or a &lt;code&gt;price&lt;/code&gt; column using the same type, and a customer notices their total is a cent wrong, in a way that somehow compounds across enough transactions to matter. Nobody wrote a bug in the usual sense. The data type was the bug, and it had been sitting there quietly since the table was created.&lt;/p&gt;

&lt;p&gt;Choosing a column's type feels like the most mechanical part of designing a schema — pick something that looks roughly right and move on. I used to treat it that way too. It's actually one of the few decisions that's genuinely annoying to undo later, because by the time you notice it's wrong, there's real data sitting in that column.&lt;/p&gt;

&lt;h2&gt;
  
  
  A table that works fine until it doesn't
&lt;/h2&gt;

&lt;p&gt;Say you're building a &lt;code&gt;venues&lt;/code&gt; table for a dashboard that tracks locations and closures. It's tempting to just reach for whatever feels familiar — &lt;code&gt;VARCHAR&lt;/code&gt; for text, &lt;code&gt;FLOAT&lt;/code&gt; for anything with a decimal, &lt;code&gt;INTEGER&lt;/code&gt; for IDs without thinking twice.&lt;/p&gt;

&lt;p&gt;That table inserts rows fine. It passes whatever tests you write in the first week. Then a risk score computed from &lt;code&gt;FLOAT&lt;/code&gt; values starts drifting in a way that doesn't reproduce consistently, or the ID column runs into its ceiling because nobody considered &lt;code&gt;BIGINT&lt;/code&gt;, or a &lt;code&gt;TIMESTAMP&lt;/code&gt; column with no timezone awareness makes an event look like it happened in a different hour depending on which server handled it. None of these are exotic problems. They're just what happens when types don't get real thought up front.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going through the types one at a time
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The table itself
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;latitude&lt;/span&gt; &lt;span class="nb"&gt;DOUBLE&lt;/span&gt; &lt;span class="nb"&gt;PRECISION&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;longitude&lt;/span&gt; &lt;span class="nb"&gt;DOUBLE&lt;/span&gt; &lt;span class="nb"&gt;PRECISION&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;is_closed&lt;/span&gt; &lt;span class="nb"&gt;BOOLEAN&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&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;This is a fairly realistic starting point for a venue-tracking dashboard. Every type choice here is worth understanding on its own, not just copying because it looked right in a tutorial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;INTEGER&lt;/code&gt; / &lt;code&gt;BIGINT&lt;/code&gt;&lt;/strong&gt; — good for counts and IDs. The distinction matters once you think about scale: &lt;code&gt;INTEGER&lt;/code&gt; tops out around 2.1 billion. If there's any real chance a table could grow past that — a high-volume events table, say — starting with &lt;code&gt;BIGINT&lt;/code&gt; costs nothing now and avoids a painful migration later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;SERIAL&lt;/code&gt; / &lt;code&gt;BIGSERIAL&lt;/code&gt;&lt;/strong&gt; — the usual auto-incrementing ID setup. It's worth knowing this isn't actually a separate type. It's an &lt;code&gt;INTEGER&lt;/code&gt; (or &lt;code&gt;BIGINT&lt;/code&gt;) column backed by a sequence that hands out the next value automatically. That distinction matters later if you ever need to work with the sequence directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;VARCHAR(n)&lt;/code&gt; vs &lt;code&gt;TEXT&lt;/code&gt;&lt;/strong&gt; — this one surprised me coming from MySQL. In Postgres these perform almost identically. &lt;code&gt;TEXT&lt;/code&gt; is usually the better default unless you actually need to enforce a maximum length — &lt;code&gt;VARCHAR(n)&lt;/code&gt; is really just &lt;code&gt;TEXT&lt;/code&gt; with a length constraint bolted on, not a different storage format underneath.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;NUMERIC(p,s)&lt;/code&gt; vs &lt;code&gt;DOUBLE PRECISION&lt;/code&gt;&lt;/strong&gt; — this is the one that actually causes real incidents. &lt;code&gt;NUMERIC&lt;/code&gt; stores exact decimal values. &lt;code&gt;DOUBLE PRECISION&lt;/code&gt; is a floating-point approximation. Don't use &lt;code&gt;FLOAT&lt;/code&gt;/&lt;code&gt;DOUBLE PRECISION&lt;/code&gt; for money — the rounding errors aren't a hypothetical, they show up given enough transactions. &lt;code&gt;DOUBLE PRECISION&lt;/code&gt; is fine for something like geospatial coordinates, where the imprecision at that scale doesn't really change the result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;BOOLEAN&lt;/code&gt;&lt;/strong&gt; — flags. Not much to say here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;TIMESTAMP&lt;/code&gt; vs &lt;code&gt;TIMESTAMPTZ&lt;/code&gt;&lt;/strong&gt; — &lt;code&gt;TIMESTAMPTZ&lt;/code&gt; stores the value normalized to UTC and converts it on display based on the client's timezone. &lt;code&gt;TIMESTAMP&lt;/code&gt; just stores whatever you gave it, with no timezone awareness at all. For pretty much any real app — anything with users spread across timezones, or a backend and frontend that might not agree on local time — &lt;code&gt;TIMESTAMPTZ&lt;/code&gt; is the safer default, even though &lt;code&gt;TIMESTAMP&lt;/code&gt; looks simpler at first glance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;JSONB&lt;/code&gt;&lt;/strong&gt; — binary-stored, indexable, faster to query than &lt;code&gt;JSON&lt;/code&gt;, which is just stored as raw text. Anything semi-structured, like a payload synced from a third-party API, belongs in &lt;code&gt;JSONB&lt;/code&gt; by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;UUID&lt;/code&gt;&lt;/strong&gt; — useful when IDs need to be generated somewhere other than the database itself, or across multiple systems, without collision risk. Needs either &lt;code&gt;gen_random_uuid()&lt;/code&gt; or an extension like &lt;code&gt;pgcrypto&lt;/code&gt; or &lt;code&gt;uuid-ossp&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%2Fjty6ob1h84uormqt8r4w.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%2Fjty6ob1h84uormqt8r4w.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The two questions that always come up
&lt;/h2&gt;

&lt;p&gt;"Difference between &lt;code&gt;VARCHAR&lt;/code&gt; and &lt;code&gt;TEXT&lt;/code&gt;?" — functionally almost identical in Postgres, unlike MySQL. &lt;code&gt;VARCHAR(n)&lt;/code&gt; just adds a length constraint on top of the same underlying storage.&lt;/p&gt;

&lt;p&gt;"Difference between &lt;code&gt;JSON&lt;/code&gt; and &lt;code&gt;JSONB&lt;/code&gt;?" — &lt;code&gt;JSON&lt;/code&gt; stores the exact text, preserving whitespace and key order, but it's slower to query and doesn't support much indexing. &lt;code&gt;JSONB&lt;/code&gt; stores a parsed binary format, which loses the exact original formatting but is faster and indexable through GIN indexes. Default to &lt;code&gt;JSONB&lt;/code&gt; most of the time, and only reach for plain &lt;code&gt;JSON&lt;/code&gt; if you specifically need to preserve the text exactly as it came in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Altering a table isn't always as harmless as it looks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="k"&gt;RENAME&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;venue_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These look simple, and on a small table they are. The problem shows up at scale — altering a table with millions of rows during peak traffic can lock it, blocking reads and writes for however long the operation takes. &lt;code&gt;ADD COLUMN&lt;/code&gt; with a default value used to force a full table rewrite in older Postgres versions. That got a lot cheaper starting in Postgres 11 for constant defaults, but it's worth knowing that history exists, since not every production system runs the latest version, and assuming modern behavior on an older cluster is a reasonable way to cause an outage.&lt;/p&gt;

&lt;h3&gt;
  
  
  DROP vs TRUNCATE vs DELETE
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;-- removes the table and its structure entirely&lt;/span&gt;
&lt;span class="k"&gt;TRUNCATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;-- empties all rows, keeps the structure&lt;/span&gt;
&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;-- removes rows, can be filtered, slower, undoable within a transaction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;DELETE&lt;/code&gt; works row by row, gets logged, supports &lt;code&gt;WHERE&lt;/code&gt;, and is fully transaction-safe — you can roll it back. &lt;code&gt;TRUNCATE&lt;/code&gt; is close to instant because it deallocates whole pages instead of scanning rows one at a time. It can't use &lt;code&gt;WHERE&lt;/code&gt;, but it's still transactional in Postgres, so it can be rolled back too, as long as you're inside a transaction that hasn't committed. &lt;code&gt;DROP&lt;/code&gt; removes the entire table, structure included, not just what's inside it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing a type before it becomes a real migration
&lt;/h2&gt;

&lt;p&gt;Say the &lt;code&gt;venues&lt;/code&gt; table above shipped with &lt;code&gt;risk_score DOUBLE PRECISION&lt;/code&gt;, because someone figured "it's just a number between 0 and 1, a float is fine." A few weeks later, a report comparing risk scores across venues starts showing inconsistent sort order for values that should be identical — classic floating-point comparison drift.&lt;/p&gt;

&lt;p&gt;Caught early, the fix is a simple alteration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;venues&lt;/span&gt; &lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;risk_score&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caught after the table has millions of rows, this becomes a much more careful operation — possibly needing a maintenance window, or a safer pattern like adding a new column, backfilling it, and swapping it in. The gap between fixing this on day one and fixing it six months later isn't small. It's the difference between a one-line change and a planned migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves you
&lt;/h2&gt;

&lt;p&gt;Types in Postgres aren't just about what values a column technically accepts — they carry real assumptions about precision, timezone handling, and scale. Those assumptions are cheap to get right when you're creating the table and expensive to fix once there's data in it. Next time you write a &lt;code&gt;CREATE TABLE&lt;/code&gt;, it's worth treating each type as a real decision, especially &lt;code&gt;NUMERIC&lt;/code&gt; vs &lt;code&gt;DOUBLE PRECISION&lt;/code&gt; for anything money-related, and &lt;code&gt;TIMESTAMPTZ&lt;/code&gt; vs &lt;code&gt;TIMESTAMP&lt;/code&gt; for anything tied to a user.&lt;/p&gt;

&lt;p&gt;Next up: actually working with the data — &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, and the upsert pattern for handling "insert or update" cleanly.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>sql</category>
      <category>database</category>
      <category>mysql</category>
    </item>
    <item>
      <title>Getting Into PostgreSQL: psql, Connections, and the First Commands You Actually Need</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Mon, 12 Oct 2026 17:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/getting-into-postgresql-psql-connections-and-the-first-commands-you-actually-need-1mgg</link>
      <guid>https://dev.to/im_nishant/getting-into-postgresql-psql-connections-and-the-first-commands-you-actually-need-1mgg</guid>
      <description>&lt;p&gt;Most tutorials rush past this part. "Install Postgres, connect, start querying" — as if opening the database is the boring bit you skip through to get to the real content. When I was starting, that gap was exactly where I felt lost. You're connected, technically, but you have no idea what's actually in front of you.&lt;/p&gt;

&lt;p&gt;This article covers those first few minutes: getting into &lt;code&gt;psql&lt;/code&gt;, figuring out what you're connected to, and a handful of commands that eventually become reflexes if you use Postgres regularly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not knowing your way around costs you time
&lt;/h2&gt;

&lt;p&gt;Say you inherit a project. Someone hands you a connection string, you open &lt;code&gt;psql&lt;/code&gt;, and you're in. Now what? You don't know what databases exist on the server. You don't know what tables are in the one you're connected to. Someone mentioned a table in a Slack message three months ago and you have no idea what columns it has.&lt;/p&gt;

&lt;p&gt;Without a small set of orientation commands, every one of those questions turns into either opening a GUI (if one's set up) or trying to remember how to query Postgres's internal system catalogs directly, which honestly nobody has memorized. There's a small handful of &lt;code&gt;psql&lt;/code&gt; shortcuts that answer all of this in a couple of seconds, and once they're second nature, this stops being a problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting, and the commands that orient you
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Connecting
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-U&lt;/span&gt; username &lt;span class="nt"&gt;-d&lt;/span&gt; database_name &lt;span class="nt"&gt;-h&lt;/span&gt; host &lt;span class="nt"&gt;-p&lt;/span&gt; 5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each flag does one job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-U&lt;/code&gt; — the user you're connecting as&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt; — the database to connect to&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-h&lt;/code&gt; — the host, a remote server or &lt;code&gt;localhost&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p&lt;/code&gt; — the port, and 5432 is Postgres's default. It's a small detail, but it comes up as a quick sanity-check question fairly often.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A few commands worth knowing by heart
&lt;/h3&gt;

&lt;p&gt;Once you're inside &lt;code&gt;psql&lt;/code&gt;, there's a set of meta-commands — not SQL, just shortcuts specific to &lt;code&gt;psql&lt;/code&gt; itself, which is why they start with a backslash and don't need a semicolon:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;list databases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\c dbname&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;connect to a database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\dt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;list tables in the current schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\d tablename&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;describe a table — columns, types, constraints, indexes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\du&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;list roles/users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;quit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;\d tablename&lt;/code&gt; is the one I use the most. It's the fastest way to see what a table actually looks like without leaving the terminal, and it shows constraints and indexes too, not just column names — something a plain &lt;code&gt;SELECT * LIMIT 1&lt;/code&gt; won't tell you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why these are separate from SQL
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;psql&lt;/code&gt; splits things into two categories on purpose. SQL is for talking to the database engine about your data — it gets parsed, planned, and executed on the server. Meta-commands are for talking to the client about your environment, so &lt;code&gt;\dt&lt;/code&gt; doesn't need a semicolon and responds more or less instantly, because it's not going through the same query pipeline.&lt;/p&gt;

&lt;p&gt;If you get asked how to check a table's structure without a GUI, &lt;code&gt;\d tablename&lt;/code&gt; is basically the expected answer. It's less about the command itself and more a quick check on whether you've actually spent time in a terminal with Postgres, versus only clicking around in a visual tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the confusion usually starts: databases, clusters, templates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating and dropping a database
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;project_db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;project_db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One convention worth knowing early: one database per logical application is the norm. A geospatial dashboard would get its own database, separate from anything unrelated, even if they're sitting on the same server.&lt;/p&gt;

&lt;p&gt;In multi-tenant setups, people sometimes reach for "one database per tenant" because it feels like clean isolation. It usually isn't the right call — hundreds of databases becomes a real management headache. A &lt;code&gt;tenant_id&lt;/code&gt; column, or separate schemas per tenant within one database, tends to hold up much better as things grow.&lt;/p&gt;

&lt;h3&gt;
  
  
  What CREATE DATABASE is actually doing
&lt;/h3&gt;

&lt;p&gt;Here's a detail that surprised me the first time I read about it: &lt;code&gt;CREATE DATABASE&lt;/code&gt; doesn't build an empty database from scratch. It clones a template database — &lt;code&gt;template1&lt;/code&gt; by default. That explains a specific category of confusing bugs. If &lt;code&gt;template1&lt;/code&gt; has an unexpected encoding or locale setting, every database you create afterward quietly inherits it, and the symptoms show up much later as garbled text or sorting that doesn't behave the way you'd expect.&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%2Fy5p5ow0fh8xr44ry0njy.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%2Fy5p5ow0fh8xr44ry0njy.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a project database, step by step
&lt;/h2&gt;

&lt;p&gt;Say you're starting the geospatial dashboard from nothing. Here's roughly how that goes in practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-h&lt;/span&gt; localhost &lt;span class="nt"&gt;-p&lt;/span&gt; 5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're connected to the default &lt;code&gt;postgres&lt;/code&gt; database — not your project's yet, just the entry point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirms nothing named &lt;code&gt;venue_dashboard&lt;/code&gt; already exists, so you're not about to collide with something.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;venue_dashboard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="n"&gt;venue_dashboard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you're connected to your project's own database, kept separate from anything else on the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing comes back — no tables yet, which is expected on a fresh database. It also confirms you're actually in the right place before running any &lt;code&gt;CREATE TABLE&lt;/code&gt; statements.&lt;/p&gt;

&lt;p&gt;Connect, list, create, switch, verify. It's a small sequence, but it's one you end up running at the start of most new projects, and doing it deliberately once means you're not fumbling through it later, especially in something like a live technical interview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves you
&lt;/h2&gt;

&lt;p&gt;The few minutes before your first &lt;code&gt;CREATE TABLE&lt;/code&gt; matter more than they seem to. Knowing &lt;code&gt;\dt&lt;/code&gt;, &lt;code&gt;\d&lt;/code&gt;, and &lt;code&gt;\l&lt;/code&gt; well enough that you don't have to think about them, and understanding that &lt;code&gt;CREATE DATABASE&lt;/code&gt; clones a template rather than starting from nothing, makes navigating Postgres a lot less stressful day to day.&lt;/p&gt;

&lt;p&gt;Next time you sit down in &lt;code&gt;psql&lt;/code&gt;, even in a database you know well, try running the orientation commands first anyway. It's a small habit, but it holds up well as the number of databases and tables you're dealing with grows.&lt;/p&gt;

&lt;p&gt;Next up: actually shaping data — tables, data types, and constraints that make bad data hard to insert in the first place.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>sql</category>
      <category>postgressql</category>
      <category>database</category>
    </item>
    <item>
      <title>Egg Dropping: Min Outside, Max Inside</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Sat, 10 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/egg-dropping-min-outside-max-inside-cp1</link>
      <guid>https://dev.to/im_nishant/egg-dropping-min-outside-max-inside-cp1</guid>
      <description>&lt;p&gt;Scrambled String needed an extra dimension because a substring couldn't be pinned down by position alone, it also needed a length. Egg Dropping needs something different again: the partition point k isn't a place in a string this time, it's an actual floor of a building, and for the first time in this series, the combining step has to account for the fact that you don't get to see the outcome of your own choice before committing to it.&lt;/p&gt;




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

&lt;p&gt;You have E eggs and a building with F floors. There's some unknown threshold floor: eggs dropped from it or below survive, eggs dropped above it break. You want to find that threshold using as few drops as possible, but you have to plan for the worst case, since you don't know in advance which floor the threshold actually is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Floor:   1  2  3  4  5  6  7  8  9  10
         ok ok ok ok ok break break break break break
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the threshold is floor 5. The egg survives dropped from there, and breaks from floor 6 onward. If you tested floors one at a time starting from the bottom, you could end up needing all the way up to F drops in the worst case, since the threshold could turn out to be the very last floor you try. The goal is a strategy that guarantees finding the threshold using as few worst-case attempts as possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  Picking a Floor to Test
&lt;/h2&gt;

&lt;p&gt;Say you drop an egg from floor k. There are exactly two outcomes, and each one tells you something different about where the threshold has to be.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          10
           9
           8
           7
           6
          --------------
           5   &amp;lt;- drop here
          --------------
           4
           3
           2
           1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The egg breaks.&lt;/strong&gt; The threshold has to be below k. Every floor at k and above is now known to break, so the search space shrinks to floors 1 through k-1. You've also used up one of your eggs, since it just broke, so you're left with E-1 eggs and k-1 floors still to search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;subproblem: solve(E - 1, k - 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The egg survives.&lt;/strong&gt; The threshold has to be at k or above. Floors below k are ruled out, and the search space becomes k+1 through F, a span of F-k floors. Since the egg survived, you still have all E eggs, just fewer floors left to check.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;subproblem: solve(E, F - k)
&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;                     Drop at k
                         |
              +----------+----------+
              |                     |
            Break                No Break
              |                     |
        E - 1 eggs                E eggs
        k - 1 floors             F - k floors
              |                     |
       solve(E-1, k-1)         solve(E, F-k)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the part that's genuinely new compared to every problem earlier in this series. You don't get to choose which of these two outcomes happens. The egg either breaks or it doesn't, and you have no control over that, and no way to know in advance. So whatever strategy you commit to has to be judged by its worst possible outcome, not its best one. That means the two branches get combined with &lt;code&gt;max&lt;/code&gt;, not the &lt;code&gt;min&lt;/code&gt; or the &lt;code&gt;sum&lt;/code&gt; seen in earlier chapters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 + max(solve(E - 1, k - 1), solve(E, F - k))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;+1&lt;/code&gt; accounts for the drop you just made, which counts as one attempt regardless of which way it goes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Still Looks Like MCM
&lt;/h2&gt;

&lt;p&gt;The core move is identical to every problem in this series so far: try every possible partition point, solve two subproblems, combine them. What's different is the shape of the combination.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for k in range(1, F + 1):
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every earlier problem in this family picked the best partition using a &lt;code&gt;min&lt;/code&gt; over k. Egg Dropping does that too, but with a twist: at each individual k, you first have to brace for the worse of the two outcomes with &lt;code&gt;max&lt;/code&gt;, and only after that do you compare across different values of k with &lt;code&gt;min&lt;/code&gt;, looking for whichever floor gives the smallest worst-case guarantee.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                   MIN (choose the best floor)
                    |
       +------------+------------+
       k=1         k=2          k=3 ...
        |            |             |
      MAX          MAX           MAX  (brace for the worse outcome)
     /    \        /    \        /    \
 break  survive  break  survive break  survive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That min-outside, max-inside structure is the actual signature of this problem, and it's worth naming explicitly, because it's the piece that's genuinely new. Every earlier problem in this series only ever needed one of the two: MCM and Palindrome Partitioning only needed &lt;code&gt;min&lt;/code&gt;, Boolean Parenthesization only needed sums, Scrambled String only needed a boolean &lt;code&gt;or&lt;/code&gt;. This is the first one that needs both a &lt;code&gt;min&lt;/code&gt; and a &lt;code&gt;max&lt;/code&gt; at once, nested inside each other, because you're optimizing a strategy against an adversary you can't predict.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dp(E, F) = min over 1 &amp;lt;= k &amp;lt;= F of { 1 + max(dp(E - 1, k - 1), dp(E, F - k)) }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Three conditions end the recursion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No floors left (&lt;code&gt;F == 0&lt;/code&gt;):&lt;/strong&gt; nothing to test, zero attempts needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One floor left (&lt;code&gt;F == 1&lt;/code&gt;):&lt;/strong&gt; there's nothing to narrow down, one drop settles it, so it's one attempt either way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Down to one egg (&lt;code&gt;E == 1&lt;/code&gt;):&lt;/strong&gt; this one is worth sitting with, because it's the case where the whole partitioning strategy stops being available to you. With only one egg left, you can no longer afford the risk of testing high up and having it break, since a single break with no eggs left in reserve means you can't continue testing at all. The only safe strategy left is testing floors one at a time from the bottom, which means the worst case is F attempts, testing every floor in sequence until you find the one that breaks.&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;F&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;F&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;F&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;E&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;F&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%2Fng93fjuzds3fg9ko843d.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%2Fng93fjuzds3fg9ko843d.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Recursive 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;solve&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;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&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;F&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;F&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;F&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;E&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;F&lt;/span&gt;

        &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&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;F&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;break_case&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;no_break_case&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt; &lt;span class="o"&gt;-&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;attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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;break_case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;no_break_case&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;eggDrop&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;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&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;self&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;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A Small Example: E = 2, F = 3
&lt;/h2&gt;

&lt;p&gt;Try dropping at floor k = 2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If it breaks:&lt;/strong&gt; one egg left, one floor left below (floor 1) to check. &lt;code&gt;solve(1, 1) = 1&lt;/code&gt; attempt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If it survives:&lt;/strong&gt; two eggs still available, one floor left above (floor 3) to check. &lt;code&gt;solve(2, 1) = 1&lt;/code&gt; attempt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;attempts at k = 2 = 1 + max(1, 1) = 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With 2 eggs and 3 floors, dropping first at floor 2 guarantees finding the threshold in at most 2 attempts, regardless of which way that first drop goes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two Ways to Represent the Same State
&lt;/h2&gt;

&lt;p&gt;Just like Scrambled String had a dictionary version and an index-based version describing the same subproblem, Egg Dropping has an equivalent choice, whether to model floors as an explicit range &lt;code&gt;(i, j)&lt;/code&gt; or as a simple count &lt;code&gt;F&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicit interval:&lt;/strong&gt; &lt;code&gt;solve(E, i, j)&lt;/code&gt;, tracking the actual floor boundaries. A partition at k splits the break case into &lt;code&gt;i&lt;/code&gt; through &lt;code&gt;k-1&lt;/code&gt; and the survive case into &lt;code&gt;k+1&lt;/code&gt; through &lt;code&gt;j&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;min over i &amp;lt;= k &amp;lt;= j of { 1 + max(solve(E - 1, i, k - 1), solve(E, k + 1, j)) }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Relative span:&lt;/strong&gt; &lt;code&gt;solve(E, F)&lt;/code&gt;, tracking only how many untested floors remain, not their absolute labels.&lt;/p&gt;

&lt;p&gt;The reason the simpler version works here, and it's a genuinely useful thing to notice, is that this problem doesn't care &lt;em&gt;which specific floors&lt;/em&gt; remain, only &lt;em&gt;how many&lt;/em&gt;. Floors 4 through 10 behave identically to floors 1 through 7 as far as the strategy is concerned, since nothing about the problem references a floor's absolute position, only the count of floors still left to search. That's different from something like Palindrome Partitioning, where the actual characters at each position mattered, not just how many characters were left. Because Egg Dropping's subproblems only ever depend on a count, the 2D state &lt;code&gt;(E, F)&lt;/code&gt; is already complete, with no need for the extra index bookkeeping that Scrambled String's &lt;code&gt;length&lt;/code&gt; dimension required.&lt;/p&gt;




&lt;h2&gt;
  
  
  Memoization: A 2D Table
&lt;/h2&gt;

&lt;p&gt;Since only two things change between subproblems, the number of eggs and the number of remaining floors, an &lt;code&gt;(E+1) x (F+1)&lt;/code&gt; table covers the entire state space.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        F -&amp;gt;
E |    0  1  2  3  4  5 ...
      ---------------------
  1  |
  2  |
  3  |
  4  |
&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;solve&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;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;F&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;F&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;F&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;E&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;F&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;E&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;F&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;E&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&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;F&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;break_case&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="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;no_break_case&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt; &lt;span class="o"&gt;-&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;attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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;break_case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;no_break_case&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attempts&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;E&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ans&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;E&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;F&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;eggDrop&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;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&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;F&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;E&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;self&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;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same memoization pattern from every earlier chapter, check before computing, store after, just keyed on &lt;code&gt;(E, F)&lt;/code&gt; instead of &lt;code&gt;(i, j)&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Interval DP Family, Side by Side
&lt;/h2&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;Partition point&lt;/th&gt;
&lt;th&gt;Subproblems&lt;/th&gt;
&lt;th&gt;Combination&lt;/th&gt;
&lt;th&gt;Objective&lt;/th&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MCM&lt;/td&gt;
&lt;td&gt;k between matrices&lt;/td&gt;
&lt;td&gt;solve(i,k), solve(k+1,j)&lt;/td&gt;
&lt;td&gt;left + right + scalar cost&lt;/td&gt;
&lt;td&gt;min&lt;/td&gt;
&lt;td&gt;2D: T[i][j]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Palindrome Partitioning&lt;/td&gt;
&lt;td&gt;k between string indices&lt;/td&gt;
&lt;td&gt;solve(i,k), solve(k+1,j)&lt;/td&gt;
&lt;td&gt;left + right + 1&lt;/td&gt;
&lt;td&gt;min&lt;/td&gt;
&lt;td&gt;2D: T[i][j]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boolean Parenthesization&lt;/td&gt;
&lt;td&gt;k at operator positions&lt;/td&gt;
&lt;td&gt;left(T/F), right(T/F)&lt;/td&gt;
&lt;td&gt;truth table combinations&lt;/td&gt;
&lt;td&gt;count (sum)&lt;/td&gt;
&lt;td&gt;3D: T[i][j][isTrue]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scrambled String&lt;/td&gt;
&lt;td&gt;k splitting string lengths&lt;/td&gt;
&lt;td&gt;no_swap(left,right), swap(left,right)&lt;/td&gt;
&lt;td&gt;boolean OR&lt;/td&gt;
&lt;td&gt;boolean match&lt;/td&gt;
&lt;td&gt;3D: T[i][j][length]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Egg Dropping&lt;/td&gt;
&lt;td&gt;k = dropped floor&lt;/td&gt;
&lt;td&gt;solve(E-1,k-1), solve(E,F-k)&lt;/td&gt;
&lt;td&gt;1 + max(break, survive)&lt;/td&gt;
&lt;td&gt;min over k&lt;/td&gt;
&lt;td&gt;2D: T[E][F]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every row in this table shares the same skeleton, boundaries, a loop over k, two subproblems, a combining rule. What's actually been changing chapter to chapter is entirely in the last two or three columns: what the subproblems represent, how they combine, and how many dimensions the state needs to carry. Egg Dropping's real contribution to this table isn't a new kind of partitioning, it's the first appearance of &lt;code&gt;max&lt;/code&gt; inside the combination step, sitting underneath the &lt;code&gt;min&lt;/code&gt; that every other row in this table already had.&lt;/p&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Egg Dropping
     |
Choose a floor k
     |
     +-----------------------+
     |                       |
   BREAK                  SURVIVE
     |                       |
 E - 1 eggs              E eggs
 k - 1 floors            F - k floors
     |                       |
     +----------+------------+
                |
        max(break, survive)
                |
          + 1 attempt
                |
      try every possible k
                |
             minimum

Base cases:
  F == 0 or F == 1  -&amp;gt; return F
  E == 1            -&amp;gt; return F (must test bottom-up)

Recurrence:
  dp(E, F) = min over k of { 1 + max(dp(E-1, k-1), dp(E, F-k)) }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"min outside, max inside" is the signature of this problem, and more broadly, of interval DP problems where you're minimizing a worst-case guarantee rather than a straightforward cost. The &lt;code&gt;min&lt;/code&gt; picks the best strategy available to you. The &lt;code&gt;max&lt;/code&gt; accounts for the fact that once you've picked, the outcome isn't yours to control.&lt;/p&gt;




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

&lt;p&gt;Egg Dropping keeps the exact partitioning skeleton this whole series has been building on, but it's the first problem where the two subproblems on either side of the split aren't both under your control. One of them happens &lt;em&gt;to&lt;/em&gt; you, not because you chose it. That's why &lt;code&gt;max&lt;/code&gt; shows up nested inside the &lt;code&gt;min&lt;/code&gt; here for the first time: the outer &lt;code&gt;min&lt;/code&gt; is you picking the best strategy, and the inner &lt;code&gt;max&lt;/code&gt; is bracing for whichever of the two outcomes turns out worse, since you don't get to decide which one you get.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Scrambled String: The MCM Skeleton, Now With Two Strings and a Swap Choice</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Fri, 09 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/scrambled-string-the-mcm-skeleton-now-with-two-strings-and-a-swap-choice-457l</link>
      <guid>https://dev.to/im_nishant/scrambled-string-the-mcm-skeleton-now-with-two-strings-and-a-swap-choice-457l</guid>
      <description>&lt;p&gt;Boolean Parenthesization stretched the state from &lt;code&gt;(i, j)&lt;/code&gt; to &lt;code&gt;(i, j, isTrue)&lt;/code&gt; because a single number stopped being enough to describe a subproblem. Scrambled String stretches things differently. There are now two strings involved instead of one, and at every partition point there's a genuine choice: keep the two halves in order, or swap them. The skeleton is still the same one from MCM. What changes is what counts as a valid match on each side of the split.&lt;/p&gt;




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

&lt;p&gt;Given two strings A and B, determine whether B is a scrambled version of A.&lt;/p&gt;

&lt;p&gt;A scrambled string comes from repeatedly splitting a string in two and optionally swapping the two halves, recursively, at every level. Picture &lt;code&gt;A = GREAT&lt;/code&gt; as a binary tree, where each split produces two children that can optionally be swapped:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             GREAT
            /     \
          GR       EAT
         /  \     /   \
        G    R   E     AT
                       / \
                      A   T
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At any non-leaf node in this tree, the two children are allowed to swap places. Swapping &lt;code&gt;GR&lt;/code&gt; gives &lt;code&gt;RG&lt;/code&gt;. Swapping &lt;code&gt;EAT&lt;/code&gt; gives &lt;code&gt;ATE&lt;/code&gt;. If enough of these swaps happen at the right places, &lt;code&gt;GREAT&lt;/code&gt; can be transformed into some other arrangement, and the question is whether B is reachable from A this way.&lt;/p&gt;

&lt;p&gt;A split always has to produce two non-empty parts. Splitting &lt;code&gt;GREAT&lt;/code&gt; into &lt;code&gt;GREAT&lt;/code&gt; and an empty string isn't a valid partition, so index 0 and index n are both off-limits as split points.&lt;/p&gt;

&lt;p&gt;Two things are worth noting before going further. Zero swaps is a completely valid scramble. If A and B are identical, that's a scrambled string with nothing actually scrambled, and it should return True. And if A and B have different lengths, B can never be a scramble of A at all, so that's an immediate False before anything else gets checked.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recognising the MCM Pattern
&lt;/h2&gt;

&lt;p&gt;The core question, "where can this string be split," is the same question MCM has been asking all along.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GREAT can split at:
  G | REAT
  GR | EAT
  GRE | AT
  GREA | T
&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;String
  |
Can be recursively divided into two parts
  |
Try every possible partition
  |
Check left and right parts
  |
MCM / Interval DP pattern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no scalar cost being minimized here the way there was in MCM's multiplication cost or Palindrome Partitioning's cut count. What carries over from MCM isn't the specific thing being optimized, it's the structural template underneath all of these problems: partition, solve the left, solve the right, combine. Scrambled String borrows that template and fills in a completely different combining rule.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Happens After You Partition
&lt;/h2&gt;

&lt;p&gt;Here's where this problem earns its own identity. Split A at position k, giving &lt;code&gt;A1 = A[0:k]&lt;/code&gt; and &lt;code&gt;A2 = A[k:n]&lt;/code&gt;. B has to be split to match, but because of the swap rule, there are two different ways B's pieces could correspond to A's pieces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No swap:&lt;/strong&gt; &lt;code&gt;A1&lt;/code&gt; should match a same-length piece of B taken from the front, and &lt;code&gt;A2&lt;/code&gt; should match the rest of B.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A1 -&amp;gt; B1 (length k)
A2 -&amp;gt; B2 (length n-k)

Check: solve(A1, B1) and solve(A2, B2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Swap:&lt;/strong&gt; &lt;code&gt;A1&lt;/code&gt; should match a same-length piece of B taken from the &lt;em&gt;end&lt;/em&gt;, and &lt;code&gt;A2&lt;/code&gt; should match whatever's left at the front of B.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A1 -&amp;gt; B2 (length k)
A2 -&amp;gt; B1 (length n-k)

Check: solve(A1, B2) and solve(A2, B1)
&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;              Split at k
                  |
        ---------------------
        |                   |
    No Swap               Swap
    A1 -&amp;gt; B1               A1 -&amp;gt; B2
    A2 -&amp;gt; B2               A2 -&amp;gt; B1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If either the no-swap combination works or the swap combination works, for any valid k, the whole thing is a match. That's an OR across every partition point, and within each partition point, an AND between the two halves matching. k ranges from 1 to n-1 inclusive, the same non-empty-halves constraint mentioned earlier:&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;k&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="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%2F0grj4vbg0m8s552a2bku.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%2F0grj4vbg0m8s552a2bku.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;Three checks run before any partitioning happens, and they're worth doing in this specific order, since each one is cheaper than the next and can short-circuit the more expensive recursive work below it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Length mismatch:&lt;/strong&gt; if &lt;code&gt;len(A) != len(B)&lt;/code&gt;, return False immediately. Nothing else needs checking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exact match:&lt;/strong&gt; if &lt;code&gt;A == B&lt;/code&gt;, return True. Zero swaps is a legitimate scramble, and this also happens to be the natural base case that ends the recursion once a partition has been narrowed down to matching single characters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anagram pruning:&lt;/strong&gt; if &lt;code&gt;sorted(A) != sorted(B)&lt;/code&gt;, return False. This one is worth sitting with, because it's not obviously necessary the way the first two checks are; it's an optimization built on a real property of the problem. Swapping the two children of a node in the scramble tree rearranges characters, but it can never create or destroy them, and it can never change &lt;em&gt;how many&lt;/em&gt; of each character exist. So if A and B don't contain the same multiset of characters, no sequence of swaps, at any level of the tree, could ever turn one into the other. Checking this early prunes off entire branches of recursion that are doomed before a single partition gets tried.&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;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&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;B&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;B&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="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&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;h2&gt;
  
  
  The Recursive 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;solve&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;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="k"&gt;if&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;A&lt;/span&gt;&lt;span class="p"&gt;)&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;B&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;B&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="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&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="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;A&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;k&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="p"&gt;):&lt;/span&gt;

            &lt;span class="c1"&gt;# No Swap
&lt;/span&gt;            &lt;span class="n"&gt;left&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&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="n"&gt;B&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="n"&gt;right&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&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="n"&gt;B&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;left&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

            &lt;span class="c1"&gt;# Swap
&lt;/span&gt;            &lt;span class="n"&gt;left&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&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="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
            &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&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;A&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="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;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;left&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;isScramble&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;s1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s2&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;self&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;s1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The swapped indexing is the detail most likely to trip you up on a first read, so it's worth spelling out explicitly. &lt;code&gt;A1&lt;/code&gt;, the first k characters of A, has length k, so in the swap case it needs to match the &lt;em&gt;last&lt;/em&gt; k characters of B, which is &lt;code&gt;B[n-k:]&lt;/code&gt;. &lt;code&gt;A2&lt;/code&gt;, the remaining &lt;code&gt;n-k&lt;/code&gt; characters of A, needs to match whatever's left, the &lt;em&gt;first&lt;/em&gt; &lt;code&gt;n-k&lt;/code&gt; characters of B, which is &lt;code&gt;B[:n-k]&lt;/code&gt;. The lengths on both sides always have to agree; only which end of B they're pulled from changes between the swap and no-swap cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  Memoizing with a Dictionary
&lt;/h2&gt;

&lt;p&gt;The recursion above re-solves identical &lt;code&gt;(A, B)&lt;/code&gt; substring pairs across different partition branches constantly, which is the same overlapping-subproblems signal that justified memoization in every earlier chapter of this series. The most direct way to cache it is keying on the actual substrings themselves.&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;solve&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;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="k"&gt;if&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;A&lt;/span&gt;&lt;span class="p"&gt;)&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;B&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;B&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="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&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="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&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;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;memo&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;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&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;A&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;k&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="p"&gt;):&lt;/span&gt;

            &lt;span class="c1"&gt;# No Swap
&lt;/span&gt;            &lt;span class="n"&gt;left&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&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="n"&gt;B&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="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&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;A&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="n"&gt;B&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="n"&gt;memo&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;left&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&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;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

            &lt;span class="c1"&gt;# Swap
&lt;/span&gt;            &lt;span class="n"&gt;left&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&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="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:],&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&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;A&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="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;memo&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;left&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&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;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

        &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;isScramble&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;s1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;memo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&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;s1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key is the pair &lt;code&gt;(A, B)&lt;/code&gt; itself, the actual substrings, not indices. This works correctly, but it's worth noticing what it's actually storing: two full string objects per cache entry, which is more memory than strictly necessary given that every substring here is fully determined by where it starts and how long it is.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two Ways to Represent the Same State
&lt;/h2&gt;

&lt;p&gt;Both the dictionary approach and an index-based array approach are tracking the exact same logical subproblem. They just describe the coordinates of that subproblem differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dictionary approach:&lt;/strong&gt; keys are &lt;code&gt;(A, B)&lt;/code&gt;, the substrings themselves. The length of each substring is implicit, it's just &lt;code&gt;len(A)&lt;/code&gt; and &lt;code&gt;len(B)&lt;/code&gt;, and the starting position within the original string isn't tracked at all, because the substring itself carries all the information needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Array approach:&lt;/strong&gt; coordinates are &lt;code&gt;T[i][j][length]&lt;/code&gt;, where &lt;code&gt;i&lt;/code&gt; is the starting index into the original A, &lt;code&gt;j&lt;/code&gt; is the starting index into the original B, and &lt;code&gt;length&lt;/code&gt; is how long the matching substrings are. Nothing gets sliced into a new substring object; the boundaries are computed on demand as &lt;code&gt;A[i : i+length]&lt;/code&gt; and &lt;code&gt;B[j : j+length]&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;Dictionary:  key = (A, B)                    -&amp;gt; substrings carry their own length
Array:       key = (i, j, length)            -&amp;gt; substrings recomputed from indices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same tradeoff that shows up anywhere a problem can be memoized either by value (the actual substring) or by position (indices into the original string). The array version avoids the overhead of creating and hashing new string objects on every recursive call, at the cost of needing one more dimension, length, that the dictionary version got for free by just measuring the strings it was already holding onto.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 3D Index-Based Version
&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;solve&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;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&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="n"&gt;length&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;B&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;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;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="n"&gt;length&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;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="n"&gt;length&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;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;length&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="n"&gt;length&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;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="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;length&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="n"&gt;length&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="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&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;length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

            &lt;span class="c1"&gt;# No Swap
&lt;/span&gt;            &lt;span class="n"&gt;left&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&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="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;right&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&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="n"&gt;k&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;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;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="n"&gt;length&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;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

            &lt;span class="c1"&gt;# Swap
&lt;/span&gt;            &lt;span class="n"&gt;left&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&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;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;right&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&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="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;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="n"&gt;length&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;return&lt;/span&gt; &lt;span class="bp"&gt;True&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="n"&gt;length&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="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;isScramble&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;s1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s2&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;s1&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;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;s2&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="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="p"&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;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&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;solve&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="n"&gt;s2&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="n"&gt;n&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;T&lt;/code&gt; uses three sentinel values: &lt;code&gt;-1&lt;/code&gt; for not yet computed, &lt;code&gt;0&lt;/code&gt; for False, and &lt;code&gt;1&lt;/code&gt; for True, since a plain boolean can't represent "haven't checked this yet" the way &lt;code&gt;-1&lt;/code&gt; can.&lt;/p&gt;

&lt;p&gt;The swap indexing needs the same care here that it needed in the plain recursive version, just expressed through index arithmetic instead of slicing. For a split at &lt;code&gt;k&lt;/code&gt; within a range of &lt;code&gt;length&lt;/code&gt;, the left partition has length &lt;code&gt;k&lt;/code&gt; and the right partition has length &lt;code&gt;length - k&lt;/code&gt;. In the swap case, the left partition of A needs to match against a piece of B starting at &lt;code&gt;j + length - k&lt;/code&gt;, that offset is what places it at the &lt;em&gt;end&lt;/em&gt; of the current B range rather than the start. The right partition of A matches against B starting right at &lt;code&gt;j&lt;/code&gt;, the front of the range.&lt;/p&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scrambled String
       |
Recursive partitioning
       |
MCM / Interval DP pattern
       |
Try k = 1 to n-1
       |
       +-----------------+
       |                 |
    No Swap            Swap
       |                 |
 A1 -&amp;gt; B1             A1 -&amp;gt; B2
 A2 -&amp;gt; B2             A2 -&amp;gt; B1
       |                 |
       +------ OR -------+
                |
             True/False

Base cases, in order:
  len(A) != len(B)         -&amp;gt; False
  A == B                   -&amp;gt; True
  sorted(A) != sorted(B)   -&amp;gt; False (anagram pruning)

Memoization:
  Dictionary: key = (A, B)
  Array:      T[i][j][length], sentinels -1/0/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;MCM tells you where to partition. It's the scrambling rule specifically, the choice between matching halves in order or swapped, that tells you how the two sides are allowed to correspond once you've split. That's the part genuinely new to this problem: an extra binary decision at every partition point, checked as an OR across two different pairings rather than a single fixed combination the way MCM and Palindrome Partitioning had.&lt;/p&gt;

&lt;p&gt;The other genuinely new idea here is the length dimension in the index-based memoization. Boolean Parenthesization needed one extra dimension, &lt;code&gt;isTrue&lt;/code&gt;, because a single count wasn't enough information for a subproblem. Scrambled String needs one extra dimension, &lt;code&gt;length&lt;/code&gt;, because tracking a substring by its starting position alone isn't sufficient, you also need to know how far it extends, once you stop carrying that information implicitly inside an actual sliced-out string.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Coin Change I: When the Default Value Can Break Everything</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Thu, 08 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/coin-change-i-when-the-default-value-can-break-everything-2ebc</link>
      <guid>https://dev.to/im_nishant/coin-change-i-when-the-default-value-can-break-everything-2ebc</guid>
      <description>&lt;p&gt;Coin Change II counts ways. Coin Change I asks a different question: what is the minimum number of coins needed to make a given amount?&lt;/p&gt;

&lt;p&gt;The choice structure is identical. Unbounded, same-row TAKE, previous-row SKIP. Two things change: &lt;code&gt;+&lt;/code&gt; becomes &lt;code&gt;min(...) + 1&lt;/code&gt;, and the initialisation needs careful thought because the default value for an impossible state can no longer be zero.&lt;/p&gt;

&lt;p&gt;That second point is where most people get confused on this problem. This chapter addresses it directly.&lt;/p&gt;




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



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

Some combinations:
  2 + 3          → 2 coins
  1 + 1 + 3      → 3 coins
  1 + 2 + 2      → 3 coins
  1 + 1 + 1 + 2  → 4 coins

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

&lt;/div&gt;



&lt;p&gt;Same coins as Coin Change II. Same amount. But instead of counting four ways, you want the one that uses the fewest coins.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Initialisation Is Different
&lt;/h2&gt;

&lt;p&gt;In Coin Change II, the table stored counts. A count of zero meant "zero ways to make this amount," which was a valid meaningful answer. And &lt;code&gt;T[i][0] = 1&lt;/code&gt; because there is one way to make amount zero: choose nothing.&lt;/p&gt;

&lt;p&gt;Here the table stores the minimum number of coins. Zero means "zero coins needed," which is the correct answer for amount zero. But for amounts that are genuinely impossible to make with the available coins, you can't store zero — that would look like "zero coins needed," which is wrong. You need a sentinel value that means "this state is unreachable."&lt;/p&gt;

&lt;p&gt;That sentinel is a very large number, conventionally called &lt;code&gt;INF&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;min()&lt;/code&gt; compares a real answer against &lt;code&gt;INF&lt;/code&gt;, &lt;code&gt;INF&lt;/code&gt; loses and gets ignored. That's its entire purpose.&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%2Fjd1qtoup6i1fn8kdpctm.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%2Fjd1qtoup6i1fn8kdpctm.png" alt=" " width="799" height="333"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why &lt;code&gt;INF = 2**31 - 2&lt;/code&gt; and Not &lt;code&gt;2**31 - 1&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;When you TAKE a coin, the transition adds 1:&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="mi"&gt;1&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="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;coins&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;T[i][j - coins[i-1]]&lt;/code&gt; is &lt;code&gt;2**31 - 1&lt;/code&gt; (the maximum integer), adding 1 causes integer overflow in languages like C++ and Java. The result wraps around to a negative number, which then looks like a valid minimum — a completely silent wrong answer.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;2**31 - 2&lt;/code&gt; keeps it one step back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 + (2**31 - 2) = 2**31 - 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still a huge number, still loses to any real answer in &lt;code&gt;min()&lt;/code&gt;, but doesn't overflow.&lt;/p&gt;

&lt;p&gt;In Python, integers don't overflow, so &lt;code&gt;float('inf')&lt;/code&gt; works fine. But knowing why the &lt;code&gt;-1&lt;/code&gt; is there matters if you're writing this in any other language.&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] = minimum coins needed to make amount j
           using the first i coins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Initialisation in Three Parts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Amount zero:&lt;/strong&gt; Zero coins needed regardless of which coins are available.&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;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;No coins available (row 0):&lt;/strong&gt; Every positive amount 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="c1"&gt;# T[0][j] = INF for all j &amp;gt; 0
# Already handled if table is initialised to INF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;First coin row (row 1):&lt;/strong&gt; This needs its own loop. With only the first coin available, an amount is reachable only if it's exactly divisible by that coin.&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;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;amount&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;j&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;coins&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;0&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="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="o"&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;coins&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="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="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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, with &lt;code&gt;coins[0] = 3&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;Amount: 0   1    2    3    4    5    6    7    8    9
Coins:  0  INF  INF   1   INF  INF   2   INF  INF   3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Amount 3 needs 1 coin. Amount 6 needs 2. Amount 1, 2, 4, 5, 7, 8 are impossible with only coin 3.&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%2Flsccrrf0zm5w3rkrmgy4.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%2Flsccrrf0zm5w3rkrmgy4.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;When the coin fits (&lt;code&gt;coins[i-1] &amp;lt;= j&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;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;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="mi"&gt;1&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="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;coins&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: same row + 1 coin
&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: previous row
&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; counts the coin being taken. The same-row reference allows taking the same coin again.&lt;/p&gt;

&lt;p&gt;When the coin doesn't fit:&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="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;# only SKIP
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Operation Table
&lt;/h2&gt;

&lt;p&gt;Across the Unbounded family, the operation is the only thing that varies:&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;Goal&lt;/th&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rod Cutting&lt;/td&gt;
&lt;td&gt;Maximum profit&lt;/td&gt;
&lt;td&gt;&lt;code&gt;max(take, skip)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coin Change II&lt;/td&gt;
&lt;td&gt;Count ways&lt;/td&gt;
&lt;td&gt;&lt;code&gt;take + skip&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coin Change I&lt;/td&gt;
&lt;td&gt;Minimum coins&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min(1 + take, skip)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;+1&lt;/code&gt; in Coin Change I is because taking a coin costs one coin. The &lt;code&gt;1 +&lt;/code&gt; is absent in Rod Cutting and Coin Change II because they don't count individual items used.&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%2Fxiddgykra958syh5k8m0.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%2Fxiddgykra958syh5k8m0.png" alt=" " width="799" height="333"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Complete 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;coinChange&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;coins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&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;coins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# INF represents an impossible/unreachable state.
&lt;/span&gt;        &lt;span class="c1"&gt;# Using 2**31 - 2 instead of 2**31 - 1 so that
&lt;/span&gt;        &lt;span class="c1"&gt;# 1 + INF doesn't overflow in other languages.
&lt;/span&gt;        &lt;span class="c1"&gt;# In Python, float('inf') also works.
&lt;/span&gt;        &lt;span class="n"&gt;INF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

        &lt;span class="c1"&gt;# T[i][j] = minimum coins to make amount j
&lt;/span&gt;        &lt;span class="c1"&gt;# using first i coins.
&lt;/span&gt;        &lt;span class="c1"&gt;# Start everything as INF — unreachable by default.
&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="n"&gt;INF&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;amount&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;# Amount 0 needs 0 coins — for every row
&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="mi"&gt;0&lt;/span&gt;

        &lt;span class="c1"&gt;# First coin row: only reachable if amount
&lt;/span&gt;        &lt;span class="c1"&gt;# is exactly divisible by coins[0]
&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;amount&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;j&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;coins&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;0&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="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="o"&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;coins&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="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="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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INF&lt;/span&gt;

        &lt;span class="c1"&gt;# Fill remaining rows
&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;2&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;amount&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;coins&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;# TAKE: same row (coin can be reused), add 1 coin
&lt;/span&gt;                    &lt;span class="c1"&gt;# SKIP: previous row
&lt;/span&gt;                    &lt;span class="c1"&gt;# min() because we want fewest coins
&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;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="mi"&gt;1&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="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;coins&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;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;# Coin too large — only skip
&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;# If still INF, the amount is impossible
&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;amount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;INF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;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;amount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final check &lt;code&gt;if T[n][amount] == INF: return -1&lt;/code&gt; handles the case where no combination of coins can make the target amount. LeetCode's Coin Change problem expects &lt;code&gt;-1&lt;/code&gt; for this case.&lt;/p&gt;




&lt;h2&gt;
  
  
  One Correction Worth Keeping in Your Notes
&lt;/h2&gt;

&lt;p&gt;An empty coin array with a positive amount does not mean "infinite ways." It means "impossible." There are zero ways, and the minimum number of coins is undefined — represented as &lt;code&gt;INF&lt;/code&gt;. The confusion comes from mixing up Count of Subsets thinking (where &lt;code&gt;T[i][0] = 1&lt;/code&gt; represents the empty combination) with this problem (where &lt;code&gt;T[i][0] = 0&lt;/code&gt; represents zero coins needed and &lt;code&gt;INF&lt;/code&gt; represents unreachable).&lt;/p&gt;

&lt;p&gt;These are different kinds of "nothing."&lt;/p&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T[i][j] = minimum coins to make amount j using first i coins

Initialisation:
  Everything starts as INF
  T[i][0] = 0          (amount 0 → 0 coins)
  T[1][j] = j//coins[0] if j % coins[0] == 0, else INF

Transition:
  if coins[i-1] &amp;lt;= j:
    T[i][j] = min(1 + T[i][j-coins[i-1]], T[i-1][j])
  else:
    T[i][j] = T[i-1][j]

Final check:
  if T[n][amount] == INF: return -1

Why INF = 2**31 - 2:
  1 + INF must not overflow → use INF - 1 as sentinel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Coin Change I completes the core Unbounded Knapsack problem family. Three problems, one transition direction, three different operations: &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;min(...) + 1&lt;/code&gt;. The initialisation is the part that actually differs meaningfully between them, because it depends on what the table stores and what "impossible" means in each context.&lt;/p&gt;

&lt;p&gt;The next chapter moves to a different DP pattern entirely: Longest Common Subsequence. The choice diagram changes, the table dimensions change, but the same fundamental approach from Chapter 1 applies: understand the choices, find the base case, write the recursion, then build the table.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Boolean Parenthesization: The MCM Skeleton, Counting Instead of Minimising</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Thu, 08 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/boolean-parenthesization-the-mcm-skeleton-counting-instead-of-minimising-4kae</link>
      <guid>https://dev.to/im_nishant/boolean-parenthesization-the-mcm-skeleton-counting-instead-of-minimising-4kae</guid>
      <description>&lt;h1&gt;
  
  
  Boolean Parenthesization: The MCM Skeleton, Counting Instead of Minimising
&lt;/h1&gt;

&lt;p&gt;Matrix Chain Multiplication had matrices and multiplication costs. Palindrome Partitioning swapped that for a string and a &lt;code&gt;+1&lt;/code&gt; per cut. Boolean Parenthesization keeps the same skeleton again, but this time the combining step gets genuinely more involved, because the answer isn't a single number anymore, it's two: how many ways to reach True, and how many ways to reach False.&lt;/p&gt;




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

&lt;p&gt;Given a Boolean expression made of &lt;code&gt;T&lt;/code&gt;, &lt;code&gt;F&lt;/code&gt;, and the operators &lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;^&lt;/code&gt;, count how many distinct ways you can parenthesize it so the whole thing evaluates to True.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s = T | F &amp;amp; T

Two valid parenthesizations:
  (T | F) &amp;amp; T   → evaluates to True
  T | (F &amp;amp; T)   → evaluates to True

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

&lt;/div&gt;



&lt;p&gt;This isn't asking whether a True evaluation exists. It's asking how many structurally different ways of grouping the expression land on True.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recognising the MCM Pattern
&lt;/h2&gt;

&lt;p&gt;The same four signals from the MCM chapter show up here. There's a sequence you can partition (the expression). A minimum, or in this case a count, is being asked for. Multiple partition points are possible, one for each operator in the string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expression:       T | F &amp;amp; T
Partitions:       T | (F &amp;amp; T)
                   (T | F) &amp;amp; T
Counting answer:  yes
Multiple k:       yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same &lt;code&gt;(i, j, k)&lt;/code&gt; structure applies, with &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; marking the boundaries of the current substring and &lt;code&gt;k&lt;/code&gt; marking where you split it. The difference shows up almost immediately once you try to define what &lt;code&gt;solve(i, j)&lt;/code&gt; should even return.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why One Number Isn't Enough
&lt;/h2&gt;

&lt;p&gt;In MCM, &lt;code&gt;solve(i, j)&lt;/code&gt; returns a single number, the minimum cost. In Palindrome Partitioning, &lt;code&gt;solve(i, j)&lt;/code&gt; also returns a single number, the minimum cuts. Here, a single number breaks down almost immediately once you think through what combining two sides actually requires.&lt;/p&gt;

&lt;p&gt;Take the XOR operator. &lt;code&gt;Left ^ Right&lt;/code&gt; evaluates to True in exactly two situations: Left is True and Right is False, or Left is False and Right is True.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;True ^ False = True
False ^ True = True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To count the ways &lt;code&gt;Left ^ Right&lt;/code&gt; can be True, you need to know how many ways Left can be True, how many ways Left can be False, how many ways Right can be True, and how many ways Right can be False, all four, not just one of them. A &lt;code&gt;solve(i, j)&lt;/code&gt; that only tracks "minimum cost" or "cuts" has nowhere to put that information.&lt;/p&gt;

&lt;p&gt;So the state grows by one dimension. Instead of &lt;code&gt;solve(i, j)&lt;/code&gt;, it's &lt;code&gt;solve(i, j, isTrue)&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;solve(s, i, j, isTrue)

isTrue = True  → count of ways s[i..j] evaluates to True
isTrue = False → count of ways s[i..j] evaluates to False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every call to &lt;code&gt;solve&lt;/code&gt; for a given &lt;code&gt;(i, j)&lt;/code&gt; range actually needs both variants computed, because the combining step for whichever operator sits at the split point needs both the True count and the False count from each 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%2F9h5l2nbt62zhvjj0lfwo.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%2F9h5l2nbt62zhvjj0lfwo.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;Two conditions end the recursion, and they mirror the MCM and Palindrome Partitioning base cases closely, just adjusted for the extra &lt;code&gt;isTrue&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;i &amp;gt; j&lt;/code&gt;:&lt;/strong&gt; An invalid, empty range. Nothing to evaluate. Return 0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;i == j&lt;/code&gt;:&lt;/strong&gt; A single operand remains, either &lt;code&gt;T&lt;/code&gt; or &lt;code&gt;F&lt;/code&gt;. Whether this counts toward the answer depends on what &lt;code&gt;isTrue&lt;/code&gt; is asking for.&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;i&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;if&lt;/span&gt; &lt;span class="n"&gt;isTrue&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;T&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&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="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;F&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;isTrue&lt;/code&gt; is True and the single character is literally &lt;code&gt;T&lt;/code&gt;, there's exactly one way to make this range True, itself. If the character is &lt;code&gt;F&lt;/code&gt; instead, there are zero ways to make it True. The &lt;code&gt;isTrue = False&lt;/code&gt; branch mirrors this exactly, checking for &lt;code&gt;F&lt;/code&gt; instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finding k, Operators Only
&lt;/h2&gt;

&lt;p&gt;Just like MCM splits between matrices and Palindrome Partitioning splits between characters, Boolean Parenthesization splits at operator positions. Operands and operators alternate in the string, so &lt;code&gt;k&lt;/code&gt; has to land specifically on an operator index, never on a &lt;code&gt;T&lt;/code&gt; or &lt;code&gt;F&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;Index:  0   1   2   3   4
Value:  T   |   F   &amp;amp;   T
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operators sit at odd indices, &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt;. Stepping by 2 starting from &lt;code&gt;i + 1&lt;/code&gt; walks across exactly those positions:&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;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;k&lt;/code&gt; splits the expression into a left substring &lt;code&gt;s[i..k-1]&lt;/code&gt;, the operator &lt;code&gt;s[k]&lt;/code&gt;, and a right substring &lt;code&gt;s[k+1..j]&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Combining Step
&lt;/h2&gt;

&lt;p&gt;This is where the extra dimension actually pays off. For each &lt;code&gt;k&lt;/code&gt;, both sides get solved for both True and False:&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;leftTrue&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;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;leftFalse&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;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;rightTrue&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;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;rightFalse&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;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare this against the single &lt;code&gt;tempAns&lt;/code&gt; line from Palindrome Partitioning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MCM:                    tempAns = left + right + arr[i-1]*arr[k]*arr[j]
Palindrome Partitioning: tempAns = left + right + 1
Boolean Parenthesization: four separate values, combined differently per operator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no single &lt;code&gt;tempAns&lt;/code&gt; line here, because the combination depends entirely on which operator sits at &lt;code&gt;k&lt;/code&gt;. Each operator has its own truth table, and each truth table tells you exactly which pairs of left and right outcomes multiply together to contribute toward True, and which contribute toward False.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AND (&lt;code&gt;&amp;amp;&lt;/code&gt;):&lt;/strong&gt; True only when both sides are True.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target True:  leftTrue * rightTrue
target False: everything else = (leftTrue * rightFalse) + (leftFalse * rightTrue) + (leftFalse * rightFalse)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;OR (&lt;code&gt;|&lt;/code&gt;):&lt;/strong&gt; False only when both sides are False.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target True:  everything else = (leftTrue * rightTrue) + (leftTrue * rightFalse) + (leftFalse * rightTrue)
target False: leftFalse * rightFalse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;XOR (&lt;code&gt;^&lt;/code&gt;):&lt;/strong&gt; True only when the sides disagree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target True:  (leftTrue * rightFalse) + (leftFalse * rightTrue)
target False: (leftTrue * rightTrue) + (leftFalse * rightFalse)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In every case, multiplication combines two independent counts (this is the counting principle: if there are &lt;code&gt;a&lt;/code&gt; ways to make the left side a certain value and &lt;code&gt;b&lt;/code&gt; ways to make the right side a certain value, there are &lt;code&gt;a * b&lt;/code&gt; ways to combine them into that pair), and addition combines multiple mutually exclusive ways of reaching the same target across different operand combinations.&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%2F5hd77ntg0a07txfvedog.png" alt=" " width="800" height="533"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Recursive 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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;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="n"&gt;isTrue&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;i&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;if&lt;/span&gt; &lt;span class="n"&gt;isTrue&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;T&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&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="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;F&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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="n"&gt;leftTrue&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;leftFalse&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;rightTrue&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;rightFalse&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;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;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&lt;/span&gt;&lt;span class="sh"&gt;'&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;isTrue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;leftTrue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightTrue&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;leftTrue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightFalse&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;leftFalse&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightTrue&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;leftFalse&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightFalse&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isTrue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;leftTrue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightTrue&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;leftTrue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightFalse&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;leftFalse&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightTrue&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;leftFalse&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightFalse&lt;/span&gt;

            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;^&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isTrue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;leftTrue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightFalse&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;leftFalse&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightTrue&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;leftTrue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightTrue&lt;/span&gt;
                        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;leftFalse&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rightFalse&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;

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

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;countWays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;countWays&lt;/code&gt; calls &lt;code&gt;solve&lt;/code&gt; once, over the full string, asking specifically for the True count, since that's the actual question the problem is asking.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Small Dry Run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s = T ^ F
Index:  0   1   2
        T   ^   F
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only operator sits at &lt;code&gt;k = 1&lt;/code&gt;, so the left substring is &lt;code&gt;s[0..0] = "T"&lt;/code&gt; and the right substring is &lt;code&gt;s[2..2] = "F"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Left (&lt;code&gt;T&lt;/code&gt;):&lt;/strong&gt; &lt;code&gt;leftTrue = 1&lt;/code&gt; (it's literally &lt;code&gt;T&lt;/code&gt;), &lt;code&gt;leftFalse = 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Right (&lt;code&gt;F&lt;/code&gt;):&lt;/strong&gt; &lt;code&gt;rightTrue = 0&lt;/code&gt;, &lt;code&gt;rightFalse = 1&lt;/code&gt; (it's literally &lt;code&gt;F&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Combining with XOR's target-True formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target True = leftTrue * rightFalse + leftFalse * rightTrue
            = (1 * 1) + (0 * 0)
            = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One way to make &lt;code&gt;T ^ F&lt;/code&gt; evaluate to True, which checks out, since there's only one possible parenthesization for a two-operand expression in the first place, and it does evaluate to True.&lt;/p&gt;




&lt;h2&gt;
  
  
  MCM vs Palindrome Partitioning vs Boolean Parenthesization
&lt;/h2&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;MCM&lt;/th&gt;
&lt;th&gt;Palindrome Partitioning&lt;/th&gt;
&lt;th&gt;Boolean Parenthesization&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;Dimension array&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Boolean expression string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(i, j, isTrue)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;k&lt;/code&gt; loop&lt;/td&gt;
&lt;td&gt;&lt;code&gt;range(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;range(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;range(i+1, j, 2)&lt;/code&gt;, operators only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Left/right subproblems&lt;/td&gt;
&lt;td&gt;One value each&lt;/td&gt;
&lt;td&gt;One value each&lt;/td&gt;
&lt;td&gt;Two values each (True count, False count)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Combining step&lt;/td&gt;
&lt;td&gt;&lt;code&gt;left + right + arr[i-1]*arr[k]*arr[j]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;left + right + 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Per-operator truth table, multiply and add&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregation across k&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;+=&lt;/code&gt; (sum across all valid splits)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answer represents&lt;/td&gt;
&lt;td&gt;A minimum cost&lt;/td&gt;
&lt;td&gt;A minimum cut count&lt;/td&gt;
&lt;td&gt;A count of valid parenthesizations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern holds across all three: boundaries &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt;, a loop over valid split points &lt;code&gt;k&lt;/code&gt;, subproblems solved on both sides, and a combination step that's specific to the problem. What changes each time is what the state actually needs to track, and how the two sides get combined once you have them. MCM and Palindrome Partitioning could get away with a single value per subproblem because they were optimizing one number. Boolean Parenthesization needs both True and False counts, because the operator's truth table decides which cross-combinations of the two sides actually matter.&lt;/p&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;solve(i, j, isTrue) = number of ways s[i..j] evaluates to isTrue

Base cases:
  if i &amp;gt; j: return 0
  if i == j: return 1 if s[i] matches isTrue, else 0

Transition:
  for k in range(i+1, j, 2):   # operators only
    leftTrue, leftFalse   = solve(i, k-1, True), solve(i, k-1, False)
    rightTrue, rightFalse = solve(k+1, j, True), solve(k+1, j, False)
    combine using s[k]'s truth table, add to ans

Initial call: solve(0, n-1, True)

The change from MCM and Palindrome Partitioning:
  state grows from (i, j) to (i, j, isTrue)
  each subproblem needs both True and False counts
  combining step is a truth table per operator, not a single formula
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Boolean Parenthesization keeps the exact same partitioning skeleton as MCM and Palindrome Partitioning, boundaries, a split point, subproblems on both sides, but it's the first problem in this family where a single number per subproblem genuinely isn't enough. The moment an operator like XOR needs to know both how a side can be True and how it can be False to figure out what the combination produces, the state has to grow to carry both. That's the real lesson here: the skeleton doesn't change, but the shape of what each subproblem needs to return depends entirely on what the combining step at the top actually requires.&lt;/p&gt;

&lt;p&gt;The next chapter takes this same recursive solution and adds memoization to it, the same reasoning as before, except now the cache has to be keyed on three values instead of two, &lt;code&gt;(i, j, isTrue)&lt;/code&gt;, using either a dictionary or a structured 3D table.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Palindrome Partitioning: The MCM Skeleton With a New `tempAns`</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Wed, 07 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/palindrome-partitioning-the-mcm-skeleton-with-a-new-tempans-38a</link>
      <guid>https://dev.to/im_nishant/palindrome-partitioning-the-mcm-skeleton-with-a-new-tempans-38a</guid>
      <description>&lt;p&gt;Matrix Chain Multiplication had matrices and multiplication costs. Palindrome Partitioning has a string and cuts. The problems look nothing alike. But once you map the structure, the skeleton is identical and only &lt;code&gt;tempAns&lt;/code&gt; changes.&lt;/p&gt;




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

&lt;p&gt;Given a string, partition it so that every substring in the partition is a palindrome. Find the minimum number of cuts needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s = "NITIK"

Trivial partition:  N | I | T | I | K  → 4 cuts (valid but not minimal)
Optimal partition:  N | ITI | K        → 2 cuts

N   → palindrome ✓
ITI → palindrome ✓
K   → palindrome ✓

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

&lt;/div&gt;



&lt;p&gt;Every individual character is a palindrome, so you can always cut the string into single characters. But that's the worst case. You want to find where cutting fewer times still gives all palindromes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recognising the MCM Pattern
&lt;/h2&gt;

&lt;p&gt;From Chapter 1, the four signals are: array or string, can be partitioned, minimum answer needed, multiple partition points possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String:          NITIK
Partitions:      N | ITIK
                 NI | TIK
                 NIT | IK
                 NITI | K
Minimum answer:  yes
Multiple k:      yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All four signals are present. This is an MCM problem.&lt;/p&gt;

&lt;p&gt;The same &lt;code&gt;(i, j, k)&lt;/code&gt; structure applies. &lt;code&gt;i&lt;/code&gt; is the left boundary, &lt;code&gt;j&lt;/code&gt; is the right boundary, &lt;code&gt;k&lt;/code&gt; is the split point. &lt;code&gt;solve(i, j)&lt;/code&gt; is the minimum cuts for &lt;code&gt;s[i..j]&lt;/code&gt;.&lt;/p&gt;




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

&lt;p&gt;Two things can end the recursion early.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;i &amp;gt;= j&lt;/code&gt;:&lt;/strong&gt; A single character or an empty range. One character is always a palindrome. No cuts needed. Return 0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The entire substring &lt;code&gt;s[i..j]&lt;/code&gt; is already a palindrome:&lt;/strong&gt; No need to partition it at all. Return 0.&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;i&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isPalindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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;The &lt;code&gt;isPalindrome&lt;/code&gt; check is an extra base case that doesn't exist in MCM. It's a short-circuit: if the current range is already palindromic, don't cut it further.&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%2Fm9su80n7pnj6l3ogm4aj.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%2Fm9su80n7pnj6l3ogm4aj.png" alt=" " width="800" height="840"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The &lt;code&gt;tempAns&lt;/code&gt; Line
&lt;/h2&gt;

&lt;p&gt;After the base cases, try every &lt;code&gt;k&lt;/code&gt; from &lt;code&gt;i&lt;/code&gt; to &lt;code&gt;j-1&lt;/code&gt;. Split the string at &lt;code&gt;k&lt;/code&gt; and compute the cost of each partition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;solve(i, k)    → minimum cuts for left substring s[i..k]
solve(k+1, j)  → minimum cuts for right substring s[k+1..j]
+1             → the cut at position k that separates the two halves
&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="n"&gt;tempAns&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;i&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;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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="n"&gt;ans&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;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempAns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare with MCM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MCM:                  solve(i,k) + solve(k+1,j) + arr[i-1]*arr[k]*arr[j]
Palindrome:           solve(i,k) + solve(k+1,j) + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;+1&lt;/code&gt; replaces the multiplication cost. Everything else is the same.&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%2Fm3u2nwk9q0w9cgu1p0de.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%2Fm3u2nwk9q0w9cgu1p0de.png" alt=" " width="800" height="840"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Helper Function
&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;def&lt;/span&gt; &lt;span class="nf"&gt;isPalindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&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="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="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs in &lt;code&gt;O(n)&lt;/code&gt; per call. For each &lt;code&gt;(i, j)&lt;/code&gt; pair and each value of &lt;code&gt;k&lt;/code&gt;, &lt;code&gt;isPalindrome&lt;/code&gt; is called on the initial range once. It's not called on each subproblem — the base case check only applies to the top-level call for each &lt;code&gt;(i, j)&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Recursive 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;isPalindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;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="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;j&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;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&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="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="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&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;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;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="c1"&gt;# Base case: single char or empty range
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="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="mi"&gt;0&lt;/span&gt;

        &lt;span class="c1"&gt;# Short-circuit: no cuts needed if already palindrome
&lt;/span&gt;        &lt;span class="k"&gt;if&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;isPalindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="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;# Cut at k: left + right + 1 cut
&lt;/span&gt;            &lt;span class="n"&gt;tempAns&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;self&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;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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="n"&gt;ans&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;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempAns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;minCut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;h2&gt;
  
  
  Adding Memoization
&lt;/h2&gt;

&lt;p&gt;Same reasoning as MCM. The state is &lt;code&gt;(i, j)&lt;/code&gt;. Initialise with &lt;code&gt;-1&lt;/code&gt;. Check before computing, store after.&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;isPalindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;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="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;j&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;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&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="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="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;minCut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="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="n"&gt;n&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="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;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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="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="mi"&gt;0&lt;/span&gt;

            &lt;span class="k"&gt;if&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;isPalindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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;# Return stored answer if already computed
&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;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="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;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="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="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;# Use cached values where available
&lt;/span&gt;                &lt;span class="n"&gt;left&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="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;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;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;solve&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;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&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;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&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;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;k&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="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;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;left&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;k&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&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="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;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;right&lt;/span&gt;

                &lt;span class="n"&gt;tempAns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;
                &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempAns&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;ans&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ans&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="mi"&gt;0&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;h2&gt;
  
  
  MCM vs Palindrome Partitioning
&lt;/h2&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;MCM&lt;/th&gt;
&lt;th&gt;Palindrome Partitioning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;Dimension array&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;solve(i,j)&lt;/code&gt; means&lt;/td&gt;
&lt;td&gt;Min multiplication cost&lt;/td&gt;
&lt;td&gt;Min cuts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;k&lt;/code&gt; loop&lt;/td&gt;
&lt;td&gt;&lt;code&gt;range(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;range(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Left subproblem&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(i, k)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(i, k)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Right subproblem&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(k+1, j)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(k+1, j)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tempAns&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;left + right + arr[i-1]*arr[k]*arr[j]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;left + right + 1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extra base case&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;code&gt;isPalindrome(s, i, j)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memoised state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rows that differ: &lt;code&gt;tempAns&lt;/code&gt; and the extra palindrome base case. Every other row is identical.&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%2Fgj86jbvn4wd1br175ud3.png" alt=" " width="800" height="533"&gt;
&lt;/h2&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;solve(i, j) = minimum cuts for s[i..j]

Base cases:
  if i &amp;gt;= j: return 0
  if isPalindrome(s, i, j): return 0

Transition:
  for k in range(i, j):
    tempAns = solve(i,k) + solve(k+1,j) + 1
    ans = min(ans, tempAns)

Memoize: T[i][j], initialised to -1

Initial call: solve(0, n-1)

The only change from MCM:
  tempAns uses +1 instead of arr[i-1]*arr[k]*arr[j]
  Extra isPalindrome base case
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Palindrome Partitioning is MCM with a simpler &lt;code&gt;tempAns&lt;/code&gt;. The combining cost of splitting a string at position &lt;code&gt;k&lt;/code&gt; is just &lt;code&gt;+1&lt;/code&gt; — the single cut that divides the two halves. The &lt;code&gt;isPalindrome&lt;/code&gt; check is an optimisation that short-circuits the recursion when the current range needs no further cutting.&lt;/p&gt;

&lt;p&gt;The next chapter applies the same skeleton to Boolean Parenthesization, where the &lt;code&gt;tempAns&lt;/code&gt; becomes more involved: instead of counting cuts or multiplications, you're counting how many ways to parenthesise a boolean expression so that it evaluates to &lt;code&gt;True&lt;/code&gt;. The structure is the same. The combination logic is where things get interesting.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Coin Change II: Counting Ways With Unlimited Coins</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Wed, 07 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/coin-change-ii-counting-ways-with-unlimited-coins-2d9k</link>
      <guid>https://dev.to/im_nishant/coin-change-ii-counting-ways-with-unlimited-coins-2d9k</guid>
      <description>&lt;p&gt;Rod Cutting asked: what's the maximum profit? Coin Change II asks: how many ways can you reach a target amount? The choice structure is the same. The transition direction is the same. Two things change: &lt;code&gt;max()&lt;/code&gt; becomes &lt;code&gt;+&lt;/code&gt;, and the initialisation needs one careful adjustment.&lt;/p&gt;

&lt;p&gt;If you've been following the series, this chapter should feel like a small variation on something familiar rather than a new problem entirely.&lt;/p&gt;




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

&lt;p&gt;Given a list of coin denominations and a target amount, count the number of distinct combinations of coins that sum to that amount. Each coin can be used any number of times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coins  = [1, 2, 5]
amount = 5

Ways to make 5:
  5
  2 + 2 + 1
  2 + 1 + 1 + 1
  1 + 1 + 1 + 1 + 1

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

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;2 + 2 + 1&lt;/code&gt; and &lt;code&gt;1 + 2 + 2&lt;/code&gt; count as the same combination. Order doesn't matter here — it's combinations, not permutations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where It Sits in the Pattern
&lt;/h2&gt;

&lt;p&gt;The choice diagram is the standard TAKE / SKIP fork. And since the same coin can be used multiple times, it's Unbounded Knapsack. Since you're counting how many ways rather than finding a maximum, the operation is &lt;code&gt;+&lt;/code&gt; instead of &lt;code&gt;max()&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%2Fu4btapsvrrgmqn43or8g.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%2Fu4btapsvrrgmqn43or8g.png" alt=" " width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's how the operation changes across the problems you've seen so far:&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;Operation&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;Possible or not&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 (each item once)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rod Cutting&lt;/td&gt;
&lt;td&gt;Maximum profit&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;Coin Change II&lt;/td&gt;
&lt;td&gt;How many ways (unlimited use)&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;Coin Change II looks like Count of Subsets, but with one critical difference in the TAKE branch.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Difference From Count of Subsets
&lt;/h2&gt;

&lt;p&gt;Count of Subsets (from Chapter 4) also counted ways using &lt;code&gt;+&lt;/code&gt;. But each element could only be used once, so TAKE moved to the previous row.&lt;/p&gt;

&lt;p&gt;Coin Change II allows unlimited use, so TAKE stays on the same row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Count of Subsets (0/1):
T[i][j] = T[i-1][j - arr[i-1]]   ← previous row
         + T[i-1][j]

Coin Change II (Unbounded):
T[i][j] = T[i][j - coins[i-1]]   ← same row
         + T[i-1][j]
&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%2Fb8bbbcvh6qgzagptukf8.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%2Fb8bbbcvh6qgzagptukf8.png" alt=" " width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One index. Completely different behaviour.&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 ways to make amount j
           using the first i coins
&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 coin denominations, how many combinations make 5?&lt;/p&gt;

&lt;p&gt;Final answer: &lt;code&gt;T[n][amount]&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Initialisation
&lt;/h2&gt;

&lt;p&gt;Two boundaries to think through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No coins available (&lt;code&gt;i = 0&lt;/code&gt;):&lt;/strong&gt; You can't make any positive amount with zero coins. &lt;code&gt;T[0][j] = 0&lt;/code&gt; for all &lt;code&gt;j &amp;gt; 0&lt;/code&gt;. This is already handled by initialising the table to zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amount zero (&lt;code&gt;j = 0&lt;/code&gt;):&lt;/strong&gt; There is exactly one way to make amount zero: choose nothing. The empty combination. So &lt;code&gt;T[i][0] = 1&lt;/code&gt; for every &lt;code&gt;i&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is different from Count of Subsets in Chapter 4, where you initialised only &lt;code&gt;T[0][0] = 1&lt;/code&gt; and let the transition handle zeros in the array. Here there are no zero-valued coins to worry about (coin denominations are always positive), so initialising the entire first column to 1 is safe and correct.&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%2Fbpvjz9o6iojkn4ojvwdy.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%2Fbpvjz9o6iojkn4ojvwdy.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;When the coin fits (&lt;code&gt;coins[i-1] &amp;lt;= j&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;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="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;coins&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: same row
&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;# SKIP: previous row
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We add because we're counting. Ways from TAKE plus ways from SKIP gives total ways.&lt;/p&gt;

&lt;p&gt;When the coin doesn't fit (&lt;code&gt;coins[i-1] &amp;gt; j&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;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;# only SKIP
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Complete 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;change&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;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coins&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;coins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# T[i][j] = number of ways to make amount j
&lt;/span&gt;        &lt;span class="c1"&gt;# using the first i coins
&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;amount&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;# Amount 0 has exactly one combination: choose nothing
&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="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="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;amount&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;coins&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;# TAKE: same row (unbounded — coin can be used again)
&lt;/span&gt;                    &lt;span class="c1"&gt;# SKIP: previous row
&lt;/span&gt;                    &lt;span class="c1"&gt;# Add because we are counting ways
&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="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;coins&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="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;# Coin too large — only SKIP
&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;amount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A Dry Run
&lt;/h2&gt;

&lt;p&gt;For &lt;code&gt;coins = [1, 2, 5]&lt;/code&gt;, &lt;code&gt;amount = 5&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;After filling the table with coin 1 (row 1), every amount from 1 to 5 has exactly 1 way (all ones). After adding coin 2 (row 2), each amount gains ways that combine 2s with 1s. By the time coin 5 (row 3) is added, &lt;code&gt;T[3][5]&lt;/code&gt; captures all four combinations.&lt;/p&gt;

&lt;p&gt;The key cell to trace: &lt;code&gt;T[2][4]&lt;/code&gt; with coins [1, 2].&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coins[1] = 2, j = 4
2 &amp;lt;= 4 → fits

T[2][4] = T[2][4-2] + T[1][4]
        = T[2][2]   + T[1][4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;T[2][2]&lt;/code&gt; is at the same row, meaning: how many ways to make 2 using coins [1, 2]? That's &lt;code&gt;2&lt;/code&gt; (either &lt;code&gt;2&lt;/code&gt; or &lt;code&gt;1+1&lt;/code&gt;). &lt;code&gt;T[1][4]&lt;/code&gt; is using only coin 1 to make 4: exactly 1 way (&lt;code&gt;1+1+1+1&lt;/code&gt;). So &lt;code&gt;T[2][4] = 2 + 1 = 3&lt;/code&gt;. Three ways to make 4 using coins [1, 2]: &lt;code&gt;2+2&lt;/code&gt;, &lt;code&gt;2+1+1&lt;/code&gt;, &lt;code&gt;1+1+1+1&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%2Fcznsthvc9mu0hayh480e.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%2Fcznsthvc9mu0hayh480e.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Three Things to Keep Straight
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;+&lt;/code&gt;?&lt;/strong&gt; You're counting ways. Ways from TAKE plus ways from SKIP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why same row on TAKE?&lt;/strong&gt; Unlimited coin use. Same coin available after picking it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;T[i][0] = 1&lt;/code&gt;?&lt;/strong&gt; Amount zero has one valid combination: pick nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Revision
&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 ways to make amount j using first i coins

Initialisation:
  T[i][0] = 1 for all i     (empty combination makes 0)
  T[0][j] = 0 for all j &amp;gt; 0 (no coins, no ways)

Transition:
  if coins[i-1] &amp;lt;= j:
    T[i][j] = T[i][j-coins[i-1]] + T[i-1][j]
  else:
    T[i][j] = T[i-1][j]

Key: same row + + = Unbounded counting problem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Coin Change II is Count of Subsets made unbounded. The &lt;code&gt;+&lt;/code&gt; comes from counting. The same-row TAKE comes from unlimited use. The &lt;code&gt;T[i][0] = 1&lt;/code&gt; initialisation comes from the empty combination being a valid answer for amount zero.&lt;/p&gt;

&lt;p&gt;Chapter 10 covers Coin Change I, where the question shifts again: instead of counting how many ways, you want the minimum number of coins. The transition flips from &lt;code&gt;+&lt;/code&gt; to &lt;code&gt;min()&lt;/code&gt;, and the initialisation needs a different starting value for the same reason Count of Subsets used &lt;code&gt;None&lt;/code&gt; instead of &lt;code&gt;False&lt;/code&gt; — the default value can't be a valid answer.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>datastructures</category>
    </item>
    <item>
      <title>Rod Cutting: Unbounded Knapsack With a Different Label on the Inputs</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Tue, 06 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/rod-cutting-unbounded-knapsack-with-a-different-label-on-the-inputs-1cm2</link>
      <guid>https://dev.to/im_nishant/rod-cutting-unbounded-knapsack-with-a-different-label-on-the-inputs-1cm2</guid>
      <description>&lt;p&gt;Chapter 7 introduced Unbounded Knapsack and ended with a promise: every problem in the unbounded family inherits the same structure, just with a different question. Rod Cutting is the first of those problems, and it's a good one to start with because the mapping from Knapsack to Rod Cutting is clean and direct.&lt;/p&gt;

&lt;p&gt;Once you see the mapping, the code practically writes itself.&lt;/p&gt;




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

&lt;p&gt;You have a rod of length &lt;code&gt;n&lt;/code&gt;. For every possible piece length, there's a price you can sell it for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;price = [1, 5, 8, 9]

Length 1 → price 1
Length 2 → price 5
Length 3 → price 8
Length 4 → price 9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cut the rod into pieces in whatever combination maximises total profit.&lt;/p&gt;

&lt;p&gt;For a rod of length 4, some options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Don't cut at all:    length 4           → profit 9
Cut into two halves: 2 + 2              → profit 5 + 5 = 10
Cut three pieces:    1 + 1 + 2          → profit 1 + 1 + 5 = 7
Cut four pieces:     1 + 1 + 1 + 1      → profit 1 + 1 + 1 + 1 = 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The best option here is &lt;code&gt;2 + 2&lt;/code&gt; with profit 10.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One thing to notice:&lt;/strong&gt; some versions of this problem give you both a &lt;code&gt;length&lt;/code&gt; array and a &lt;code&gt;price&lt;/code&gt; array. Others give only &lt;code&gt;price&lt;/code&gt;, with the lengths implied as &lt;code&gt;[1, 2, 3, ..., n]&lt;/code&gt;. When the length array isn't given, just construct it as &lt;code&gt;range(1, n+1)&lt;/code&gt; where &lt;code&gt;n = len(price)&lt;/code&gt;. There's nothing more to it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Is an Unbounded Knapsack Problem
&lt;/h2&gt;

&lt;p&gt;For each available piece length, you decide: use this length or don't. That's the TAKE / SKIP structure of Knapsack.&lt;/p&gt;

&lt;p&gt;And the same piece length can be used multiple times. &lt;code&gt;2 + 2&lt;/code&gt; uses the length-2 piece twice. &lt;code&gt;1 + 1 + 1 + 1&lt;/code&gt; uses the length-1 piece four times. There's no restriction on repetition.&lt;/p&gt;

&lt;p&gt;That's Unbounded Knapsack.&lt;/p&gt;

&lt;p&gt;The variable names just change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unbounded Knapsack    →    Rod Cutting

weight                →    piece length
value                 →    price
capacity              →    rod length
maximum value         →    maximum profit
&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%2Fxdhoalcjdo9ph2oa9bna.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%2Fxdhoalcjdo9ph2oa9bna.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T[i][j] = maximum profit using the first i piece lengths
           for a rod of length j
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rows represent which piece lengths are available. Columns represent the rod length being considered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          Rod Length (j) →
          0   1   2   3   4
Length
  0       0   0   0   0   0
  1       0   ?   ?   ?   ?
  2       0   ?   ?   ?   ?
  3       0   ?   ?   ?   ?
  4       0   ?   ?   ?   ?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Base cases are the same as always: no piece lengths available means profit is 0, rod of length 0 means profit is 0. The whole table initialises to zero.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fit Condition: &lt;code&gt;if i &amp;lt;= j&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Before deciding TAKE or SKIP, you need to check whether the current piece actually fits in the current rod length.&lt;/p&gt;

&lt;p&gt;Here &lt;code&gt;i&lt;/code&gt; is the piece length and &lt;code&gt;j&lt;/code&gt; is the rod length. So the condition is:&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;i&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;# piece fits — TAKE or SKIP
&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;# piece too long — only SKIP
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not anything new. It's the same fit check as in Knapsack (&lt;code&gt;if wt[i-1] &amp;lt;= j&lt;/code&gt;). The difference is that in Rod Cutting, &lt;code&gt;i&lt;/code&gt; is both the row index and the piece length. Since lengths go &lt;code&gt;1, 2, 3, ..., n&lt;/code&gt; and the row index goes &lt;code&gt;1, 2, 3, ..., n&lt;/code&gt;, the piece length at row &lt;code&gt;i&lt;/code&gt; is simply &lt;code&gt;i&lt;/code&gt;. So &lt;code&gt;wt[i-1]&lt;/code&gt; from Knapsack becomes just &lt;code&gt;i&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%2Fuz42n8eaep615s1pnti2.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%2Fuz42n8eaep615s1pnti2.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;When the piece fits:&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="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;price&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="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;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# TAKE: same row (unbounded)
&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: previous row
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TAKE branch subtracts &lt;code&gt;i&lt;/code&gt; from &lt;code&gt;j&lt;/code&gt; (the piece length from the rod length) and stays at row &lt;code&gt;i&lt;/code&gt;. Staying at row &lt;code&gt;i&lt;/code&gt; means the same piece length is still available, so it can be picked again. That's the unbounded behaviour from Chapter 7.&lt;/p&gt;

&lt;p&gt;When the piece doesn't fit:&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="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;# only SKIP is possible
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A Small Dry Run
&lt;/h2&gt;

&lt;p&gt;For &lt;code&gt;price = [1, 5, 8, 9]&lt;/code&gt;, consider &lt;code&gt;i = 2&lt;/code&gt;, &lt;code&gt;j = 4&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;2 &amp;lt;= 4 → piece fits

T[2][4] = max(
    price[1] + T[2][4-2],
    T[1][4]
)
= max(
    5 + T[2][2],
    T[1][4]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;T[2][2]&lt;/code&gt; is at the same row &lt;code&gt;i = 2&lt;/code&gt;. That cell can itself pick another length-2 piece since &lt;code&gt;2 &amp;lt;= 2&lt;/code&gt;. So &lt;code&gt;2 + 2&lt;/code&gt; is a valid selection. The unbounded behaviour is visible here in a concrete cell computation.&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%2Foy9o496rjl0d9ghx8zmm.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%2Foy9o496rjl0d9ghx8zmm.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Complete 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;cutRod&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;price&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;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# T[i][j] = max profit using first i piece lengths
&lt;/span&gt;        &lt;span class="c1"&gt;# for a rod of length j.
&lt;/span&gt;        &lt;span class="c1"&gt;# Initialised to 0 — handles both base cases.
&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;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;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;# i is both the row index and the piece length
&lt;/span&gt;        &lt;span class="c1"&gt;# (lengths are 1-indexed: 1, 2, ..., n)
&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;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&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;# Piece fits — TAKE or SKIP
&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;price&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="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;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# TAKE: stay at row i
&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: move to row i-1
&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;# Piece too long — only SKIP
&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;# Answer: all piece lengths considered, full rod length
&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;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare this with the Unbounded Knapsack code from Chapter 7. The only structural difference is &lt;code&gt;if i &amp;lt;= j&lt;/code&gt; instead of &lt;code&gt;if wt[i-1] &amp;lt;= j&lt;/code&gt;, and &lt;code&gt;T[i][j-i]&lt;/code&gt; instead of &lt;code&gt;T[i][j-wt[i-1]]&lt;/code&gt;. Both simplifications happen because piece length at row &lt;code&gt;i&lt;/code&gt; is just &lt;code&gt;i&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Pattern Connection
&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%2F5an1cic5ky7mzn7316kj.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%2F5an1cic5ky7mzn7316kj.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;The mapping:&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;Knapsack weight    → piece length (i)
Knapsack value     → price[i-1]
Knapsack capacity  → rod length (j)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The fit condition:&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="c1"&gt;# piece length fits in rod length
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The 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="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;price&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="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;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# TAKE: same row (unbounded)
&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: previous row
&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;When length array isn't given:&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;lengths are implicitly [1, 2, 3, ..., n]
where n = len(price)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Rod Cutting is Unbounded Knapsack with renamed variables. The fit condition &lt;code&gt;i &amp;lt;= j&lt;/code&gt; is just checking whether the piece is short enough to fit in the remaining rod. The TAKE branch stays on the same row because the same piece length can be used again.&lt;/p&gt;

&lt;p&gt;Chapter 9 continues the Unbounded family with Coin Change I: instead of maximising profit, you're minimising the number of coins to reach a target amount. The choice structure stays the same. The operation changes from &lt;code&gt;max&lt;/code&gt; to &lt;code&gt;min&lt;/code&gt;, and the initialisation needs one careful adjustment because of it.&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>dp</category>
      <category>python</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Matrix Chain Multiplication: Making the Skeleton Concrete</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Tue, 06 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/matrix-chain-multiplication-making-the-skeleton-concrete-edk</link>
      <guid>https://dev.to/im_nishant/matrix-chain-multiplication-making-the-skeleton-concrete-edk</guid>
      <description>&lt;p&gt;Chapter 1 introduced the MCM skeleton. This chapter fills in the one line that was left abstract: &lt;code&gt;tempAns&lt;/code&gt;. For Matrix Chain Multiplication specifically, that line becomes the cost of multiplying two groups of matrices together after splitting the chain at position &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Everything else — the &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt; boundaries, the &lt;code&gt;k&lt;/code&gt; loop, the recursion into both halves, the &lt;code&gt;min&lt;/code&gt; aggregation — comes directly from Chapter 1.&lt;/p&gt;




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

&lt;p&gt;You're given an array of dimensions representing a chain of matrices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [40, 20, 30, 10, 30]

Matrix A1: 40 × 20   (arr[0] × arr[1])
Matrix A2: 20 × 30   (arr[1] × arr[2])
Matrix A3: 30 × 10   (arr[2] × arr[3])
Matrix A4: 10 × 30   (arr[3] × arr[4])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The matrices must be multiplied in order — you can't rearrange them. But you can choose where to put the parentheses, and different parenthesizations have different costs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(A1 × A2) × (A3 × A4)
A1 × (A2 × (A3 × A4))
(A1 × (A2 × A3)) × A4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three produce the same result matrix. But the number of scalar multiplications required is different for each. Find the parenthesization with the minimum cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Matrix Multiplication Cost Works
&lt;/h2&gt;

&lt;p&gt;To multiply a matrix of dimensions &lt;code&gt;a × b&lt;/code&gt; by a matrix of dimensions &lt;code&gt;b × c&lt;/code&gt;, you perform &lt;code&gt;a × b × c&lt;/code&gt; scalar multiplications, and the result is &lt;code&gt;a × c&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;A = 40 × 20
B = 20 × 30

A × B costs: 40 × 20 × 30 = 24,000
Result: 40 × 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This formula — &lt;code&gt;arr[i-1] × arr[k] × arr[j]&lt;/code&gt; — becomes the combining cost in the MCM recurrence.&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%2Fv6hgtfpxetb2olj9ofrp.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%2Fv6hgtfpxetb2olj9ofrp.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How the Array Represents the Matrices
&lt;/h2&gt;

&lt;p&gt;This indexing is important and trips people up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Matrix Ai has dimensions: arr[i-1] × arr[i]

A1 = arr[0] × arr[1]
A2 = arr[1] × arr[2]
A3 = arr[2] × arr[3]
A4 = arr[3] × arr[4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;arr&lt;/code&gt; has &lt;code&gt;n&lt;/code&gt; elements, there are &lt;code&gt;n-1&lt;/code&gt; matrices. For &lt;code&gt;arr = [40, 20, 30, 10, 30]&lt;/code&gt; with &lt;code&gt;n = 5&lt;/code&gt;, there are 4 matrices.&lt;/p&gt;

&lt;p&gt;This is why the initial call is &lt;code&gt;solve(1, n-1)&lt;/code&gt; not &lt;code&gt;solve(0, n-1)&lt;/code&gt;. The matrices are indexed &lt;code&gt;1&lt;/code&gt; through &lt;code&gt;n-1&lt;/code&gt;, not &lt;code&gt;0&lt;/code&gt; through &lt;code&gt;n-1&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Applying the MCM Skeleton
&lt;/h2&gt;

&lt;p&gt;From Chapter 1, the skeleton is:&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;solve&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="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="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INF&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;left&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;i&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="n"&gt;right&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;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tempAns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;cost&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;k&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="n"&gt;fill&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;
        &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempAns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Matrix Chain Multiplication, &lt;code&gt;cost(i, k, j)&lt;/code&gt; is the cost of multiplying the result of the left group with the result of the right group.&lt;/p&gt;

&lt;p&gt;After &lt;code&gt;solve(i, k)&lt;/code&gt;, the left group produces a matrix of dimensions &lt;code&gt;arr[i-1] × arr[k]&lt;/code&gt;.&lt;br&gt;
After &lt;code&gt;solve(k+1, j)&lt;/code&gt;, the right group produces a matrix of dimensions &lt;code&gt;arr[k] × arr[j]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Multiplying these two together costs: &lt;code&gt;arr[i-1] × arr[k] × arr[j]&lt;/code&gt;.&lt;/p&gt;

&lt;p&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;tempAns&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;i&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;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;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;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;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arr&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;That's the only line that needed to be determined. The rest was already in the skeleton.&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%2Fp8fkphmtwg7ylj2q5u1y.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%2Fp8fkphmtwg7ylj2q5u1y.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full Recurrence
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;solve(i, j) = minimum cost to multiply matrices Ai through Aj

Base case:
  if i &amp;gt;= j: return 0   (one matrix or less — no multiplication needed)

Transition:
  for k in range(i, j):
    tempAns = solve(i, k) + solve(k + 1, j) + arr[i-1] * arr[k] * arr[j]
    ans = min(ans, tempAns)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Recursive 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;solve&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;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="c1"&gt;# Base case: one matrix or invalid range — no cost
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="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="mi"&gt;0&lt;/span&gt;

        &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;# Try every possible split point
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="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;# Cost of left group + cost of right group + cost of combining them
&lt;/span&gt;            &lt;span class="n"&gt;tempAns&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;solve&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;self&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;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;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;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;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arr&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="n"&gt;ans&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;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempAns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;matrixMultiplication&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;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="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;solve&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works correctly but is slow. The same &lt;code&gt;(i, j)&lt;/code&gt; pair appears in multiple branches of the recursion. For example, &lt;code&gt;solve(2, 3)&lt;/code&gt; might be computed once when &lt;code&gt;k=1&lt;/code&gt; calls &lt;code&gt;solve(2, 4)&lt;/code&gt; which calls &lt;code&gt;solve(2, 3)&lt;/code&gt;, and again from a different path. Memoization fixes this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding Memoization
&lt;/h2&gt;

&lt;p&gt;The state is &lt;code&gt;(i, j)&lt;/code&gt;. The table is &lt;code&gt;(n × n)&lt;/code&gt; initialised to &lt;code&gt;-1&lt;/code&gt;. The &lt;code&gt;k&lt;/code&gt; loop is not part of the state — it's just how we explore all options for a given &lt;code&gt;(i, j)&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;matrixMultiplication&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;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;# -1 = not computed yet (0 is a valid cost, so can't use 0)
&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="n"&gt;n&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="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;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="c1"&gt;# Base case
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="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="mi"&gt;0&lt;/span&gt;

            &lt;span class="c1"&gt;# Return stored answer if already computed
&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;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="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;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="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

                &lt;span class="n"&gt;tempAns&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;i&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;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;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;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;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arr&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="n"&gt;ans&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;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempAns&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;ans&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ans&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The memoization check (&lt;code&gt;if T[i][j] != -1&lt;/code&gt;) is placed before the loop. If &lt;code&gt;(i, j)&lt;/code&gt; was already solved, return the stored answer immediately without re-running the loop.&lt;/p&gt;

&lt;p&gt;Note: &lt;code&gt;-1&lt;/code&gt; is the sentinel because &lt;code&gt;0&lt;/code&gt; is a valid answer (a single matrix has zero multiplication cost). The same reasoning applies here as it did in Coin Change I and Count of Subsets from the Knapsack series.&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%2F8zbwru8lfdr1ljlr2rv8.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%2F8zbwru8lfdr1ljlr2rv8.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  A Partial Dry Run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [40, 20, 30, 10, 30]
Call: solve(1, 4)

k = 1: A1 | A2 A3 A4
  left  = solve(1, 1) = 0
  right = solve(2, 4) = ...
  cost  = arr[0] * arr[1] * arr[4] = 40 * 20 * 30 = 24,000

k = 2: A1 A2 | A3 A4
  left  = solve(1, 2) = ...
  right = solve(3, 4) = ...
  cost  = arr[0] * arr[2] * arr[4] = 40 * 30 * 30 = 36,000

k = 3: A1 A2 A3 | A4
  left  = solve(1, 3) = ...
  right = solve(4, 4) = 0
  cost  = arr[0] * arr[3] * arr[4] = 40 * 10 * 30 = 12,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final answer is &lt;code&gt;min&lt;/code&gt; of &lt;code&gt;tempAns&lt;/code&gt; across all three values of &lt;code&gt;k&lt;/code&gt;. The recursive calls compute the internal costs. The answer for &lt;code&gt;arr = [40, 20, 30, 10, 30]&lt;/code&gt; is &lt;code&gt;26,000&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  MCM Pattern Checklist for This Problem
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What is &lt;code&gt;i&lt;/code&gt;?&lt;/td&gt;
&lt;td&gt;Left matrix index (1-based)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What is &lt;code&gt;j&lt;/code&gt;?&lt;/td&gt;
&lt;td&gt;Right matrix index (1-based)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base case?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;if i &amp;gt;= j: return 0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;k&lt;/code&gt; range?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;range(i, j)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Left subproblem?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(i, k)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Right subproblem?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;solve(k+1, j)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Combining cost?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arr[i-1] * arr[k] * arr[j]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregation?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = dimensions array, n = len(arr), n-1 matrices
Matrix Ai = arr[i-1] × arr[i]
Initial call: solve(1, n-1)

Base case: if i &amp;gt;= j: return 0

Transition:
  for k in range(i, j):
    tempAns = solve(i,k) + solve(k+1,j) + arr[i-1]*arr[k]*arr[j]
    ans = min(ans, tempAns)

Memoization: T[i][j], initialised to -1
  Why -1: 0 is a valid answer (single matrix costs 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;The MCM skeleton from Chapter 1 applied directly. The only new work was identifying that the combining cost is &lt;code&gt;arr[i-1] * arr[k] * arr[j]&lt;/code&gt; — the cost of multiplying the result of the left group with the result of the right group. Everything else was already written.&lt;/p&gt;

&lt;p&gt;The next chapter applies the same skeleton to Palindrome Partitioning: given a string, find the minimum number of cuts to partition it into palindromes. The &lt;code&gt;tempAns&lt;/code&gt; changes, the base case changes slightly, and the aggregation stays &lt;code&gt;min&lt;/code&gt;. The structure doesn't change at all.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Matrix Chain Multiplication: A New DP Pattern Built on One Question</title>
      <dc:creator>Nishant Gaurav </dc:creator>
      <pubDate>Mon, 05 Oct 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/im_nishant/matrix-chain-multiplication-a-new-dp-pattern-built-on-one-question-aim</link>
      <guid>https://dev.to/im_nishant/matrix-chain-multiplication-a-new-dp-pattern-built-on-one-question-aim</guid>
      <description>&lt;p&gt;The Knapsack pattern asks: should I take this item or skip it? The LCS pattern asked: do these two characters match? The MCM pattern asks something different: where should I split this?&lt;/p&gt;

&lt;p&gt;MCM is not one problem. It's a pattern that appears across eight or more problems: Matrix Chain Multiplication, Boolean Parenthesization, Palindrome Partitioning, Egg Dropping, and others. The problems look very different from each other. But once you see the shared structure, each new problem becomes a matter of changing one or two lines inside a familiar skeleton.&lt;/p&gt;

&lt;p&gt;This chapter is about that skeleton.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Recognise an MCM Problem
&lt;/h2&gt;

&lt;p&gt;When you see a new problem, look for these four signals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You're given an &lt;strong&gt;array or a string&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You need to &lt;strong&gt;partition or break it&lt;/strong&gt; somehow&lt;/li&gt;
&lt;li&gt;You need a &lt;strong&gt;minimum, maximum, count, or boolean&lt;/strong&gt; answer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple partition points&lt;/strong&gt; are possible and you don't know which is optimal&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The triggering question is: can I split this problem at some position &lt;code&gt;k&lt;/code&gt;, solve the two halves independently, and combine the results?&lt;/p&gt;

&lt;p&gt;If yes, MCM pattern likely applies.&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%2F1hdsmdtln8u5ug778chi.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%2F1hdsmdtln8u5ug778chi.png" alt=" " width="800" height="843"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Idea
&lt;/h2&gt;

&lt;p&gt;Every MCM problem works on a range &lt;code&gt;[i, j]&lt;/code&gt;. You pick a partition point &lt;code&gt;k&lt;/code&gt; somewhere inside that range, solve the left half &lt;code&gt;[i, k]&lt;/code&gt; and the right half &lt;code&gt;[k+1, j]&lt;/code&gt; independently, then combine the two results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i ─────────────────── j

         ↓ split at k

i ──── k │ k+1 ──── j
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since you don't know which &lt;code&gt;k&lt;/code&gt; is optimal, you try every possible &lt;code&gt;k&lt;/code&gt; in the range and keep the best result.&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%2Fifek0mt7tclflatnjwv6.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%2Fifek0mt7tclflatnjwv6.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Generic Structure
&lt;/h2&gt;

&lt;p&gt;This pseudocode is the skeleton of every MCM problem. The only thing that varies between problems is what goes inside &lt;code&gt;tempAns&lt;/code&gt; and whether you take &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, count, or a boolean.&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;solve&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;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="c1"&gt;# base case — smallest valid or first invalid input
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="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="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;# or 0, or -inf, depending on the problem
&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

        &lt;span class="n"&gt;left&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;arr&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;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# solve left partition
&lt;/span&gt;        &lt;span class="n"&gt;right&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;solve&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;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# solve right partition
&lt;/span&gt;
        &lt;span class="c1"&gt;# combine results — THIS LINE changes per problem
&lt;/span&gt;        &lt;span class="n"&gt;tempAns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;cost&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;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;ans&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;ans&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempAns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;# or max, or +=, depending on the problem
&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The structure has three parts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The boundaries &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt;:&lt;/strong&gt; Define which portion of the array you're currently solving. In the initial call, &lt;code&gt;i = 0&lt;/code&gt; and &lt;code&gt;j = n-1&lt;/code&gt; (or &lt;code&gt;n&lt;/code&gt; depending on the problem).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The partition loop &lt;code&gt;for k in range(i, j)&lt;/code&gt;:&lt;/strong&gt; Try every position where the range could be split. &lt;code&gt;k&lt;/code&gt; goes from &lt;code&gt;i&lt;/code&gt; to &lt;code&gt;j-1&lt;/code&gt;, never reaching &lt;code&gt;j&lt;/code&gt; because you need at least one element on each side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The combination &lt;code&gt;tempAns&lt;/code&gt;:&lt;/strong&gt; This is where the problems differ. What does it cost or produce to split at &lt;code&gt;k&lt;/code&gt;? How do the left and right results combine? Once you answer this for a specific problem, the rest of the skeleton is already written.&lt;/p&gt;

&lt;p&gt;[&lt;br&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%2Fyxz3ojplvbcxvewc6isd.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%2Fyxz3ojplvbcxvewc6isd.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Recursive Tree
&lt;/h2&gt;

&lt;p&gt;Every call to &lt;code&gt;solve(i, j)&lt;/code&gt; generates two calls for each value of &lt;code&gt;k&lt;/code&gt;. Each of those calls generates more calls. The structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          solve(i, j)
               |
           k = i to j-1
            /      \
           /        \
    solve(i, k)   solve(k+1, j)
         |               |
         ...             ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same subproblem — the same &lt;code&gt;(i, j)&lt;/code&gt; pair — can appear through multiple paths. That's the overlapping subproblems signal from Chapter 1 of this series. When you add memoization or convert to tabulation, each &lt;code&gt;(i, j)&lt;/code&gt; is computed only once.&lt;/p&gt;




&lt;h2&gt;
  
  
  Base Cases
&lt;/h2&gt;

&lt;p&gt;Two questions to ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the smallest valid input?&lt;/strong&gt; When &lt;code&gt;i == j&lt;/code&gt;, only one element remains. This is often the base case. What should a single element return? Usually 0, because there's nothing to partition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the first invalid input?&lt;/strong&gt; When &lt;code&gt;i &amp;gt; j&lt;/code&gt;, the pointers have crossed and there are no elements. This is always invalid. Return 0 or whatever the problem requires.&lt;/p&gt;

&lt;p&gt;Which one you use depends on the problem. Some problems only need &lt;code&gt;i == j&lt;/code&gt;. Others need to handle &lt;code&gt;i &amp;gt; j&lt;/code&gt; too. But always ask both questions when designing the base case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i ───────────── j        normal range
i === j                  one element (smallest valid)
i &amp;gt; j                    crossed pointers (invalid)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What Changes Between MCM Problems
&lt;/h2&gt;

&lt;p&gt;The skeleton is fixed. The &lt;code&gt;tempAns&lt;/code&gt; line is the problem. Here's what varies:&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;&lt;code&gt;tempAns&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Aggregation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Matrix Chain Multiplication&lt;/td&gt;
&lt;td&gt;&lt;code&gt;left + right + arr[i-1]*arr[k]*arr[j]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Palindrome Partitioning&lt;/td&gt;
&lt;td&gt;&lt;code&gt;left + right + 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boolean Parenthesization&lt;/td&gt;
&lt;td&gt;truth-table-based count&lt;/td&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Egg Dropping&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1 + max(left, right)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;min&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Min/Max expression value&lt;/td&gt;
&lt;td&gt;operator-based evaluation&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same loop. Same recursive structure. Different &lt;code&gt;tempAns&lt;/code&gt;. Different aggregation.&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%2Fbvk4m1b2109ey2yl81go.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%2Fbvk4m1b2109ey2yl81go.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solving Flow for Any MCM Problem
&lt;/h2&gt;

&lt;p&gt;When you encounter an MCM problem, go through these six steps in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identify the boundaries.&lt;/strong&gt; What is &lt;code&gt;i&lt;/code&gt;? What is &lt;code&gt;j&lt;/code&gt;? What do they represent in this problem?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find the base case.&lt;/strong&gt; When &lt;code&gt;i == j&lt;/code&gt;, what should you return? When &lt;code&gt;i &amp;gt; j&lt;/code&gt;, what should you return?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define the &lt;code&gt;k&lt;/code&gt; range.&lt;/strong&gt; Usually &lt;code&gt;k&lt;/code&gt; goes from &lt;code&gt;i&lt;/code&gt; to &lt;code&gt;j-1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the recursive partition.&lt;/strong&gt; &lt;code&gt;solve(i, k)&lt;/code&gt; and &lt;code&gt;solve(k+1, j)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculate &lt;code&gt;tempAns&lt;/code&gt;.&lt;/strong&gt; This is the problem-specific step. What does splitting at &lt;code&gt;k&lt;/code&gt; cost or produce?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply aggregation.&lt;/strong&gt; &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, or boolean — depending on what the problem is asking for.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next chapter applies this exact flow to the actual Matrix Chain Multiplication problem, where &lt;code&gt;tempAns&lt;/code&gt; is the number of scalar multiplications needed to multiply the matrices from &lt;code&gt;i&lt;/code&gt; to &lt;code&gt;j&lt;/code&gt; with the split at &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recognition signals:
  Array/string + partition + min/max/count/boolean + multiple split points

Core structure:
  solve(i, j)
    for k in range(i, j):
      left  = solve(i, k)
      right = solve(k+1, j)
      tempAns = combine(left, right)  ← changes per problem
      ans = min/max/count(ans, tempAns)
    return ans

Base cases:
  i == j → smallest valid input (usually return 0)
  i &amp;gt; j  → invalid (return 0)

What's fixed:     i, j boundaries + k loop + left/right recursion
What changes:     tempAns formula + aggregation type
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;MCM is a pattern, not a problem. The structure — range &lt;code&gt;[i, j]&lt;/code&gt;, partition at every &lt;code&gt;k&lt;/code&gt;, recurse on both halves, combine — is the same across all MCM problems. The only creative work is figuring out what &lt;code&gt;tempAns&lt;/code&gt; means for the specific problem you're solving.&lt;/p&gt;

&lt;p&gt;The next chapter applies this skeleton to Matrix Chain Multiplication specifically: given a chain of matrices, find the minimum number of scalar multiplications needed to compute their product. The &lt;code&gt;tempAns&lt;/code&gt; line becomes concrete, and the pattern produces a working solution.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>python</category>
    </item>
  </channel>
</rss>
