<script>!function(){functiont(t){document.documentElement.setAttribute("data-theme",t)}vare=function(){try{returnnewURLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{returnlocalStorage.getItem("theme")}catch(t){}}();t(null!==e?e:"light")}(),function(){try{constc=newURLSearchParams(window.location.search).entries();for(var[t,e]ofc)if(t.startsWith("docusaurus-data-")){vara=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><divid="__docusaurus"><divrole="region"aria-label="Skip to main content"><aclass="skipToContent_fXgn"href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><navaria-label="Main"class="navbar navbar--fixed-top"><divclass="navbar__inner"><divclass="navbar__items"><buttonaria-label="Toggle navigation bar"aria-expanded="false"class="navbar__toggle clean-btn"type="button"><svgwidth="30"height="30"viewBox="0 0 30 30"aria-hidden="true"><pathstroke="currentColor"stroke-linecap="round"stroke-miterlimit="10"stroke-width="2"d="M4 7h22M4 15h22M4 23h22"></path></svg></button><aclass="navbar__brand"href="/"><bclass="navbar__title text--truncate">mf</b></a><divclass="navbar__item dropdown dropdown--hoverable"><ahref="#"aria-haspopup="true"aria-expanded="false"role="button"class="navbar__link">Additional FI MU materials</a><ulclass="dropdown__menu"><li><aaria-current="page"class="dropdown__link dropdown__link--active"href="/algorithms/">Algorithms</a></li><li><aclass="dropdown__link"href="/c/">C</a></li><li><aclass="dropdown__link"href="/cpp/">C++</a></li></ul></div><aclass="navbar__item navbar__link"href="/contributions/">Contributions</a><aclass="navbar__item navbar__link"href="/talks/">Talks</a></div><divclass="navbar__items navbar__items--right"><aclass="navbar__item navbar__link"href="/blog/">Blog</a><divclass="toggle_vylO colorModeToggle_DEke"><buttonclass="clean-btn toggleButton_gllP toggleButtonDisabled_aARS"type="button"disabled=""title="Switch between dark and light mode (currently light mode)"aria-label="Switch between dark and light mode (currently light mode)"aria-live="polite"><svgviewBox="0 0 24 24"width="24"height="24"class="lightToggleIcon_pyhR"><pathfill="currentColor"d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svgviewBox="0 0 24 24"width="24"height="24"class="darkToggleIcon_wfgR"><pathfill="currentColor"d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg></button></div><divclass="navbarSearchContainer_Bca1"><buttontype="button"class="DocSearch DocSearch-Button"aria-label="Search"><spanclass="DocSearch-Button-Container"><svgwidth="20"height="20"class="DocSearch-Search-Icon"viewBox="0 0 20 20"><pathd="M14.38614.386l4.08774.0877-4.0877-4.0877c-2.
<p>If you try to think in depth about the top-down DP solution, you might notice
that the <em>core</em> of it stands on caching the calculations that have been already
done on the lower “levels” of the pyramid. Our bottom-up implementation will be
using this fact!</p>
<divclass="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><divclass="admonitionHeading_Gvgb"><spanclass="admonitionIcon_Rf37"><svgviewBox="0 0 12 16"><pathfill-rule="evenodd"d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><divclass="admonitionContent_BuS1"><p>As I have said in the <em>top-down DP</em> section, it is the easiest way to implement
DP (unless the cached function has complicated parameters, in that case it might
get messy).</p><p>Bottom-up dynamic programming can be more effective, but may be more complicated
to implement right from the beginning.</p></div></div>
<p>Let's see how we can implement it:</p>
<divclass="language-java codeBlockContainer_Ckt0 theme-code-block"style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><divclass="codeBlockContent_biex"><pretabindex="0"class="prism-code language-java codeBlock_bY9V thin-scrollbar"style="color:#393A34;background-color:#f6f8fa"><codeclass="codeBlockLines_e6Vv"><spanclass="token-line"style="color:#393A34"><spanclass="token keyword"style="color:#00009f">public</span><spanclass="token plain"></span><spanclass="token keyword"style="color:#00009f">static</span><spanclass="token plain"></span><spanclass="token keyword"style="color:#00009f">int</span><spanclass="token plain"></span><spanclass="token function"style="color:#d73a49">longestSlideDown</span><spanclass="token punctuation"style="color:#393A34">(</span><spanclass="token keyword"style="color:#00009f">int</span><spanclass="token punctuation"style="color:#393A34">[</span><spanclass="token punctuation"style="color:#393A34">]</span><spanclass="token punctuation"style="color:#393A34">[</span><spanclass="token punctuation"style="color:#393A34">]</span><spanclass="token plain"> pyramid</span><spanclass="token punctuation"style="color:#393A34">)</span><spanclass="token plain"></span><spanclass="token punctuation"style="color:#393A34">{</span><spanclass="token plain"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"></span><spanclass="token comment"style="color:#999988;font-style:italic">// In the beginning we declare new array. At this point it is easier to just</span><spanclass="token plain"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"></span><spanclass="token comment"style="color:#999988;font-style:italic">// work with the one dimension, i.e. just allocating the space for the rows.</span><spanclass="token plain"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"></span><spanclass="token keyword"style="color:#00009f">int</span><spanclass="token punctuation"style="color:#393A34">[</span><spanclass="token punctuation"style="color:#393A34">]</span><spanclass="token punctuation"style="color:#393A34">[</span><spanclass="token punctuation"style="color:#393A34">]</span><spanclass="token plain"> slideDowns </span><spanclass="token operator"style="color:#393A34">=</span><spanclass="token plain"></span><spanclass="token keyword"style="color:#00009f">new</span><spanclass="token plain"></span><spanclass="token keyword"style="color:#00009f">int</span><spanclass="token punctuation"style="color:#393A34">[</span><spanclass="token plain">pyramid</span><spanclass="token punctuation"style="color:#393A34">.</span><spanclass="token plain">length</span><spanclass="token punctuation"style="color:#393A34">]</span><spanclass="token punctuation"style="color:#393A34">[</span><spanclass="token punctuation"style="color:#393A34">]</span><spanclass="token punctuation"style="color:#393A34">;</span><spanclass="token plain"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"style="display:inline-block"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"></span><spanclass="token comment"style="color:#999988;font-style:italic">// Bottom row gets just copied, there's nothing else to do… It's the base</span><spanclass="token plain"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"></span><spanclass="token comment"style="color:#999988;font-style:italic">// case.</span><spanclass="token plain"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"> slideDowns</span><spanclass="token punctuation"style="color:#393A34">[</span><spanclass="token plain">pyramid</span><spanclass="token punctuation"style="color:#393A34">.</span><spanclass="token plain">length </span><spanclass="token operator"style="color:#393A34">-</span><spanclass="token plain"></spa
<p>I've tried to explain the code as much as possible within the comments, since it
might be more beneficial to see right next to the “offending” lines.</p>
<p>As you can see, in this approach we go from the other side<sup><ahref="#user-content-fn-1"id="user-content-fnref-1"data-footnote-ref="true"aria-describedby="footnote-label">1</a></sup>, the bottom of
the pyramid and propagate the partial results up.</p>
<divclass="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><divclass="admonitionHeading_Gvgb"><spanclass="admonitionIcon_Rf37"><svgviewBox="0 0 14 16"><pathfill-rule="evenodd"d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>How is this different from the <em>greedy</em> solution???</div><divclass="admonitionContent_BuS1"><p>If you try to compare them, you might find a very noticable difference. The
greedy approach is going from the top to the bottom without <strong>any</strong> knowledge of
what's going on below. On the other hand, bottom-up DP is going from the bottom
(<em>DUH…</em>) and <strong>propagates</strong> the partial results to the top. The propagation is
what makes sure that at the top I don't choose the best <strong>local</strong> choice, but
the best <strong>overall</strong> result I can achieve.</p></div></div>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="time-complexity">Time complexity<ahref="#time-complexity"class="hash-link"aria-label="Direct link to Time complexity"title="Direct link to Time complexity"></a></h2>
<p>Time complexity of this solution is rather simple. We allocate an array for the
rows and then for each row, we copy it and adjust the partial results. Doing
<p>Of course, this is an upper bound, since we iterate through the bottom row only
once.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="memory-complexity">Memory complexity<ahref="#memory-complexity"class="hash-link"aria-label="Direct link to Memory complexity"title="Direct link to Memory complexity"></a></h2>
<p>We're allocating an array for the pyramid <strong>again</strong> for our partial results, so
<divclass="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><divclass="admonitionHeading_Gvgb"><spanclass="admonitionIcon_Rf37"><svgviewBox="0 0 12 16"><pathfill-rule="evenodd"d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><divclass="admonitionContent_BuS1"><p>If we were writing this in C++ or Rust, we could've avoided that, but not
really.</p><p>C++ would allow us to <strong>copy</strong> the pyramid rightaway into the parameter, so we
would be able to directly change it. However it's still a copy, even though we
don't need to allocate anything ourselves. It's just implicitly done for us.</p><p>Rust is more funny in this case. If the pyramids weren't used after the call of
<code>longest_slide_down</code>, it would simply <strong>move</strong> them into the functions. If they
were used afterwards, the compiler would force you to either borrow it, or
<em>clone-and-move</em> for the function.</p><hr><p>Since we're doing it in Java, we get a reference to the <em>original</em> array and we
can't do whatever we want with it.</p></div></div>
<h1>Summary</h1>
<p>And we've finally reached the end. We have seen 4 different “solutions”<sup><ahref="#user-content-fn-2"id="user-content-fnref-2"data-footnote-ref="true"aria-describedby="footnote-label">2</a></sup> of
the same problem using different approaches. Different approaches follow the
order in which you might come up with them, each approach influences its
successor and represents the way we can enhance the existing implementation.</p>
<sectiondata-footnotes="true"class="footnotes"><h2class="anchor anchorWithStickyNavbar_LWe7 sr-only"id="footnote-label">Footnotes<ahref="#footnote-label"class="hash-link"aria-label="Direct link to Footnotes"title="Direct link to Footnotes"></a></h2>
<ol>
<liid="user-content-fn-1">
<p>definitely not an RHCP reference <!---->😉 <ahref="#user-content-fnref-1"data-footnote-backref=""aria-label="Back to reference 1"class="data-footnote-backref">↩</a></p>
</li>
<liid="user-content-fn-2">
<p>one was not correct, thus the quotes <ahref="#user-content-fnref-2"data-footnote-backref=""aria-label="Back to reference 2"class="data-footnote-backref">↩</a></p>