<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>dp &#8211; Huahua&#8217;s Tech Road</title>
	<atom:link href="https://zxi.mytechroad.com/blog/tag/dp/feed/" rel="self" type="application/rss+xml" />
	<link>https://zxi.mytechroad.com/blog</link>
	<description></description>
	<lastBuildDate>Thu, 10 Apr 2025 15:01:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.4</generator>

<image>
	<url>https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/cropped-photo-32x32.jpg</url>
	<title>dp &#8211; Huahua&#8217;s Tech Road</title>
	<link>https://zxi.mytechroad.com/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>花花酱 LeetCode 650. 2 Keys Keyboard</title>
		<link>https://zxi.mytechroad.com/blog/searching/leetcode-650-2-keys-keyboard/</link>
					<comments>https://zxi.mytechroad.com/blog/searching/leetcode-650-2-keys-keyboard/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 10 Apr 2025 14:44:47 +0000</pubDate>
				<category><![CDATA[Search]]></category>
		<category><![CDATA[BFS]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[search]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10307</guid>

					<description><![CDATA[这道题目还是可以的。每个阶段有两种选择，求最短的决策次数。有好多种不同的做法，我们一个一个来。 方法1: BFS 把问题看成求无权重图中的最短路径，BFS可以找到最优解。 我们的节点有两个状态，当前的长度，剪贴板（上次复制后）的长度。长度超过n一定无解，所以我们的状态最多只有n2种，每个状态最多拓展2个新的节点。 时间复杂度：O(n2)空间复杂度：O(n2) [crayon-69b13a1e9faa0586709666/]]]></description>
										<content:encoded><![CDATA[
<p>这道题目还是可以的。每个阶段有两种选择，求最短的决策次数。有好多种不同的做法，我们一个一个来。</p>



<p>方法1: BFS<br><br>把问题看成求无权重图中的最短路径，BFS可以找到最优解。</p>



<p>我们的节点有两个状态，当前的长度，剪贴板（上次复制后）的长度。<br>长度超过n一定无解，所以我们的状态最多只有n<sup>2</sup>种，每个状态最多拓展2个新的节点。</p>



<figure class="wp-block-image size-full"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/04/2-keys.png"><img fetchpriority="high" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/04/2-keys.png" alt="" class="wp-image-10312" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/04/2-keys.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/04/2-keys-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/04/2-keys-768x432.png 768w" sizes="(max-width: 960px) 100vw, 960px" /></a></figure>



<p>时间复杂度：O(n<sup>2</sup>)<br>空间复杂度：O(n<sup>2</sup>)</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
  int minSteps(int n) {
    vector&lt;vector&lt;bool&gt;&gt; seen(n + 1, vector&lt;bool&gt;(n + 1));
    queue&lt;pair&lt;int, int&gt;&gt; q;

    auto expand = [&amp;](int len, int clip) {
      if (len &gt; n || len &gt; n || seen[len][clip]) return;
      q.emplace(len, clip);
      seen[len][clip] = true;
    };

    int steps = 0;
    expand(1, 0); // init state.
    while (!q.empty()) {
      int size = q.size();
      while (size--) {
        auto [len, clip] = q.front(); q.pop();
        if (len == n) return steps;
        expand(len, len); // copy.
        expand(len + clip, clip); // paste.
      }
      ++steps;
    }
    return -1;
  }
};</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/searching/leetcode-650-2-keys-keyboard/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 646. Maximum Length of Pair Chain</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-646-maximum-length-of-pair-chain/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-646-maximum-length-of-pair-chain/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Thu, 10 Apr 2025 05:25:42 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[Greedy]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[greedy]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[proof]]></category>
		<category><![CDATA[subset]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10301</guid>

					<description><![CDATA[这题我选DP，因为不需要证明，直接干就行了。 方法1: DP 首先还是需要对pairs的right进行排序。一方面是为了方便chaining，另一方面是可以去重。 然后定义 dp[i] := 以pairs[i]作为结尾，最长的序列的长度。 状态转移：dp[i] = max(dp[j] + 1) where pairs[i].left > pairs[j].right and 0 &#60; j &#60; i. 解释：对于pairs[i]，找一个最优的pairs[j]，满足pairs[i].left >&#8230;]]></description>
										<content:encoded><![CDATA[
<p>这题我选DP，因为不需要证明，直接干就行了。</p>



<p>方法1: DP</p>



<p>首先还是需要对pairs的right进行排序。一方面是为了方便chaining，另一方面是可以去重。</p>



<p>然后定义 dp[i] := 以pairs[i]作为结尾，最长的序列的长度。<br><br>状态转移：dp[i] = max(dp[j] + 1) where pairs[i].left > pairs[j].right and 0 &lt; j &lt; i.</p>



<p>解释：对于pairs[i]，找一个最优的pairs[j]，满足pairs[i].left > pairs[j].right，这样我就可以把pairs[i]追加到以pairs[j]结尾的最长序列后面了，长度+1。</p>



<p>边检条件：dp[0:n] = 1，每个pair以自己作为序列的最后元素，长度为1。</p>



<p>时间复杂度：O(n<sup>2</sup>)<br>空间复杂度：O(n)</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
  int findLongestChain(vector&lt;vector&lt;int&gt;&gt;&amp; pairs) {
    sort(begin(pairs), end(pairs), [](const auto&amp; p1, const auto&amp; p2){
      return p1[1] &lt; p2[1];
    });

    const int n = pairs.size();

    vector&lt;int&gt; dp(n, 1);
    for (int i = 0; i &lt; n; ++i)
      for (int j = 0; j &lt; i; ++j)
        if (pairs[i][0] &gt; pairs[j][1])
          dp[i] = max(dp[i], dp[j] + 1);

    return *max_element(begin(dp), end(dp));
  }
};</pre>



<p>方法2: 贪心</p>



<p>和DP一样，对数据进行排序。</p>



<p>每当我看到 cur.left > prev.right，那么就直接把cur接在prev后面。我们需要证明这么做是最优的，而不是跳过它选后面的元素。<br><br>Case 0: cur已经是最后一个元素了，跳过就不是最优解了。<br><br>假设cur后面有next, 因为已经排序过了，我们可以得知 next.right >= cur.right。<br><br>Case 1: next.right == cur.right。这时候选cur和选next对后面的决策来说是一样的，但由于Case 0的存在，我必须选cur。<br><br>Case 2: next.right > cur.right。不管left的情况怎么样，由于right更小，这时候选择cur一定是优于next。</p>



<p>综上所述，看到有元素可以连接起来就贪心的选它就对了。</p>



<p>时间复杂度：O(nlogn)<br>空间复杂度：O(1)</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
  int findLongestChain(vector&lt;vector&lt;int&gt;&gt;&amp; pairs) {
    sort(begin(pairs), end(pairs), [](const auto&amp; p1, const auto&amp; p2){
      return p1[1] &lt; p2[1];
    });

    int right = INT_MIN;
    int ans = 0;
    for (const auto&amp; p : pairs)
      if (p[0] &gt; right) {
        right = p[1];
        ++ans;
      }
    return ans;
  }
};</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-646-maximum-length-of-pair-chain/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 514. Freedom Trail</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-514-freedom-trail/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-514-freedom-trail/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 07 Apr 2025 02:11:53 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[head]]></category>
		<category><![CDATA[ring]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10292</guid>

					<description><![CDATA[一眼DP，看数据规模标程应该是O(1003)。 阶段肯定就是吟唱完一个字符，状态和哪个字符在12:00点有关。 所以我们定义 dp[i][j] := 吟唱完keys[0~i]后，rings[j]停在12:00点所需要的最少步数。 转移方程：dp[i][j] = min(dp[i-1][k] + steps(k, j) + 1) if keys[i] == rings[j] else +inf. 第i-1字符吟唱完ring停留在k，第i个字符吟唱完ring停留在j (rings[j] 必须和 keys[i] 相同)，steps(k,&#8230;]]></description>
										<content:encoded><![CDATA[
<p>一眼DP，看数据规模标程应该是O(100<sup>3</sup>)。</p>



<p>阶段肯定就是吟唱完一个字符，状态和哪个字符在12:00点有关。</p>



<p>所以我们定义 dp[i][j] := 吟唱完keys[0~i]后，rings[j]停在12:00点所需要的最少步数。</p>



<p>转移方程：dp[i][j] = min(dp[i-1][k] + steps(k, j) + 1)  if keys[i] == rings[j] else +inf.</p>



<p>第i-1字符吟唱完ring停留在k，第i个字符吟唱完ring停留在j (rings[j] 必须和 keys[i] 相同)，steps(k, j)表示ring从k转到j所需要的最少步数，最后还要+1，表示吟唱当前字符所需要的额外步骤。</p>



<p>边界条件：对于第0个字符，ring一开始停留在第0个字符，最小步数就是1 + steps(0, key[0])。</p>



<p>时间复杂度：O(mn<sup>2</sup>)<br>空间复杂度：O(mn) 可以降维到 O(n)</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
  int findRotateSteps(string ring, string key) {
    const int n = ring.size();
    const int m = key.size();
    auto steps = [n](int i, int j) {
      return min(abs(i - j), n - abs(i - j));
    };
    // dp[i][j] min steps to spell key[0~i] and ring[j] is at 12:00.
    vector&lt;vector&lt;int&gt;&gt; dp(m, vector&lt;int&gt;(n, INT_MAX/2));
    for (int i = 0; i &lt; m; ++i)
      for (int j = 0; j &lt; n; ++j) {
        if (ring[j] != key[i]) continue;
        for (int k = 0; k &lt; n; ++k)
          dp[i][j] = min(dp[i][j], 1 + (i == 0 ? steps(0, j) : (dp[i - 1][k] + steps(j, k))));
      }
    return *min_element(begin(dp.back()), end(dp.back()));
  }
};</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-514-freedom-trail/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 403. Frog Jump</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-403-frog-jump/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-403-frog-jump/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 06 Apr 2025 04:11:01 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[jump]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10275</guid>

					<description><![CDATA[肯定是用DP，但我自己想了一个奇怪的方法，勉强过了&#8230; 使用dp[i] = {steps}，表示可以达到stones[i]的最后一跳的unit的集合。dp[0] = {0}dp[1] = {1} if stones[1] = 1 else {}然后对于stones[i]，枚举所有step &#8211; 1, step, step + 1三种情况，看看是否可以跳到新的石头上面（使用一个hashtable判断），如果可以的吧，把跳的unit存到dp[j]中。相当于推了。需要使用hashset去重，不然会超时。 时间复杂度：O(n2)空间复杂度：O(n2) [crayon-69b13a1ea0c9d467640466/] &#8220;优化&#8221;：由于每次只能k-1,k,k+1steps，所以最大的units和n是线性关系，达到stones[i]最多跳i+1个units。可以用二维数组dp[j][k] := 是否可以通过k步跳到stones[j].dp[j][k]&#8230;]]></description>
										<content:encoded><![CDATA[
<p>肯定是用DP，但我自己想了一个奇怪的方法，勉强过了&#8230;</p>



<p>使用dp[i] = {steps}，表示可以达到stones[i]的最后一跳的unit的集合。<br>dp[0] = {0}<br>dp[1] = {1} if stones[1] = 1 else {}<br>然后对于stones[i]，枚举所有step &#8211; 1, step, step + 1三种情况，看看是否可以跳到新的石头上面（使用一个hashtable判断），如果可以的吧，把跳的unit存到dp[j]中。相当于推了。<br>需要使用hashset去重，不然会超时。</p>



<p>时间复杂度：O(n<sup>2</sup>)<br>空间复杂度：O(n<sup>2</sup>)</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
  bool canCross(vector&lt;int&gt;&amp; stones) {
    if (stones[1] != 1) return false;
    unordered_map&lt;int, int&gt; m;
    const int n = stones.size();
    for (int i = 0; i &lt; n; ++i)
      m[stones[i]] = i;
    // dp[i] = {steps} steps to jump to stone[i].
    vector&lt;unordered_set&lt;int&gt;&gt; dp(n);
    dp[0] = {0};
    dp[1] = {1};
    for (int i = 2; i &lt; n; ++i) {
      for (int last : dp[i - 1]) {
        for (int cur = last - 1; cur &lt;= last + 1; cur++) {
          if (cur &lt; 1) continue;
          const int t = stones[i - 1] + cur;
          auto it = m.find(t);
          if (it != end(m)) dp[it-&gt;second].insert(cur);
        }
      }
    }
    return !dp.back().empty();
  }
};</pre>



<p>&#8220;优化&#8221;：由于每次只能k-1,k,k+1steps，所以最大的units和n是线性关系，达到stones[i]最多跳i+1个units。<br>可以用二维数组dp[j][k] := 是否可以通过k步跳到stones[j].<br>dp[j][k] = dp[i][k-1] || dp[i][k] || dp[i][k+1], k = stones[j] &#8211; stones[i]. 即从stones[i]跳到stones[j]，并且要求跳到stones[i]的可能步数中存在k-1,k,k+1。<br>时间复杂度和空间复杂度是一样的。</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
  bool canCross(vector&lt;int&gt;&amp; stones) {
    const int n = stones.size();
    vector&lt;vector&lt;bool&gt;&gt; dp(n, vector&lt;bool&gt;(n + 1));
    dp[0][0] = true;
    for (int i = 1; i &lt; n; ++i)
      for (int j = 0; j &lt; i; ++j) {
        const int d = stones[i] - stones[j];
        if (d &gt;= n) continue; // undefined range.
        dp[i][d] = dp[i][d] || (dp[j][d - 1] || dp[j][d] || dp[j][d + 1]);
      }
    return any_of(begin(dp.back()), end(dp.back()), [](bool x) { return x; });
  }
};</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-403-frog-jump/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 368. Largest Divisible Subset</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-368-largest-divisible-subset/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-368-largest-divisible-subset/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 05 Apr 2025 02:17:49 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[sort]]></category>
		<category><![CDATA[subset]]></category>
		<category><![CDATA[unique]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10266</guid>

					<description><![CDATA[也算是一道比较经典的DP题了，需要找到一个最大的子集，使得其中元素两两的余数为0。 我们假设有一个集合为{a1, a2, a3, &#8230;, an}, {a1 &#60; a2 &#60; &#8230; &#60; an) 如果 a2 % a1 = 0, a3 % a2 == 0, 那么a3&#8230;]]></description>
										<content:encoded><![CDATA[
<p>也算是一道比较经典的DP题了，需要找到一个最大的子集，使得其中元素两两的余数为0。</p>



<p>我们假设有一个集合为{a1, a2, a3, &#8230;, an}, {a1 &lt; a2 &lt; &#8230; &lt; an)</p>



<p>如果 a2 % a1 = 0,  a3 % a2 == 0, 那么a3 % a1 一定也等于0。也就是说a2是a1的倍数，a3是a2的倍数，那么a3一定也是a1的倍数。所以我们并不需要测试任意两个元素之间的余数为0，我们只需要检测a[i]是否为a[i-1]的倍数即可，如果成立，则可以确保a[i]也是a[i-2], a[i-3], &#8230; a[1]的倍数。这样就可以大大降低问题的复杂度。</p>



<p>接下来就需要dp就发挥威力了。我们将原数组排序，用dp[i]来表示以a[i]结尾（集合中的最大值），能够构建的子集的最大长度。</p>



<p>转移方程：dp[j] = max(dp[j], dp[i] + 1) if nums[j] % nums[i] = 0.</p>



<p>这表示，如果nums[j] 是 nums[i]的倍数，那么我们可以把nums[j]加入以nums[i]结尾的最大子集中，构建一个新的最大子集，长度+1。当然对于j，可能有好多个满足条件的i，我们需要找一个最大的。</p>



<p>举个例子：<br>nums = {2, 3, 4, 12}<br>以3结尾的最大子集{3}，长度为1。由于12%3==0，那么我们可以把12追加到{3} 中，构成{3,12}。<br>以4结尾的最大子集是{2,4}，长度为2。由于12%4==0，那么我们可以把12追加到{2,4} 中，构成{2,4,12} 。得到最优解。</p>



<p>这样我们只需要双重循环，枚举i，再枚举j (0 &lt;= i &lt; j)。时间复杂度：O(n^2)。空间复杂度：O(n)。</p>



<p>最后需要输出一个最大子集，如果不记录递推过程，则需要稍微判断一下。</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
  vector&lt;int&gt; largestDivisibleSubset(vector&lt;int&gt;&amp; nums) {
    const int n = nums.size();
    sort(begin(nums), end(nums));
    // dp[i] = max size of subset ends with nums[i]
    vector&lt;int&gt; dp(n);
    for (int i = 0; i &lt; n; ++i)
      for (int j = i + 1; j &lt; n; ++j)
        if (nums[j] % nums[i] == 0)
          dp[j] = max(dp[j], dp[i] + 1);
    int s = *max_element(begin(dp), end(dp));
    vector&lt;int&gt; ans;
    for (int i = n - 1; i &gt;= 0; --i) {
      if (dp[i] == s &amp;&amp; (ans.empty() || ans.back() % nums[i] == 0)) {
        ans.push_back(nums[i]);
        --s;
      }
    }
    return ans;
  }
};</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-368-largest-divisible-subset/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 3489. Zero Array Transformation IV</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-3489-zero-array-transformation-iv/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-3489-zero-array-transformation-iv/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 16 Mar 2025 14:23:47 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[leetcode]]></category>
		<category><![CDATA[medium]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10211</guid>

					<description><![CDATA[一道不错的DP题目！ 首先看到每次可以取任意一个nums[l] ~ nums[r]的子集 不能用贪心（无法找到全局最优解） 不能用搜索 （数据规模太大，(2^10) ^ 1000） 那只能用动态规划了 状态定义: dp[k][i][j] 能否通过使用前k个变换使得第i个数的值变成j 边界条件: dp[0][i][nums[i]] = 1，不使用任何变换，第i个数可以达到的数值就是nums[i]本身。 状态转移：dp[k][i][j] = dp[k-1][i][j] &#124; (dp[k &#8211; 1][i][j +&#8230;]]></description>
										<content:encoded><![CDATA[
<p>一道不错的DP题目！</p>



<p>首先看到每次可以取任意一个nums[l] ~ nums[r]的子集 </p>



<ul class="wp-block-list"><li>不能用贪心（无法找到全局最优解）</li><li>不能用搜索 （数据规模太大，(2^10) ^ 1000）</li></ul>



<p>那只能用动态规划了</p>



<p>状态定义: dp[k][i][j] 能否通过使用前k个变换使得第i个数的值变成j</p>



<p>边界条件: dp[0][i][nums[i]] = 1，不使用任何变换，第i个数可以达到的数值就是nums[i]本身。</p>



<p>状态转移：dp[k][i][j] = dp[k-1][i][j] | (dp[k &#8211; 1][i][j + val[k]] if l[k] &lt;= i &lt;= r[k] else 0)</p>



<p>简单来说如果第k-1轮第i个数可以变成j + val[k]，那么第k轮就可以通过减去val[k]变成j。</p>



<p>上面是拉的公式，我们也可以写成推的:</p>



<p>dp[k][i][j &#8211; val[k]] = dp[k-1][i][j &#8211; vak[k]] | (dp[k &#8211; 1][i][j] if l[k] &lt;= i &lt;= r[k] else 0)</p>



<p>当然这么定义的话空间复杂度太高O(10^7)，由于第k轮的初始状态就等于k-1轮的状态，我们可以使用滚动数组来降维，空间复杂度降低到O(10^4)。</p>



<p>时间复杂度：O(k*n*MaxV) = O(10^7)。</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
    int minZeroArray(vector&lt;int&gt;&amp; nums, vector&lt;vector&lt;int&gt;&gt;&amp; queries) {
      if (accumulate(begin(nums), end(nums), 0) == 0) return 0;
      constexpr int kMaxV = 1000;
      const int n = nums.size();
      const int K = queries.size();
      vector&lt;bitset&lt;kMaxV + 1&gt;&gt; dp(n);
      for (int i = 0; i &lt; n; ++i)
        dp[i][nums[i]] = 1;
      for (int k = 0; k &lt; K; ++k) {
        int l = queries[k][0];
        int r = queries[k][1];
        int v = queries[k][2];
        for (int i = l; i &lt;= r; ++i)
          for (int j = 0; j &lt;= kMaxV - v; ++j)
            if (dp[i][j + v]) dp[i][j] = 1;
        bool found = true;
        for (int i = 0; i &lt; n; ++i)
          if (!dp[i][0]) found = false;
        if (found) return k + 1;
      }
      return -1;
    }
};</pre>



<p>剪枝优化</p>



<p>上面我们把整个数组看作一个整体，一轮一轮来做。但如果某些数在第k轮能到变成0了，就没有必要参与后面的变化了，或者说它用于无法变成0，那么就是无解，其他数也就不需要再计算了。</p>



<p>所以，我们可以对<strong><em>每个数单独进行dp</em></strong>。即对于第i个数，计算最少需要多少轮才能把它变成0。然后对所有的轮数取一个最大值。总的时间复杂度不变（最坏情况所有数都需要经过K轮）。空间复杂度则可以再降低一个纬度到O(MaxV) = O(10^3)。</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
    int minZeroArray(vector&lt;int&gt;&amp; nums, vector&lt;vector&lt;int&gt;&gt;&amp; queries) {
      constexpr int kMaxV = 1000;
      const int n = nums.size();
      const int K = queries.size();
      auto rounds = [&amp;](int i) -&gt; int {
        if (!nums[i]) return 0;
        bitset&lt;kMaxV + 1&gt; dp;
        dp[nums[i]] = 1;
        for (int k = 0; k &lt; K; ++k) {
          int l = queries[k][0];
          int r = queries[k][1];
          int v = queries[k][2];
          if (l &gt; i || r &lt; i) continue;
          for (int j = 0; j &lt;= kMaxV - v; ++j)
            if (dp[j + v]) dp[j] = 1;
          if (dp[0]) return k + 1;
        }
        return INT_MAX;
      };
      int ans = 0;
      for (int i = 0; i &lt; n &amp;&amp; ans &lt;= K; ++i)
        ans = max(ans, rounds(i));
      return ans == INT_MAX ? -1 : ans;
    }
};</pre>



<p>再加速：我们可以使用C++ bitset的右移操作符，dp &gt;&gt; v，相当于把整个集合全部剪去v，再和原先的状态做或运算（集合并）来达到新的状态。时间复杂度应该是一样的，只是代码简单，速度也会快不少。注: dp&gt;&gt;v 会创建一个临时对象，大小为O(MaxV)。</p>



<p>举个例子：<br>dp = {2, 3, 7} <br>dp &gt;&gt; 2 -&gt; {0, 1, 5}<br>dp |= dp &gt;&gt; v -&gt; {0, 1, 2, 3, 5, 7]</p>



<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
    int minZeroArray(vector&lt;int&gt;&amp; nums, vector&lt;vector&lt;int&gt;&gt;&amp; queries) {
      constexpr int kMaxV = 1000;
      const int n = nums.size();
      const int K = queries.size();
      auto rounds = [&amp;](int i) -&gt; int {
        if (!nums[i]) return 0;
        bitset&lt;kMaxV + 1&gt; dp;
        dp[nums[i]] = 1;
        for (int k = 0; k &lt; K; ++k) {
          int l = queries[k][0];
          int r = queries[k][1];
          int v = queries[k][2];
          if (l &gt; i || r &lt; i) continue;
          dp |= dp &gt;&gt; v; // magic
          if (dp[0]) return k + 1;
        }
        return INT_MAX;
      };
      int ans = 0;
      for (int i = 0; i &lt; n &amp;&amp; ans &lt;= K; ++i)
        ans = max(ans, rounds(i));
      return ans == INT_MAX ? -1 : ans;
    }
};</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-3489-zero-array-transformation-iv/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2771. Longest Non-decreasing Subarray From Two Arrays</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2771-longest-non-decreasing-subarray-from-two-arrays/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2771-longest-non-decreasing-subarray-from-two-arrays/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 15 Jul 2023 15:50:52 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[medium]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10063</guid>

					<description><![CDATA[You are given two&#160;0-indexed&#160;integer arrays&#160;nums1&#160;and&#160;nums2&#160;of length&#160;n. Let&#8217;s define another&#160;0-indexed&#160;integer array,&#160;nums3, of length&#160;n. For each index&#160;i&#160;in the range&#160;[0, n - 1], you can assign either&#160;nums1[i]&#160;or&#160;nums2[i]&#160;to&#160;nums3[i]. Your&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You are given two&nbsp;<strong>0-indexed</strong>&nbsp;integer arrays&nbsp;<code>nums1</code>&nbsp;and&nbsp;<code>nums2</code>&nbsp;of length&nbsp;<code>n</code>.</p>



<p>Let&#8217;s define another&nbsp;<strong>0-indexed</strong>&nbsp;integer array,&nbsp;<code>nums3</code>, of length&nbsp;<code>n</code>. For each index&nbsp;<code>i</code>&nbsp;in the range&nbsp;<code>[0, n - 1]</code>, you can assign either&nbsp;<code>nums1[i]</code>&nbsp;or&nbsp;<code>nums2[i]</code>&nbsp;to&nbsp;<code>nums3[i]</code>.</p>



<p>Your task is to maximize the length of the&nbsp;<strong>longest non-decreasing subarray</strong>&nbsp;in&nbsp;<code>nums3</code>&nbsp;by choosing its values optimally.</p>



<p>Return&nbsp;<em>an integer representing the length of the&nbsp;<strong>longest non-decreasing</strong>&nbsp;subarray in</em>&nbsp;<code>nums3</code>.</p>



<p><strong>Note:&nbsp;</strong>A&nbsp;<strong>subarray</strong>&nbsp;is a contiguous&nbsp;<strong>non-empty</strong>&nbsp;sequence of elements within an array.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums1 = [2,3,1], nums2 = [1,2,1]
<strong>Output:</strong> 2
<strong>Explanation: </strong>One way to construct nums3 is: 
nums3 = [nums1[0], nums2[1], nums2[2]] =&gt; [2,2,1]. 
The subarray starting from index 0 and ending at index 1, [2,2], forms a non-decreasing subarray of length 2. 
We can show that 2 is the maximum achievable length.</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums1 = [1,3,2,1], nums2 = [2,2,3,4]
<strong>Output:</strong> 4
<strong>Explanation:</strong> One way to construct nums3 is: 
nums3 = [nums1[0], nums2[1], nums2[2], nums2[3]] =&gt; [1,2,3,4]. 
The entire array forms a non-decreasing subarray of length 4, making it the maximum achievable length.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums1 = [1,1], nums2 = [2,2]
<strong>Output:</strong> 2
<strong>Explanation:</strong> One way to construct nums3 is: 
nums3 = [nums1[0], nums1[1]] =&gt; [1,1]. 
The entire array forms a non-decreasing subarray of length 2, making it the maximum achievable length.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>1 &lt;= nums1.length == nums2.length == n &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= nums1[i], nums2[i] &lt;= 10<sup>9</sup></code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: DP</strong></h2>



<p>Let dp1(i), dp2(i) denote the length of the Longest Non-decreasing Subarray ends with nums1[i] and nums2[i] respectively.</p>



<p>init: dp1(0) = dp2(0) = 1</p>



<p>dp1(i) = max(dp1(i &#8211; 1) + 1 if nums1[i] &gt;= nums1[i &#8211; 1] else 1, dp2(i &#8211; 1) + 1 if nums1[i] &gt;= nums2[i &#8211; 1] else 1)<br>dp2(i) = max(dp1(i &#8211; 1) + 1 if nums2[i] &gt;= nums1[i &#8211; 1] else 1, dp2(i &#8211; 1) + 1 if nums2[i] &gt;= nums2[i &#8211; 1] else 1)</p>



<p>ans = max(dp1, dp2)</p>



<p>Time complexity: O(n)<br>Space complexity: O(n) -&gt; O(1)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class Solution:
  def maxNonDecreasingLength(self, nums1: List[int], nums2: List[int]) -&amp;gt; int:
    n = len(nums1)
    nums = [nums1, nums2]

    @cache
    def dp(i: int, j: int):
      if i == 0: return 1
      ans = 1
      for k in range(2):
        if nums[j][i] &gt;= nums[k][i - 1]:
          ans = max(ans, dp(i - 1, k) + 1)
      return ans

    return max(max(dp(i, 0), dp(i, 1)) for i in range(n))</pre>
</div></div>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int maxNonDecreasingLength(vector&lt;int&gt;&amp; nums1, vector&lt;int&gt;&amp; nums2) {
    int ans = 1;
    for (int i = 1, dp1 = 1, dp2 = 1; i &lt; nums1.size(); ++i) {
      int t1 = max(nums1[i] &gt;= nums1[i - 1] ? dp1 + 1 : 1, 
                   nums1[i] &gt;= nums2[i - 1] ? dp2 + 1 : 1);
      int t2 = max(nums2[i] &gt;= nums1[i - 1] ? dp1 + 1 : 1, 
                   nums2[i] &gt;= nums2[i - 1] ? dp2 + 1 : 1);
      dp1 = t1;
      dp2 = t2;
      ans = max({ans, dp1, dp2});
    }
    return ans;
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2771-longest-non-decreasing-subarray-from-two-arrays/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2770. Maximum Number of Jumps to Reach the Last Index</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2770-maximum-number-of-jumps-to-reach-the-last-index/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2770-maximum-number-of-jumps-to-reach-the-last-index/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Wed, 12 Jul 2023 01:27:39 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[jump]]></category>
		<category><![CDATA[medium]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10060</guid>

					<description><![CDATA[You are given a&#160;0-indexed&#160;array&#160;nums&#160;of&#160;n&#160;integers and an integer&#160;target. You are initially positioned at index&#160;0. In one step, you can jump from index&#160;i&#160;to any index&#160;j&#160;such that: 0&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You are given a&nbsp;<strong>0-indexed</strong>&nbsp;array&nbsp;<code>nums</code>&nbsp;of&nbsp;<code>n</code>&nbsp;integers and an integer&nbsp;<code>target</code>.</p>



<p>You are initially positioned at index&nbsp;<code>0</code>. In one step, you can jump from index&nbsp;<code>i</code>&nbsp;to any index&nbsp;<code>j</code>&nbsp;such that:</p>



<ul class="wp-block-list"><li><code>0 &lt;= i &lt; j &lt; n</code></li><li><code>-target &lt;= nums[j] - nums[i] &lt;= target</code></li></ul>



<p>Return&nbsp;<em>the&nbsp;<strong>maximum number of jumps</strong>&nbsp;you can make to reach index</em>&nbsp;<code>n - 1</code>.</p>



<p>If there is no way to reach index&nbsp;<code>n - 1</code>, return&nbsp;<code>-1</code>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [1,3,6,4,1,2], target = 2
<strong>Output:</strong> 3
<strong>Explanation:</strong> To go from index 0 to index n - 1 with the maximum number of jumps, you can perform the following jumping sequence:
- Jump from index 0 to index 1. 
- Jump from index 1 to index 3.
- Jump from index 3 to index 5.
It can be proven that there is no other jumping sequence that goes from 0 to n - 1 with more than 3 jumps. Hence, the answer is 3. </pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [1,3,6,4,1,2], target = 3
<strong>Output:</strong> 5
<strong>Explanation:</strong> To go from index 0 to index n - 1 with the maximum number of jumps, you can perform the following jumping sequence:
- Jump from index 0 to index 1.
- Jump from index 1 to index 2.
- Jump from index 2 to index 3.
- Jump from index 3 to index 4.
- Jump from index 4 to index 5.
It can be proven that there is no other jumping sequence that goes from 0 to n - 1 with more than 5 jumps. Hence, the answer is 5. </pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [1,3,6,4,1,2], target = 0
<strong>Output:</strong> -1
<strong>Explanation:</strong> It can be proven that there is no jumping sequence that goes from 0 to n - 1. Hence, the answer is -1. 
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>2 &lt;= nums.length == n &lt;= 1000</code></li><li><code>-10<sup>9</sup>&nbsp;&lt;= nums[i]&nbsp;&lt;= 10<sup>9</sup></code></li><li><code>0 &lt;= target &lt;= 2 * 10<sup>9</sup></code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: DP</strong></h2>



<p>Let dp(i) denotes the maximum jumps from index i to index n-1.</p>



<p>For each index i, try jumping to all possible index j.</p>



<p>dp(i) = max(1 + dp(j)) if j &gt; i and abs(nums[j] &#8211; nums[i) &lt;= target else -1</p>



<p>Time complexity: O(n<sup>2</sup>)<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class Solution:
  def maximumJumps(self, nums: List[int], target: int) -&gt; int:
    n = len(nums)
    @cache
    def dp(i):
      if i == n - 1: return 0
      ans = -1
      for j in range(i + 1, n):
        if abs(nums[j] - nums[i]) &lt;= target and dp(j) != -1:
          ans = max(ans, 1 + dp(j))
      return ans
    
    return dp(0)</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2770-maximum-number-of-jumps-to-reach-the-last-index/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2560. House Robber IV</title>
		<link>https://zxi.mytechroad.com/blog/algorithms/binary-search/leetcode-2560-house-robber-iv/</link>
					<comments>https://zxi.mytechroad.com/blog/algorithms/binary-search/leetcode-2560-house-robber-iv/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 05 Feb 2023 05:47:10 +0000</pubDate>
				<category><![CDATA[Binary Search]]></category>
		<category><![CDATA[binary search]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[medium]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9932</guid>

					<description><![CDATA[There are several consecutive houses along a street, each of which has some money inside. There is also a robber, who wants to steal money&#8230;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="花花酱 LeetCode 2560. House Robber IV - 刷题找工作 EP409" width="500" height="281" src="https://www.youtube.com/embed/DulvOfbAdzI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>There are several consecutive houses along a street, each of which has some money inside. There is also a robber, who wants to steal money from the homes, but he&nbsp;<strong>refuses to steal from adjacent homes</strong>.</p>



<p>The&nbsp;<strong>capability</strong>&nbsp;of the robber is the maximum amount of money he steals from one house of all the houses he robbed.</p>



<p>You are given an integer array&nbsp;<code>nums</code>&nbsp;representing how much money is stashed in each house. More formally, the&nbsp;<code>i<sup>th</sup></code>&nbsp;house from the left has&nbsp;<code>nums[i]</code>&nbsp;dollars.</p>



<p>You are also given an integer&nbsp;<code>k</code>, representing the&nbsp;<strong>minimum</strong>&nbsp;number of houses the robber will steal from.&nbsp;It is always possible to steal at least&nbsp;<code>k</code>&nbsp;houses.</p>



<p>Return&nbsp;<em>the&nbsp;<strong>minimum</strong>&nbsp;</em>capability of the robber out of all the possible ways to steal at least&nbsp;<code>k</code>&nbsp;houses.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [2,3,5,9], k = 2
<strong>Output:</strong> 5
<strong>Explanation:</strong> 
There are three ways to rob at least 2 houses:
- Rob the houses at indices 0 and 2. Capability is max(nums[0], nums[2]) = 5.
- Rob the houses at indices 0 and 3. Capability is max(nums[0], nums[3]) = 9.
- Rob the houses at indices 1 and 3. Capability is max(nums[1], nums[3]) = 9.
Therefore, we return min(5, 9, 9) = 5.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [2,7,9,3,1], k = 2
<strong>Output:</strong> 2
<strong>Explanation:</strong> There are 7 ways to rob the houses. The way which leads to minimum capability is to rob the house at index 0 and 4. Return max(nums[0], nums[4]) = 2.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>1 &lt;= nums.length &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= nums[i] &lt;= 10<sup>9</sup></code></li><li><code>1 &lt;= k &lt;= (nums.length + 1)/2</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution 1: Binary Search + DP</strong></h2>



<p>It&#8217;s easy to see that higher capability means more houses we can rob. Thus this can be formulate as a binary search algorithm e.g. find the minimum C s.t. we can rob at least k houses.</p>



<p>Then we can use dp(i) to calculate maximum houses we can rob if starting from the i&#8217;th house.<br>dp(i) = max(1 + dp(i + 2) if nums[i] &lt;= C else 0, dp(i + 1))</p>



<p>Time complexity: O(n log m)<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int minCapability(vector&lt;int&gt;&amp; nums, int k) {
    int l = 0;
    int r = *max_element(begin(nums), end(nums)) + 1;
    vector&lt;int&gt; cache(nums.size(), -1);
    function&lt;int(int, int)&gt; rob = [&amp;](int m, int i) -&gt; int {
      if (i &gt;= nums.size()) return 0;
      if (cache[i] &gt;= 0) return cache[i];
      if (nums[i] &gt; m) return rob(m, i + 1);
      return cache[i] = max(1 + rob(m, i + 2), rob(m, i + 1));
    };
    while (l &lt; r) {
      int m = l + (r - l) / 2;
      fill(begin(cache), end(cache), -1);
      if (rob(m, 0) &gt;= k)
        r = m;
      else
        l = m + 1;
    }
    return l;
  }
};</pre>
</div></div>



<h2 class="wp-block-heading"><strong>Solution 2: Binary Search + Greedy</strong></h2>



<p>From: dp(i) = max(1 + dp(i + 2) if nums[i] &lt;= C else 0, dp(i + 1)) we can see that if we can pick the i-th one, it will be the same or better if we skip and start from dp(i + 1). Thus we can convert this from DP to greedy. As long as we can pick the current one, we pick it first.</p>



<p>Time complexity: O(n log m)<br>Space complexity: O(1)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int minCapability(vector&lt;int&gt;&amp; nums, int k) {
    int l = 0;
    int r = *max_element(begin(nums), end(nums)) + 1;    
    auto rob = [&amp;](int m) -&gt; int {
      int ans = 0;
      for (int i = 0; i &lt; nums.size(); ++i)
        if (nums[i] &lt;= m) {
          ++ans;
          ++i;
        }
      return ans;
    };
    while (l &lt; r) {
      int m = l + (r - l) / 2;      
      if (rob(m) &gt;= k)
        r = m;
      else
        l = m + 1;
    }
    return l;
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/algorithms/binary-search/leetcode-2560-house-robber-iv/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2435. Paths in Matrix Whose Sum Is Divisible by K</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2435-paths-in-matrix-whose-sum-is-divisible-by-k/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2435-paths-in-matrix-whose-sum-is-divisible-by-k/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Tue, 11 Oct 2022 01:04:27 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[grid]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[paths]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9854</guid>

					<description><![CDATA[You are given a&#160;0-indexed&#160;m x n&#160;integer matrix&#160;grid&#160;and an integer&#160;k. You are currently at position&#160;(0, 0)&#160;and you want to reach position&#160;(m - 1, n - 1)&#160;moving&#8230;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="花花酱 LeetCode 2435. Paths in Matrix Whose Sum Is Divisible by K - 刷题找工作 EP403" width="500" height="281" src="https://www.youtube.com/embed/Gj8mvPsRkBI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>You are given a&nbsp;<strong>0-indexed</strong>&nbsp;<code>m x n</code>&nbsp;integer matrix&nbsp;<code>grid</code>&nbsp;and an integer&nbsp;<code>k</code>. You are currently at position&nbsp;<code>(0, 0)</code>&nbsp;and you want to reach position&nbsp;<code>(m - 1, n - 1)</code>&nbsp;moving only&nbsp;<strong>down</strong>&nbsp;or&nbsp;<strong>right</strong>.</p>



<p>Return<em>&nbsp;the number of paths where the sum of the elements on the path is divisible by&nbsp;</em><code>k</code>. Since the answer may be very large, return it&nbsp;<strong>modulo</strong>&nbsp;<code>10<sup>9</sup>&nbsp;+ 7</code>.</p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2022/08/13/image-20220813183124-1.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> grid = [[5,2,4],[3,0,5],[0,7,2]], k = 3
<strong>Output:</strong> 2
<strong>Explanation:</strong> There are two paths where the sum of the elements on the path is divisible by k.
The first path highlighted in red has a sum of 5 + 2 + 4 + 5 + 2 = 18 which is divisible by 3.
The second path highlighted in blue has a sum of 5 + 3 + 0 + 5 + 2 = 15 which is divisible by 3.
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2022/08/17/image-20220817112930-3.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> grid = [[0,0]], k = 5
<strong>Output:</strong> 1
<strong>Explanation:</strong> The path highlighted in red has a sum of 0 + 0 = 0 which is divisible by 5.
</pre>



<p><strong>Example 3:</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2022/08/12/image-20220812224605-3.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> grid = [[7,3,4,9],[2,3,6,2],[2,3,7,0]], k = 1
<strong>Output:</strong> 10
<strong>Explanation:</strong> Every integer is divisible by 1 so the sum of the elements on every possible path is divisible by k.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>m == grid.length</code></li><li><code>n == grid[i].length</code></li><li><code>1 &lt;= m, n &lt;= 5 * 10<sup>4</sup></code></li><li><code>1 &lt;= m * n &lt;= 5 * 10<sup>4</sup></code></li><li><code>0 &lt;= grid[i][j] &lt;= 100</code></li><li><code>1 &lt;= k &lt;= 50</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: DP</strong></h2>



<figure class="wp-block-image size-full"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-1.png"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-1.png" alt="" class="wp-image-9858" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-1-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-2.png"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-2.png" alt="" class="wp-image-9859" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-2-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-3.png"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-3.png" alt="" class="wp-image-9861" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2022/10/2435-ep403-3-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></figure>



<p>Let dp[i][j][r] := # of paths from (0,0) to (i,j) with path sum % k == r.<br><br>init: dp[0][0][grid[0][0] % k] = 1</p>



<p>dp[i][j][(r + grid[i][j]) % k] = dp[i-1][j][r] + dp[i][j-1][r]</p>



<p>ans = dp[m-1][n-1][0]</p>



<p>Time complexity: O(m*n*k)<br>Space complexity: O(m*n*k) -&gt; O(n*k)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int numberOfPaths(vector&lt;vector&lt;int&gt;&gt;&amp; grid, int k) {
    const int kMod = 1e9 + 7;
    const int m = grid.size();
    const int n = grid[0].size();
    vector&lt;vector&lt;vector&lt;int&gt;&gt;&gt; dp(m, vector&lt;vector&lt;int&gt;&gt;(n, vector&lt;int&gt;(k)));
    dp[0][0][grid[0][0] % k] = 1;
    for (int i = 0; i &lt; m; ++i)
      for (int j = 0; j &lt; n; ++j) {
        if (i == 0 &amp;&amp; j == 0) continue;
        for (int r = 0; r &lt; k; ++r)
          dp[i][j][(r + grid[i][j]) % k] = 
            ((j ? dp[i][j - 1][r] : 0) + (i ? dp[i - 1][j][r] : 0)) % kMod;          
      }
    return dp[m - 1][n - 1][0];
  }
};</pre>
</div></div>



<p>Related Problems:</p>



<ul class="wp-block-list"><li><a href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-62-unique-paths/" data-type="post" data-id="187">花花酱 LeetCode 62. Unique Paths</a></li></ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2435-paths-in-matrix-whose-sum-is-divisible-by-k/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2420. Find All Good Indices</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2420-find-all-good-indices/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2420-find-all-good-indices/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 26 Sep 2022 17:18:29 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[precompute]]></category>
		<category><![CDATA[prefix sum]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9850</guid>

					<description><![CDATA[You are given a&#160;0-indexed&#160;integer array&#160;nums&#160;of size&#160;n&#160;and a positive integer&#160;k. We call an index&#160;i&#160;in the range&#160;k &#60;= i &#60; n - k&#160;good&#160;if the following conditions are&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You are given a&nbsp;<strong>0-indexed</strong>&nbsp;integer array&nbsp;<code>nums</code>&nbsp;of size&nbsp;<code>n</code>&nbsp;and a positive integer&nbsp;<code>k</code>.</p>



<p>We call an index&nbsp;<code>i</code>&nbsp;in the range&nbsp;<code>k &lt;= i &lt; n - k</code>&nbsp;<strong>good</strong>&nbsp;if the following conditions are satisfied:</p>



<ul class="wp-block-list"><li>The&nbsp;<code>k</code>&nbsp;elements that are just&nbsp;<strong>before</strong>&nbsp;the index&nbsp;<code>i</code>&nbsp;are in&nbsp;<strong>non-increasing</strong>&nbsp;order.</li><li>The&nbsp;<code>k</code>&nbsp;elements that are just&nbsp;<strong>after</strong>&nbsp;the index&nbsp;<code>i</code>&nbsp;are in&nbsp;<strong>non-decreasing</strong>&nbsp;order.</li></ul>



<p>Return&nbsp;<em>an array of all good indices sorted in&nbsp;<strong>increasing</strong>&nbsp;order</em>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [2,1,1,1,3,4,1], k = 2
<strong>Output:</strong> [2,3]
<strong>Explanation:</strong> There are two good indices in the array:
- Index 2. The subarray [2,1] is in non-increasing order, and the subarray [1,3] is in non-decreasing order.
- Index 3. The subarray [1,1] is in non-increasing order, and the subarray [3,4] is in non-decreasing order.
Note that the index 4 is not good because [4,1] is not non-decreasing.</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [2,1,1,2], k = 2
<strong>Output:</strong> []
<strong>Explanation:</strong> There are no good indices in this array.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>n == nums.length</code></li><li><code>3 &lt;= n &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= nums[i] &lt;= 10<sup>6</sup></code></li><li><code>1 &lt;= k &lt;= n / 2</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: Prefix Sum</strong></h2>



<p>Let before[i] = length of longest non-increasing subarray ends of nums[i].<br>Let after[i] = length of longest non-decreasing subarray ends of nums[i].</p>



<p>An index is good if nums[i &#8211; 1] &gt;= k and nums[i + k] &gt;= k</p>



<p>Time complexity: O(n + (n &#8211; 2*k))<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  vector&lt;int&gt; goodIndices(vector&lt;int&gt;&amp; nums, int k) {
    const int n = nums.size();
    vector&lt;int&gt; before(n, 1);
    vector&lt;int&gt; after(n, 1);
    for (int i = 1; i &lt; n; ++i) {
      if (nums[i] &lt;= nums[i - 1])
        before[i] = before[i - 1] + 1;      
      if (nums[i] &gt;= nums[i - 1])
        after[i] = after[i - 1] + 1;    
    }
    vector&lt;int&gt; ans;
    for (int i = k; i + k &lt; n; ++i) {
      if (before[i - 1] &gt;= k &amp;&amp; after[i + k] &gt;= k)
        ans.push_back(i);
    }
    return ans;
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2420-find-all-good-indices/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2407. Longest Increasing Subsequence II</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2407-longest-increasing-subsequence-ii/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2407-longest-increasing-subsequence-ii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 12 Sep 2022 05:16:09 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[range query]]></category>
		<category><![CDATA[segment tree]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9817</guid>

					<description><![CDATA[You are given an integer array&#160;nums&#160;and an integer&#160;k. Find the longest subsequence of&#160;nums&#160;that meets the following requirements: The subsequence is&#160;strictly increasing&#160;and The difference between adjacent&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You are given an integer array&nbsp;<code>nums</code>&nbsp;and an integer&nbsp;<code>k</code>.</p>



<p>Find the longest subsequence of&nbsp;<code>nums</code>&nbsp;that meets the following requirements:</p>



<ul class="wp-block-list"><li>The subsequence is&nbsp;<strong>strictly increasing</strong>&nbsp;and</li><li>The difference between adjacent elements in the subsequence is&nbsp;<strong>at most</strong>&nbsp;<code>k</code>.</li></ul>



<p>Return<em>&nbsp;the length of the&nbsp;<strong>longest</strong>&nbsp;<strong>subsequence</strong>&nbsp;that meets the requirements.</em></p>



<p>A&nbsp;<strong>subsequence</strong>&nbsp;is an array that can be derived from another array by deleting some or no elements without changing the order of the remaining elements.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [4,2,1,4,3,4,5,8,15], k = 3
<strong>Output:</strong> 5
<strong>Explanation:</strong>
The longest subsequence that meets the requirements is [1,3,4,5,8].
The subsequence has a length of 5, so we return 5.
Note that the subsequence [1,3,4,5,8,15] does not meet the requirements because 15 - 8 = 7 is larger than 3.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [7,4,5,1,8,12,4,7], k = 5
<strong>Output:</strong> 4
<strong>Explanation:</strong>
The longest subsequence that meets the requirements is [4,5,8,12].
The subsequence has a length of 4, so we return 4.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> nums = [1,5], k = 1
<strong>Output:</strong> 1
<strong>Explanation:</strong>
The longest subsequence that meets the requirements is [1].
The subsequence has a length of 1, so we return 1.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>1 &lt;= nums.length &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= nums[i], k &lt;= 10<sup>5</sup></code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: DP + Segment Tree | Max range query</strong></h2>



<p>Let dp[i] := length of LIS end with number i.<br>dp[i] = 1 + max(dp[i-k:i])</p>



<p>Naive dp takes O(n*k) time which will cause TLE.</p>



<p>We can use segment tree to speed up the max range query to log(m), where m is the max value of the array.</p>



<p>Time complexity: O(n*logm)<br>Space complexity: O(m)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int lengthOfLIS(vector&lt;int&gt;&amp; nums, int k) {
    const int n = *max_element(begin(nums), end(nums));
    vector&lt;int&gt; dp(2 * (n + 1));
    auto query = [&amp;](int l, int r) -&gt; int {
      int ans = 0;
      for (l += n, r += n; l &lt; r; l &gt;&gt;= 1, r &gt;&gt;= 1) {
        if (l &amp; 1) ans = max(ans, dp[l++]);      
        if (r &amp; 1) ans = max(ans, dp[--r]);
      }
      return ans;
    };
    auto update = [&amp;](int i, int val) -&gt; void {
      dp[i += n] = val;
      while (i &gt; 1) {
        i &gt;&gt;= 1;
        dp[i] = max(dp[i * 2], dp[i * 2 + 1]);
      }
    };        
    int ans = 0;
    for (int x : nums) {
      int cur = 1 + query(max(1, x - k), x);
      update(x, cur);
      ans = max(ans, cur);
    }
    return ans;
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2407-longest-increasing-subsequence-ii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2304. Minimum Path Cost in a Grid</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2304-minimum-path-cost-in-a-grid/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2304-minimum-path-cost-in-a-grid/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Wed, 15 Jun 2022 03:57:20 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9751</guid>

					<description><![CDATA[You are given a&#160;0-indexed&#160;m x n&#160;integer matrix&#160;grid&#160;consisting of&#160;distinct&#160;integers from&#160;0&#160;to&#160;m * n - 1. You can move in this matrix from a cell to any other&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You are given a&nbsp;<strong>0-indexed</strong>&nbsp;<code>m x n</code>&nbsp;integer matrix&nbsp;<code>grid</code>&nbsp;consisting of&nbsp;<strong>distinct</strong>&nbsp;integers from&nbsp;<code>0</code>&nbsp;to&nbsp;<code>m * n - 1</code>. You can move in this matrix from a cell to any other cell in the&nbsp;<strong>next</strong>&nbsp;row. That is, if you are in cell&nbsp;<code>(x, y)</code>&nbsp;such that&nbsp;<code>x &lt; m - 1</code>, you can move to any of the cells&nbsp;<code>(x + 1, 0)</code>,&nbsp;<code>(x + 1, 1)</code>, &#8230;,&nbsp;<code>(x + 1, n - 1)</code>.&nbsp;<strong>Note</strong>&nbsp;that it is not possible to move from cells in the last row.</p>



<p>Each possible move has a cost given by a&nbsp;<strong>0-indexed</strong>&nbsp;2D array&nbsp;<code>moveCost</code>&nbsp;of size&nbsp;<code>(m * n) x n</code>, where&nbsp;<code>moveCost[i][j]</code>&nbsp;is the cost of moving from a cell with value&nbsp;<code>i</code>&nbsp;to a cell in column&nbsp;<code>j</code>&nbsp;of the next row. The cost of moving from cells in the last row of&nbsp;<code>grid</code>&nbsp;can be ignored.</p>



<p>The cost of a path in&nbsp;<code>grid</code>&nbsp;is the&nbsp;<strong>sum</strong>&nbsp;of all values of cells visited plus the&nbsp;<strong>sum</strong>&nbsp;of costs of all the moves made. Return&nbsp;<em>the&nbsp;<strong>minimum</strong>&nbsp;cost of a path that starts from any cell in the&nbsp;<strong>first</strong>&nbsp;row and ends at any cell in the&nbsp;<strong>last</strong>&nbsp;row.</em></p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2022/04/28/griddrawio-2.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> grid = [[5,3],[4,0],[2,1]], moveCost = [[9,8],[1,5],[10,12],[18,6],[2,4],[14,3]]
<strong>Output:</strong> 17
<strong>Explanation: </strong>The path with the minimum possible cost is the path 5 -&gt; 0 -&gt; 1.
- The sum of the values of cells visited is 5 + 0 + 1 = 6.
- The cost of moving from 5 to 0 is 3.
- The cost of moving from 0 to 1 is 8.
So the total cost of the path is 6 + 3 + 8 = 17.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> grid = [[5,1,2],[4,0,3]], moveCost = [[12,10,15],[20,23,8],[21,7,1],[8,1,13],[9,10,25],[5,3,2]]
<strong>Output:</strong> 6
<strong>Explanation:</strong> The path with the minimum possible cost is the path 2 -&gt; 3.
- The sum of the values of cells visited is 2 + 3 = 5.
- The cost of moving from 2 to 3 is 1.
So the total cost of this path is 5 + 1 = 6.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>m == grid.length</code></li><li><code>n == grid[i].length</code></li><li><code>2 &lt;= m, n &lt;= 50</code></li><li><code>grid</code>&nbsp;consists of distinct integers from&nbsp;<code>0</code>&nbsp;to&nbsp;<code>m * n - 1</code>.</li><li><code>moveCost.length == m * n</code></li><li><code>moveCost[i].length == n</code></li><li><code>1 &lt;= moveCost[i][j] &lt;= 100</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: DP</strong></h2>



<p>Let dp[i][j] := min cost to reach grid[i][j] from the first row.</p>



<p>dp[i][j] = min{grid[i][j] + dp[i &#8211; 1][k] + moveCost[grid[i &#8211; 1][k]][j]}  0 &lt;= k &lt; n<br></p>



<p>For each node, try all possible nodes from the previous row.</p>



<p>Time complexity: O(m*n<sup>2</sup>)<br>Space complexity: O(m*n) -&gt; O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int minPathCost(vector&lt;vector&lt;int&gt;&gt;&amp; grid, vector&lt;vector&lt;int&gt;&gt;&amp; moveCost) {
    const int m = grid.size();
    const int n = grid[0].size();
    vector&lt;vector&lt;int&gt;&gt; dp(m, vector&lt;int&gt;(n, INT_MAX));    
    for (int i = 0; i &lt; m; ++i)
      for (int j = 0; j &lt; n; ++j)
        for (int k = 0; k &lt; n; ++k)          
          dp[i][j] = min(dp[i][j], grid[i][j] + 
                         (i ? dp[i - 1][k] + moveCost[grid[i - 1][k]][j] : 0));
    return *min_element(begin(dp[m - 1]), end(dp[m - 1]));
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2304-minimum-path-cost-in-a-grid/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2267. Check if There Is a Valid Parentheses String Path</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2267-check-if-there-is-a-valid-parentheses-string-path/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2267-check-if-there-is-a-valid-parentheses-string-path/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Tue, 10 May 2022 15:20:01 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[hard]]></category>
		<category><![CDATA[parentheses]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9734</guid>

					<description><![CDATA[A parentheses string is a&#160;non-empty&#160;string consisting only of&#160;'('&#160;and&#160;')'. It is&#160;valid&#160;if&#160;any&#160;of the following conditions is&#160;true: It is&#160;(). It can be written as&#160;AB&#160;(A&#160;concatenated with&#160;B), where&#160;A&#160;and&#160;B&#160;are valid parentheses&#8230;]]></description>
										<content:encoded><![CDATA[
<p>A parentheses string is a&nbsp;<strong>non-empty</strong>&nbsp;string consisting only of&nbsp;<code>'('</code>&nbsp;and&nbsp;<code>')'</code>. It is&nbsp;<strong>valid</strong>&nbsp;if&nbsp;<strong>any</strong>&nbsp;of the following conditions is&nbsp;<strong>true</strong>:</p>



<ul class="wp-block-list"><li>It is&nbsp;<code>()</code>.</li><li>It can be written as&nbsp;<code>AB</code>&nbsp;(<code>A</code>&nbsp;concatenated with&nbsp;<code>B</code>), where&nbsp;<code>A</code>&nbsp;and&nbsp;<code>B</code>&nbsp;are valid parentheses strings.</li><li>It can be written as&nbsp;<code>(A)</code>, where&nbsp;<code>A</code>&nbsp;is a valid parentheses string.</li></ul>



<p>You are given an&nbsp;<code>m x n</code>&nbsp;matrix of parentheses&nbsp;<code>grid</code>. A&nbsp;<strong>valid parentheses string path</strong>&nbsp;in the grid is a path satisfying&nbsp;<strong>all</strong>&nbsp;of the following conditions:</p>



<ul class="wp-block-list"><li>The path starts from the upper left cell&nbsp;<code>(0, 0)</code>.</li><li>The path ends at the bottom-right cell&nbsp;<code>(m - 1, n - 1)</code>.</li><li>The path only ever moves&nbsp;<strong>down</strong>&nbsp;or&nbsp;<strong>right</strong>.</li><li>The resulting parentheses string formed by the path is&nbsp;<strong>valid</strong>.</li></ul>



<p>Return&nbsp;<code>true</code>&nbsp;<em>if there exists a&nbsp;<strong>valid parentheses string path</strong>&nbsp;in the grid.</em>&nbsp;Otherwise, return&nbsp;<code>false</code>.</p>



<p><strong>Example 1:</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2022/03/15/example1drawio.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> grid = [["(","(","("],[")","(",")"],["(","(",")"],["(","(",")"]]
<strong>Output:</strong> true
<strong>Explanation:</strong> The above diagram shows two possible paths that form valid parentheses strings.
The first path shown results in the valid parentheses string "()(())".
The second path shown results in the valid parentheses string "((()))".
Note that there may be other valid parentheses string paths.
</pre>



<p><strong>Example 2:</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2022/03/15/example2drawio.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> grid = [[")",")"],["(","("]]
<strong>Output:</strong> false
<strong>Explanation:</strong> The two possible paths form the parentheses strings "))(" and ")((". Since neither of them are valid parentheses strings, we return false.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>m == grid.length</code></li><li><code>n == grid[i].length</code></li><li><code>1 &lt;= m, n &lt;= 100</code></li><li><code>grid[i][j]</code>&nbsp;is either&nbsp;<code>'('</code>&nbsp;or&nbsp;<code>')'</code>.</li></ul>



<h2 class="wp-block-heading"><strong>Solution: DP</strong></h2>



<p>Let dp(i, j, b) denote whether there is a path from (i,j) to (m-1, n-1) given b open parentheses.<br>if we are at (m &#8211; 1, n &#8211; 1) and b == 0 then we found a valid path.<br>dp(i, j, b) = dp(i + 1, j, b&#8217;) or dp(i, j + 1, b&#8217;) where b&#8217; = b + 1 if  grid[i][j] == &#8216;(&#8216; else -1</p>



<p>Time complexity: O(m*n*(m + n))<br><meta charset="utf-8">Space complexity: O(m*n*(m + n))</p>



<div class="responsive-tabs">
<h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class Solution:
  def hasValidPath(self, grid: List[List[str]]) -&gt; bool:
    m, n = len(grid), len(grid[0])    
    
    @cache
    def dp(i: int, j: int, b: int) -&gt; bool:
      if b &lt; 0 or i == m or j == n: return False
      b += 1 if grid[i][j] == '(' else -1      
      if i == m - 1 and j == n - 1 and b == 0: return True      
      return dp(i + 1, j, b) or dp(i, j + 1, b)
    
    return dp(0, 0, 0)</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2267-check-if-there-is-a-valid-parentheses-string-path/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2266. Count Number of Texts</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2266-count-number-of-texts/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2266-count-number-of-texts/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Tue, 10 May 2022 14:47:44 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[decode]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[medium]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9731</guid>

					<description><![CDATA[Alice is texting Bob using her phone. The&#160;mapping&#160;of digits to letters is shown in the figure below. In order to&#160;add&#160;a letter, Alice has to&#160;press&#160;the key&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Alice is texting Bob using her phone. The&nbsp;<strong>mapping</strong>&nbsp;of digits to letters is shown in the figure below.</p>



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2022/03/15/1200px-telephone-keypad2svg.png" alt=""/></figure>



<p>In order to&nbsp;<strong>add</strong>&nbsp;a letter, Alice has to&nbsp;<strong>press</strong>&nbsp;the key of the corresponding digit&nbsp;<code>i</code>&nbsp;times, where&nbsp;<code>i</code>&nbsp;is the position of the letter in the key.</p>



<ul class="wp-block-list"><li>For example, to add the letter&nbsp;<code>'s'</code>, Alice has to press&nbsp;<code>'7'</code>&nbsp;four times. Similarly, to add the letter&nbsp;<code>'k'</code>, Alice has to press&nbsp;<code>'5'</code>&nbsp;twice.</li><li>Note that the digits&nbsp;<code>'0'</code>&nbsp;and&nbsp;<code>'1'</code>&nbsp;do not map to any letters, so Alice&nbsp;<strong>does not</strong>&nbsp;use them.</li></ul>



<p>However, due to an error in transmission, Bob did not receive Alice&#8217;s text message but received a&nbsp;<strong>string of pressed keys</strong>&nbsp;instead.</p>



<ul class="wp-block-list"><li>For example, when Alice sent the message&nbsp;<code>"bob"</code>, Bob received the string&nbsp;<code>"2266622"</code>.</li></ul>



<p>Given a string&nbsp;<code>pressedKeys</code>&nbsp;representing the string received by Bob, return&nbsp;<em>the&nbsp;<strong>total number of possible text messages</strong>&nbsp;Alice could have sent</em>.</p>



<p>Since the answer may be very large, return it&nbsp;<strong>modulo</strong>&nbsp;<code>10<sup>9</sup>&nbsp;+ 7</code>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> pressedKeys = "22233"
<strong>Output:</strong> 8
<strong>Explanation:</strong>
The possible text messages Alice could have sent are:
"aaadd", "abdd", "badd", "cdd", "aaae", "abe", "bae", and "ce".
Since there are 8 possible messages, we return 8.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> pressedKeys = "222222222222222222222222222222222222"
<strong>Output:</strong> 82876089
<strong>Explanation:</strong>
There are 2082876103 possible text messages Alice could have sent.
Since we need to return the answer modulo 10<sup>9</sup> + 7, we return 2082876103 % (10<sup>9</sup> + 7) = 82876089.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>1 &lt;= pressedKeys.length &lt;= 10<sup>5</sup></code></li><li><code>pressedKeys</code>&nbsp;only consists of digits from&nbsp;<code>'2'</code>&nbsp;&#8211;&nbsp;<code>'9'</code>.</li></ul>



<h2 class="wp-block-heading"><strong>Solution: DP</strong></h2>



<p>Similar to <a href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-91-decode-ways/" data-type="post" data-id="757">花花酱 LeetCode 91. Decode Ways</a>, let dp[i] denote # of possible messages of substr s[i:]</p>



<p>dp[i] = dp[i + 1] <br>+ dp[i + 2] (if s[i:i+1] are the same) <br>+ dp[i + 3] (if s[i:i+2] are the same) <br>+ dp[i + 4] (if s[i:i+3] are the same and s[i] in &#8217;79&#8217;)</p>



<p>dp[n] = 1</p>



<p>Time complexity: O(n)<br>Space complexity: O(n) -&gt; O(4)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class Solution:
  def countTexts(self, s: str) -&gt; int:
    kMod = 10**9 + 7
    n = len(s)
    
    @cache
    def dp(i: int) -&gt; int:      
      if i &gt;= n: return 1
      ans = dp(i + 1)
      ans += dp(i + 2) if i + 2 &lt;= n and s[i] == s[i + 1] else 0
      ans += dp(i + 3) if i + 3 &lt;= n and s[i] == s[i + 1] == s[i + 2] else 0
      ans += dp(i + 4) if i + 4 &lt;= n and s[i] == s[i + 1] == s[i + 2] == s[i + 3] and s[i] in '79' else 0      
      return ans % kMod
    
    return dp(0)</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2266-count-number-of-texts/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
