<?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: ShangjieZhou</title>
    <description>The latest articles on DEV Community by ShangjieZhou (@shangjiezhou).</description>
    <link>https://dev.to/shangjiezhou</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1224075%2F598e3189-f74d-4878-a043-09b298993dd3.png</url>
      <title>DEV Community: ShangjieZhou</title>
      <link>https://dev.to/shangjiezhou</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shangjiezhou"/>
    <language>en</language>
    <item>
      <title>JS: Closure</title>
      <dc:creator>ShangjieZhou</dc:creator>
      <pubDate>Mon, 06 May 2024 04:32:51 +0000</pubDate>
      <link>https://dev.to/shangjiezhou/js-closure-18n0</link>
      <guid>https://dev.to/shangjiezhou/js-closure-18n0</guid>
      <description>&lt;h2&gt;
  
  
  1. What is closure
&lt;/h2&gt;

&lt;p&gt;A combination of a function and the environment the within which that function was declared. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function makeFunc() {
  const name = "Mozilla";
  function displayName() {
    console.log(name);
  }
  return displayName;
}

const myFunc = makeFunc();
myFunc();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The closure here is the combination of function &lt;code&gt;displayName&lt;/code&gt; and the variable &lt;code&gt;name&lt;/code&gt;. Therefore, function &lt;code&gt;displayName&lt;/code&gt; remains a reference to variable &lt;code&gt;name&lt;/code&gt;, and when later &lt;code&gt;myFunc&lt;/code&gt; is invoked, it'll be be able to access the variable &lt;code&gt;name&lt;/code&gt; hence print out &lt;code&gt;Mozilla&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closures in JavaScript capture variables by reference, not by value&lt;/strong&gt;, which means if the value of the lexical environemtn variable changes, it will be reflected inside the function. For example:&lt;br&gt;
&lt;/p&gt;

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

let i = 0;
while (i &amp;lt; 3) {
  const a = () =&amp;gt; console.log(i);
  myFunctions.push(a);
  i += 1;
}

for (let f of myFunctions) {
  f();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Using closure for private methods
&lt;/h2&gt;

&lt;p&gt;We can utilise JS closure to write &lt;strong&gt;encapsulated functions and variables&lt;/strong&gt; that are inaccessable outside an object and to &lt;strong&gt;expose functions and variables&lt;/strong&gt; to outer environments, like private and public methods in Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const makeCounter = function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment() {
      changeBy(1);
    },

    value() {
      return privateCounter;
    },
  };
};

