<?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>Dynamic Programming &#8211; Huahua&#8217;s Tech Road</title>
	<atom:link href="https://zxi.mytechroad.com/blog/category/dynamic-programming/feed/" rel="self" type="application/rss+xml" />
	<link>https://zxi.mytechroad.com/blog</link>
	<description></description>
	<lastBuildDate>Thu, 10 Apr 2025 14:21:28 +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>Dynamic Programming &#8211; Huahua&#8217;s Tech Road</title>
	<link>https://zxi.mytechroad.com/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<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-69b106320476d419724658/] &#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 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 fetchpriority="high" 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="(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 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="(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>
		<item>
		<title>花花酱 LeetCode 2222. Number of Ways to Select Buildings</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2222-number-of-ways-to-select-buildings/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2222-number-of-ways-to-select-buildings/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 02 Apr 2022 22:22:12 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[counting]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[medium]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9609</guid>

					<description><![CDATA[You are given a&#160;0-indexed&#160;binary string&#160;s&#160;which represents the types of buildings along a street where: s[i] = '0'&#160;denotes that the&#160;ith&#160;building is an office and s[i] =&#8230;]]></description>
										<content:encoded><![CDATA[
<p>You are given a&nbsp;<strong>0-indexed</strong>&nbsp;binary string&nbsp;<code>s</code>&nbsp;which represents the types of buildings along a street where:</p>



<ul class="wp-block-list"><li><code>s[i] = '0'</code>&nbsp;denotes that the&nbsp;<code>i<sup>th</sup></code>&nbsp;building is an office and</li><li><code>s[i] = '1'</code>&nbsp;denotes that the&nbsp;<code>i<sup>th</sup></code>&nbsp;building is a restaurant.</li></ul>



<p>As a city official, you would like to&nbsp;<strong>select</strong>&nbsp;3 buildings for random inspection. However, to ensure variety,&nbsp;<strong>no two consecutive</strong>&nbsp;buildings out of the&nbsp;<strong>selected</strong>&nbsp;buildings can be of the same type.</p>



<ul class="wp-block-list"><li>For example, given&nbsp;<code>s = "0<u><strong>0</strong></u>1<u><strong>1</strong></u>0<u><strong>1</strong></u>"</code>, we cannot select the&nbsp;<code>1<sup>st</sup></code>,&nbsp;<code>3<sup>rd</sup></code>, and&nbsp;<code>5<sup>th</sup></code>&nbsp;buildings as that would form&nbsp;<code>"0<strong><u>11</u></strong>"</code>&nbsp;which is&nbsp;<strong>not</strong>&nbsp;allowed due to having two consecutive buildings of the same type.</li></ul>



<p>Return&nbsp;<em>the&nbsp;<strong>number of valid ways</strong>&nbsp;to select 3 buildings.</em></p>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s = "001101"
<strong>Output:</strong> 6
<strong>Explanation:</strong> 
The following sets of indices selected are valid:
- [0,2,4] from "<strong>0</strong>0<strong><u>1</u></strong>1<strong><u>0</u></strong>1" forms "010"
- [0,3,4] from "<strong>0</strong>01<strong>10</strong>1" forms "010"
- [1,2,4] from "0<strong>01</strong>1<strong>0</strong>1" forms "010"
- [1,3,4] from "0<strong>0</strong>1<strong>10</strong>1" forms "010"
- [2,4,5] from "00<strong>1</strong>1<strong>01</strong>" forms "101"
- [3,4,5] from "001<strong>101</strong>" forms "101"
No other selection is valid. Thus, there are 6 total ways.
</pre>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> s = "11100"
<strong>Output:</strong> 0
<strong>Explanation:</strong> It can be shown that there are no valid selections.
</pre>



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



<ul class="wp-block-list"><li><code>3 &lt;= s.length &lt;= 10<sup>5</sup></code></li><li><code>s[i]</code>&nbsp;is either&nbsp;<code>'0'</code>&nbsp;or&nbsp;<code>'1'</code>.</li></ul>



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



<p>The brute force solution will take O(n<sup>3</sup>) which will lead to TLE.</p>



<p>Since the only two valid cases are &#8220;010&#8221; and &#8220;101&#8221;.</p>



<p>We just need to count how many 0s and 1s, thus we can count 01s and 10s and finally 010s and 101s.</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:
  long long numberOfWays(string s) {    
    long long c0 = 0, c1 = 0, c01 = 0, c10 = 0, c101 = 0, c010 = 0;
    for (char c : s) {
      if (c == '0') {
        ++c0;
        c10 += c1;
        c010 += c01;
      } else {
        ++c1;
        c01 += c0;
        c101 += c10;
      }
    }
    return c101 + c010;
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2222-number-of-ways-to-select-buildings/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 2218. Maximum Value of K Coins From Piles</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2218-maximum-value-of-k-coins-from-piles/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2218-maximum-value-of-k-coins-from-piles/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Tue, 29 Mar 2022 04:51:27 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[hard]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=9596</guid>

					<description><![CDATA[There are&#160;n&#160;piles&#160;of coins on a table. Each pile consists of a&#160;positive number&#160;of coins of assorted denominations. In one move, you can choose any coin on&#160;top&#160;of&#8230;]]></description>
										<content:encoded><![CDATA[
<p>There are&nbsp;<code>n</code>&nbsp;<strong>piles</strong>&nbsp;of coins on a table. Each pile consists of a&nbsp;<strong>positive number</strong>&nbsp;of coins of assorted denominations.</p>



<p>In one move, you can choose any coin on&nbsp;<strong>top</strong>&nbsp;of any pile, remove it, and add it to your wallet.</p>



<p>Given a list&nbsp;<code>piles</code>, where&nbsp;<code>piles[i]</code>&nbsp;is a list of integers denoting the composition of the&nbsp;<code>i<sup>th</sup></code>&nbsp;pile from&nbsp;<strong>top to bottom</strong>, and a positive integer&nbsp;<code>k</code>, return&nbsp;<em>the&nbsp;<strong>maximum total value</strong>&nbsp;of coins you can have in your wallet if you choose&nbsp;<strong>exactly</strong></em>&nbsp;<code>k</code>&nbsp;<em>coins optimally</em>.</p>



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



<figure class="wp-block-image"><img decoding="async" src="https://assets.leetcode.com/uploads/2019/11/09/e1.png" alt=""/></figure>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> piles = [[1,100,3],[7,8,9]], k = 2
<strong>Output:</strong> 101
<strong>Explanation:</strong>
The above diagram shows the different ways we can choose k coins.
The maximum total we can obtain is 101.
</pre>



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



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> piles = [[100],[100],[100],[100],[100],[100],[1,1,1,1,1,1,700]], k = 7
<strong>Output:</strong> 706
<strong>Explanation:
</strong>The maximum total can be obtained if we choose all coins from the last pile.
</pre>



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



<ul class="wp-block-list"><li><code>n == piles.length</code></li><li><code>1 &lt;= n &lt;= 1000</code></li><li><code>1 &lt;= piles[i][j] &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= k &lt;= sum(piles[i].length) &lt;= 2000</code></li></ul>



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



<p>let dp(i, k) be the maximum value of picking k elements using piles[i:n].</p>



<p>dp(i, k) = max(dp(i + 1, k), sum(piles[i][0~j]) + dp(i + 1, k &#8211; j &#8211; 1)), 0 &lt;= j &lt; len(piles[i])</p>



<p>Time complexity: O(n * m), m = sum(piles[i]) &lt;= 2000<br>Space complexity: O(n * k)</p>



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

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class Solution:
  def maxValueOfCoins(self, piles: List[List[int]], k: int) -&gt; int:
    n = len(piles)
    
    @cache
    def dp(i: int, k: int) -&gt; int:
      &quot;&quot;&quot;Max value of picking k elements using piles[i:n].&quot;&quot;&quot;
      if i == n: return 0
      ans, cur = dp(i + 1, k), 0      
      for j in range(min(len(piles[i]), k)):        
        ans = max(ans, (cur := cur + piles[i][j]) + dp(i + 1, k - j - 1))
      return ans
    
    return dp(0, k)</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-2218-maximum-value-of-k-coins-from-piles/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