const counter = makeCounter();
console.log(counter.value()); // 0.
counter.increment();
console.log(counter.value()); // 1.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which is equivalent to the Java code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Counter {
    private int privateCounter = 0;

    private void changeBy(int val) {
        privateCounter += val;
    }

    public void increment() {
        changeBy(1);
    }

    public int value() {
        return privateCounter;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Closure within closure
&lt;/h2&gt;

&lt;p&gt;The following code will not behave as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function showHelp(help) {
  document.getElementById("help").textContent = help;
}

function setupHelp() {
  var helpText = [
    { id: "email", help: "Your email address" },
    { id: "name", help: "Your full name" },
    { id: "age", help: "Your age (you must be over 16)" },
  ];

  for (var i = 0; i &amp;lt; helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = () =&amp;gt; showHelp(item.help);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But changing the declaration of &lt;code&gt;item&lt;/code&gt; from &lt;code&gt;var&lt;/code&gt; to &lt;code&gt;const&lt;/code&gt; will work, since now in every loop a new variable is created with the updated value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for (let i = 0; i &amp;lt; helpText.length; i++) {
    const item = helpText[i];
    document.getElementById(item.id).onfocus = () =&amp;gt; {
      showHelp(item.help);
    };
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or we can keep the &lt;code&gt;var&lt;/code&gt;, but using yet another closure to capture the variable's live value within each loop by creating another inner function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function showHelp(help) {
  document.getElementById("help").textContent = help;
}

function makeHelpCallback(help) {
  return function () {
    showHelp(help);
  };
}

function setupHelp() {
  var helpText = [
    { id: "email", help: "Your email address" },
    { id: "name", help: "Your full name" },
    { id: "age", help: "Your age (you must be over 16)" },
  ];

  for (var i = 0; i &amp;lt; helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
    </item>
    <item>
      <title>The 0/1 Knap-sack Problem</title>
      <dc:creator>ShangjieZhou</dc:creator>
      <pubDate>Thu, 29 Feb 2024 05:53:50 +0000</pubDate>
      <link>https://dev.to/shangjiezhou/the-01-knap-sack-problem-7ee</link>
      <guid>https://dev.to/shangjiezhou/the-01-knap-sack-problem-7ee</guid>
      <description>&lt;h2&gt;
  
  
  1. Overall Idea
&lt;/h2&gt;

&lt;p&gt;The sub-problem:&lt;br&gt;
If we're given the optimal solution for &lt;code&gt;item[0]...item[i]&lt;/code&gt; with a bag of size &lt;code&gt;n&lt;/code&gt;, when facing &lt;code&gt;item[i+1]&lt;/code&gt;, we only have to think about two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If we must add &lt;code&gt;item[i+1]&lt;/code&gt; of &lt;code&gt;weight[i+1]&lt;/code&gt; and &lt;code&gt;value[i+1]&lt;/code&gt;, then the total value is:
&lt;strong&gt;(optimal solution for &lt;code&gt;item[0]...item[i]&lt;/code&gt; with a bag of size &lt;code&gt;n-weight[i+1]&lt;/code&gt;)&lt;/strong&gt; + &lt;strong&gt;(&lt;code&gt;value[i+1]&lt;/code&gt;)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;See if not including &lt;code&gt;item[i+1]&lt;/code&gt; yields a higher value, in other words, check &lt;strong&gt;optimal solution for &lt;code&gt;item[0]...item[i]&lt;/code&gt; with a bag of size &lt;code&gt;n&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Therefore, it's clear to see that we define the sub-problem as a two-dimension memoization, where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dp[i][j]&lt;/code&gt; = the optimal solution for the first &lt;code&gt;i&lt;/code&gt; items with a bag of size &lt;code&gt;j&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dp[i][j+1]&lt;/code&gt; = the higher of &lt;code&gt;dp[i-1][j+1]&lt;/code&gt; and &lt;code&gt;dp[i-1][j-weight[i]] + value[i]&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  2. The Classic Approach
&lt;/h2&gt;

&lt;p&gt;We first init a 2D array, where &lt;code&gt;row[i] = item[i]&lt;/code&gt; and &lt;code&gt;col[i] = bag of size i&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Populate the base cases of "empty bag with all items" and "first item with bag of all sizes"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dp = int[item_len][bag_size + 1]
for i in range(0, item_len): 
    dp[i][0] = 0
for i in range(0, bag_size + 1): 
    dp[0][i] = values[0] if i &amp;gt;= weights[0] else 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Applying the sub-problem induction logic, note that we need to start from the second row and second column in each row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in range(1, item_len):
    for j in range(1, bag_size + 1):
        if weights[i] &amp;gt; j: # item too big
            dp[i][j] = dp[i - 1][j]
        else:
            add_item = dp[i - 1][j - weights[i]] + values[i]
            skip_item = dp[i - 1][j]
            dp[i][j] = max(add_item, skip_item)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Space Complexity: &lt;code&gt;O(bag_size * item_len)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Time Complexity: &lt;code&gt;O(bag_size * item_len)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Space-Optimised Approach
&lt;/h2&gt;

&lt;p&gt;In the previous approach, we used a 2D array to store the computed results in our DP but we can observe one thing that to compute the result for &lt;code&gt;item[i]&lt;/code&gt; we just need the results for &lt;code&gt;item[i-1]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Therefore, we can reduce the size of our DP to 1D by just storing the results on different bag sizes for the previous element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dp = [0] * (bag_size + 1)
for i in range(0, bag_size + 1):
    if weights[0] &amp;lt;= i: dp[i] = values[0]

for i in range(1, size):
    for j in range(1, bag_size + 1):
        if weights[i] &amp;gt; j:
            dp[j] = prev[j]
        else:
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i])

print(memo[bag_size])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Space Complexity: &lt;code&gt;O(bag_size)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Time Complexity: &lt;code&gt;O(bag_size * item_len)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. The "Forward-Thinking" Approach (Intuitive)
&lt;/h2&gt;

&lt;p&gt;In all previous approaches, we think in the way of "if I add the current item(of weight &lt;code&gt;w&lt;/code&gt;) into my bag(of size &lt;code&gt;n&lt;/code&gt;), I must trace back to find the optimal solution for bag size of &lt;code&gt;n-w&lt;/code&gt; in order to calculate the new total value".&lt;/p&gt;

&lt;p&gt;This is a form of back-tracking, using "backward thinking".&lt;/p&gt;

&lt;p&gt;Another way to think about this could be "if I add the current item(of weight &lt;code&gt;w&lt;/code&gt;) into my bag(of size &lt;code&gt;n&lt;/code&gt;), it will produce a new solution(not necessarily optimal) for bag size of &lt;code&gt;n+w&lt;/code&gt;, given the optimal solution for bag size of &lt;code&gt;n&lt;/code&gt;"&lt;/p&gt;

&lt;p&gt;This is more like "forward-thinking", which is actually just the same logic, but we will now use a hashmap instead of an array to store the intermediate results, and each key-value pair of the hashmap now has a slightly different meaning than the array approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;each key of the hashmap is an integer in range &lt;code&gt;[0, bag_size]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;each value of key &lt;code&gt;n&lt;/code&gt; marks the optimal solution for a bag that has items with total size of exactly &lt;code&gt;n&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# an empty bag has maximum value of 0
dp = {0: 0}

for i in range(0, item_len):
    prev = dict(dp)
    for size in prev:
        new_size = size + weights[i]
        if new_size &amp;lt;= bag_size:
            if new_size in prev:
                dp[new_size] = max(prev[new_size], prev[size] + values[i])
            else:
                dp[new_size] = prev[size] + values[i]

print(max(dp.values()))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we cannot simply return &lt;code&gt;dp[bag_size]&lt;/code&gt; as the final solution with this approach, since:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;There might not be a combination of items that gives a total weight of exactly &lt;code&gt;bag_size&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The optimal solution might come from a key that is less than &lt;code&gt;bag_size&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Space Complexity: &lt;code&gt;O(bag_size)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Time Complexity: &lt;code&gt;O(bag_size * item_len)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. The Target Sum Problem
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Given an array of positive integers &lt;code&gt;nums&lt;/code&gt;, and an integer &lt;code&gt;target&lt;/code&gt;, return &lt;code&gt;True&lt;/code&gt; if there is a subset of &lt;code&gt;nums&lt;/code&gt; such that the sum of its elements is equal to &lt;code&gt;target&lt;/code&gt;, return &lt;code&gt;False&lt;/code&gt; otherwise. &lt;br&gt;
Example: &lt;code&gt;nums = [1,2,3,3]&lt;/code&gt;, &lt;code&gt;target = 7&lt;/code&gt; will return &lt;code&gt;True&lt;/code&gt; (&lt;code&gt;[1,3,3]&lt;/code&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We could solve this problem with the classic knap-sack approach, where &lt;code&gt;target&lt;/code&gt; is the bag size, and each number &lt;code&gt;x&lt;/code&gt; in &lt;code&gt;nums&lt;/code&gt; can be regarded as an item of weight &lt;code&gt;x&lt;/code&gt; and value &lt;code&gt;x&lt;/code&gt;, then at the end we simply return &lt;code&gt;dp[target] == target&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;dp = [False] * (target + 1)
dp[0] = True

for num in nums:
    for i in range(num, target + 1):
        dp[i] = dp[i] or dp[i - num]

return dp[target_sum]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, it's also interesting to follow the "forward thinking" approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we loop through each number in &lt;code&gt;nums&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;at each number &lt;code&gt;n&lt;/code&gt;, we keep a list of all possible sums so far &lt;code&gt;sums&lt;/code&gt;, and add in the new sums produced by &lt;code&gt;n+sums[i]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example using hashmap&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;possible_sums = {0: True}

for n in nums:
    prev = dict(possible_sums)
    for s in prev:
        if s + n &amp;lt;= target: possible_sums[s + n] = True

return (target in possible_sums)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the only difference here is that we change the order in which to find the solution, from "looking back" to "looking forward". However, by turning it to "forward thinking", it now feels more linear and straight forward.&lt;/p&gt;

&lt;p&gt;I often find it useful to take the "forward-thinking" approach for many other knapsack-like problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog, I compared the classic approach, space-optimised approach and forward-thinking approach of solving the 0/1 knap-sack problem, as well as showing how the forward-thinking approach could give us another subtle way to view and understand the knap-sack problem, by solving another similar problem "Target Sum".&lt;/p&gt;

&lt;p&gt;All of these approaches are essentially the same strategy using dynamic programming, but I hope that by giving a side-by-side comparison here, it can help us build a more thorough understanding of the knapsack problem and the idea behind dynamic programming.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Leetcode Notes</title>
      <dc:creator>ShangjieZhou</dc:creator>
      <pubDate>Sat, 02 Dec 2023 06:29:37 +0000</pubDate>
      <link>https://dev.to/shangjiezhou/leetcode-notes-3jn8</link>
      <guid>https://dev.to/shangjiezhou/leetcode-notes-3jn8</guid>
      <description>&lt;p&gt;&lt;a href="https://leetcode.com/problems/all-paths-from-source-to-target/description/"&gt;797. All Paths From Source to Target&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use recursion to find all possible paths from the source node to the destination node. &lt;br&gt;
A few important things to think about when writing recursion algorithms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to define the recursion function: what to accept as input, what to return (maybe no return value, but instead modifying global variables at each recursion)?&lt;/li&gt;
&lt;li&gt;The scope of each recursion: what's the responsibility at each recursion? For example, do we append the child nodes at this recursion, or leave it to the next recursion? i.e. only append the current node at this recursion, or only append the child nodes? 
Note that this will affect how we define base case as well.&lt;/li&gt;
&lt;li&gt;The base case/end of recursion: sometimes the base case is implicitly executed when looking at the next step in the current recusion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/number-of-islands/description/"&gt;200. Number of Islands&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Combine 2D array traversal + BFS to determine the number of isolated graphs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When approaching a problem, don't restrict yourself to only one algorithm. Like in this case, it's a combination of array traversal and BFS.&lt;/li&gt;
&lt;li&gt;Try to think without specific algorithm technique first, but to first come up with a high level strategy, to make some observations, then think of the specific realisation of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/max-area-of-island/description/"&gt;695. Max Area of Island&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Very similar to the problem above. &lt;/p&gt;

&lt;p&gt;Again, one crucial thing when doing recursion is to be very clear about what each recursion does. In this example, there's 2 alternatives:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the area of child nodes each recursion&lt;/li&gt;
&lt;li&gt;Add the area of the current node&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/reverse-words-in-a-string/description/"&gt;151. Reverse Words in a String&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The take away message is to utilise the idea of "global reverse" + "partial reverse", which is useful for many in-place string manipulation problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Greedy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The idea is "each step we will not miss the global optimal solution"&lt;/li&gt;
&lt;li&gt;Validity often supported by "proof by contradiction"&lt;/li&gt;
&lt;li&gt;When to use? It's by intuition and trials and errors really...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/gas-station/description/"&gt;134. Gas Station&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;-- make close observations when planning each greedy step.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A typical greedy solution would use 2 pointer method: both start from index 0, &lt;code&gt;curr&lt;/code&gt; goes clockwise while &lt;code&gt;base&lt;/code&gt; goes anti-clockwise. Whenever the currentSum is &amp;lt; 0, meaning out of gas, we move &lt;code&gt;base&lt;/code&gt; anti-clockwise by 1 index. The loop terminates when the 2 pointers intersect (together complete a whole circle)&lt;/p&gt;

&lt;p&gt;The key observation here is, &lt;strong&gt;whenever the currSum between &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;i + n&lt;/code&gt; is negative, any base starting between &lt;code&gt;[i, i + n]&lt;/code&gt; would also result in negative currSum, but position &lt;code&gt;i - 1&lt;/code&gt; might give us extra gas so it's worth trying; so instead of moving base forward, we need to move it backward&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/maximum-subarray/description/"&gt;53. Maximum Subarray&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Greedy is harder than DP for this problem.&lt;/p&gt;

&lt;p&gt;Again, the key here is to make close observation, then use two-pointer strategy and increment each pointer correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/jump-game/description/"&gt;55. Jump Game&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From each position &lt;code&gt;i&lt;/code&gt; we have &lt;code&gt;nums[i]&lt;/code&gt; many ways to jump, which seems to result in too many possibilities at the first glance. However, the observation is that no matter how many ways we could reach position &lt;code&gt;i&lt;/code&gt;, what we can reach from this position onwards is the same.&lt;/p&gt;

&lt;p&gt;Therefore, multiple jump capacities provided at different positions will always flatten to one single jump capacity. In other words, each following position will always overwrite the current jump capacity, so we only need to keep track of how far we can jump at each position, starting from &lt;code&gt;i = 0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Another way of thinking is to start from the back and travel backwards, we look for the first position &lt;code&gt;x&lt;/code&gt; that can jump to the last element (i.e. &lt;code&gt;nums[x]&lt;/code&gt; &amp;gt;= distance from x to the last element), then update this position as our destination (since if we could reach x, we could reach the last element), look for position that can reach x, so on and so forth until we travel back to the first element.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Programming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Find out the sub-problems: &lt;code&gt;dp[i]&lt;/code&gt; (sometimes it could be multi-dimensional)&lt;/li&gt;
&lt;li&gt;Find out the next-step-logic: &lt;code&gt;dp[i + 1] = ?&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Find out the base cases to start with: &lt;code&gt;dp[0], dp[1], etc&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/last-stone-weight-ii/description/"&gt;1049. Last Stone Weight II&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;-- Use mathmatical model to simplifiy the problem&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first, the problem of recursively pairing the stones and getting resultant stones to pair again seems complicated, but after putting it into an equation everything gets very clear:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;say the array is &lt;code&gt;[a,b,c,d,e]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;say we smash them this way &lt;code&gt;result = (a-b)-c-(d-e)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;rearrange the equation we get &lt;code&gt;result = (a+e)-(b+c+d)&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Therefore, the observation is that ultimately we just want to find a subset of the array such that &lt;code&gt;sum(subset_array)&lt;/code&gt; is closest to &lt;code&gt;sum(original_array) / 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The power of mathmatical modelling can be seen in other problems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/3sum/description/"&gt;15. 3Sum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/4sum-ii/description/"&gt;454. 4Sum II&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
