<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>子串 on 奇伏禾</title>
        <link>/tags/%E5%AD%90%E4%B8%B2/</link>
        <description>Recent content in 子串 on 奇伏禾</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <lastBuildDate>Sun, 19 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="/tags/%E5%AD%90%E4%B8%B2/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>子串与子数组模块 — LeetCode 热门 100 题精讲（Java 向）</title>
            <link>/p/substring-subarray-module/</link>
            <pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate>
            <guid>/p/substring-subarray-module/</guid>
            <description>&lt;h2 id=&#34;子串与子数组问题概述&#34;&gt;子串与子数组问题概述&#xA;&lt;/h2&gt;&lt;p&gt;子串（字符串连续片段）与子数组（数组连续片段）在算法题中占据半壁江山。解决此类问题的优化思路通常围绕&amp;quot;消除重复计算&amp;quot;展开，常见工具包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;前缀和 + 哈希表&lt;/strong&gt;：将区间和转化为两前缀和之差，O(1) 查询目标值，典型题如和为 K 的子数组。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;单调队列&lt;/strong&gt;：维护窗口内的极值，在滑动过程中 O(1) 获取最大值/最小值，典型题如滑动窗口最大值。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;双指针滑动窗口&lt;/strong&gt;：动态伸缩窗口，配合状态变量（频次计数）在 O(n) 内求解最短/最长覆盖子串，典型题如最小覆盖子串。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;LeetCode 热门 100 题中，有三道题分别代表了上述三种范式的经典应用：&lt;strong&gt;560. 和为 K 的子数组&lt;/strong&gt;（前缀和+哈希）、&lt;strong&gt;239. 滑动窗口最大值&lt;/strong&gt;（单调队列）、&lt;strong&gt;76. 最小覆盖子串&lt;/strong&gt;（滑动窗口+频次计数）。下面逐一拆解。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-和为-k-的子数组leetcode-560&#34;&gt;1. 和为 K 的子数组（LeetCode 560）&#xA;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;题目&lt;/strong&gt;：给定整数数组 &lt;code&gt;nums&lt;/code&gt; 和整数 &lt;code&gt;k&lt;/code&gt;，统计连续子数组之和等于 &lt;code&gt;k&lt;/code&gt; 的个数。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;暴力法&lt;/strong&gt;：枚举所有子数组 &lt;code&gt;(i, j)&lt;/code&gt;，累加求和并计数，时间复杂度 O(n²)。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;优化思路（前缀和 + 哈希表）&lt;/strong&gt;：&#xA;设前缀和 &lt;code&gt;pre[i] = nums[0] + ... + nums[i]&lt;/code&gt;，则子数组 &lt;code&gt;(j, i]&lt;/code&gt; 的和 = &lt;code&gt;pre[i] - pre[j-1]&lt;/code&gt;。要使其等于 k，等价于 &lt;code&gt;pre[j-1] = pre[i] - k&lt;/code&gt;。因此，在遍历 i 时，只需查找之前出现过多少个前缀和等于 &lt;code&gt;pre[i] - k&lt;/code&gt;，累加计数。用哈希表存储前缀和出现次数，初始放入 &lt;code&gt;{0: 1}&lt;/code&gt; 代表空前缀。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;subarraySum&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; nums, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; k) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Map&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer, Integer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; prefixCount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HashMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    prefixCount.&lt;span style=&#34;color:#a6e22e&#34;&gt;put&lt;/span&gt;(0, 1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; sum &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0, count &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; num : nums) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sum &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; num;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        count &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; prefixCount.&lt;span style=&#34;color:#a6e22e&#34;&gt;getOrDefault&lt;/span&gt;(sum &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; k, 0);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        prefixCount.&lt;span style=&#34;color:#a6e22e&#34;&gt;put&lt;/span&gt;(sum, prefixCount.&lt;span style=&#34;color:#a6e22e&#34;&gt;getOrDefault&lt;/span&gt;(sum, 0) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; count;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;复杂度&lt;/strong&gt;：时间 O(n)，空间 O(n)。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;关键点&lt;/strong&gt;：先查 target 再更新当前前缀和，避免 k=0 时将自身计入；哈希表存储频次而非布尔值，因为可能存在多个相同前缀和。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;2-滑动窗口最大值leetcode-239&#34;&gt;2. 滑动窗口最大值（LeetCode 239）&#xA;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;题目&lt;/strong&gt;：给定数组 &lt;code&gt;nums&lt;/code&gt; 和窗口大小 &lt;code&gt;k&lt;/code&gt;，从左向右滑动窗口，返回每个窗口中的最大值。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;暴力法&lt;/strong&gt;：每个窗口扫描 k 个元素求最大值，总时间复杂度 O(n·k)。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;优化思路（单调队列）&lt;/strong&gt;：&#xA;维护一个双端队列（Deque），其中存储数组下标，且队列中下标对应的元素值 &lt;strong&gt;严格单调递减&lt;/strong&gt;。这样队首始终是当前窗口最大值的下标。窗口滑动时：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;移除队首出界的下标（&lt;code&gt;index &amp;lt; i-k+1&lt;/code&gt;）。&lt;/li&gt;&#xA;&lt;li&gt;从队尾移除所有小于当前元素值的下标（因为它们不可能成为后续窗口的最大值）。&lt;/li&gt;&#xA;&lt;li&gt;将当前下标加入队尾。&lt;/li&gt;&#xA;&lt;li&gt;若窗口已形成（&lt;code&gt;i &amp;gt;= k-1&lt;/code&gt;），队首即为当前窗口最大值。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxSlidingWindow&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; nums, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; k) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (nums.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; k &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nums.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;n &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; k &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Deque&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; deque &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArrayDeque&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; n; i&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;deque.&lt;span style=&#34;color:#a6e22e&#34;&gt;isEmpty&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; deque.&lt;span style=&#34;color:#a6e22e&#34;&gt;peekFirst&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; k &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            deque.&lt;span style=&#34;color:#a6e22e&#34;&gt;pollFirst&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;deque.&lt;span style=&#34;color:#a6e22e&#34;&gt;isEmpty&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; nums&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;deque.&lt;span style=&#34;color:#a6e22e&#34;&gt;peekLast&lt;/span&gt;()&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; nums&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            deque.&lt;span style=&#34;color:#a6e22e&#34;&gt;pollLast&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        deque.&lt;span style=&#34;color:#a6e22e&#34;&gt;offerLast&lt;/span&gt;(i);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; k &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; 1) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            result&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; k &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nums&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;deque.&lt;span style=&#34;color:#a6e22e&#34;&gt;peekFirst&lt;/span&gt;()&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;复杂度&lt;/strong&gt;：每个元素入队出队各一次，时间 O(n)，空间 O(k)。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;关键点&lt;/strong&gt;：队列存储下标便于判断是否出界；单调性确保队首始终最大；新元素从队尾踢掉所有比自己小的元素。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;3-最小覆盖子串leetcode-76&#34;&gt;3. 最小覆盖子串（LeetCode 76）&#xA;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;题目&lt;/strong&gt;：给定字符串 &lt;code&gt;s&lt;/code&gt; 和 &lt;code&gt;t&lt;/code&gt;，在 &lt;code&gt;s&lt;/code&gt; 中找到包含 &lt;code&gt;t&lt;/code&gt; 中所有字符（含重复次数）的最短子串，若不存在返回空串。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;优化思路（滑动窗口 + 频次计数器）&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;用 &lt;code&gt;need&lt;/code&gt; 哈希表记录 t 中每个字符的需求量，用 &lt;code&gt;window&lt;/code&gt; 记录当前窗口内各字符出现次数。&lt;/li&gt;&#xA;&lt;li&gt;用 &lt;code&gt;formed&lt;/code&gt; 记录当前窗口内满足需求（频次 &amp;gt;= need）的 &lt;strong&gt;字符种类数&lt;/strong&gt;，当 &lt;code&gt;formed == need.size()&lt;/code&gt; 时窗口已经覆盖所有字符。&lt;/li&gt;&#xA;&lt;li&gt;右指针 &lt;code&gt;right&lt;/code&gt; 不断右移，加入新字符并更新 &lt;code&gt;window&lt;/code&gt; 和 &lt;code&gt;formed&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;当 &lt;code&gt;formed == required&lt;/code&gt; 时，尝试收缩左指针 &lt;code&gt;left&lt;/code&gt;，在收缩过程中不断更新最小长度和起始位置，同时更新 &lt;code&gt;window&lt;/code&gt; 和 &lt;code&gt;formed&lt;/code&gt;，直到不再满足条件。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;minWindow&lt;/span&gt;(String s, String t) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Map&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Character, Integer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; need &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HashMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Map&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Character, Integer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; window &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HashMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; c : t.&lt;span style=&#34;color:#a6e22e&#34;&gt;toCharArray&lt;/span&gt;()) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        need.&lt;span style=&#34;color:#a6e22e&#34;&gt;put&lt;/span&gt;(c, need.&lt;span style=&#34;color:#a6e22e&#34;&gt;getOrDefault&lt;/span&gt;(c, 0) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; left &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0, right &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; formed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0, required &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; need.&lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; minLen &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Integer.&lt;span style=&#34;color:#a6e22e&#34;&gt;MAX_VALUE&lt;/span&gt;, start &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (right &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; s.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;()) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s.&lt;span style=&#34;color:#a6e22e&#34;&gt;charAt&lt;/span&gt;(right);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        window.&lt;span style=&#34;color:#a6e22e&#34;&gt;put&lt;/span&gt;(c, window.&lt;span style=&#34;color:#a6e22e&#34;&gt;getOrDefault&lt;/span&gt;(c, 0) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (need.&lt;span style=&#34;color:#a6e22e&#34;&gt;containsKey&lt;/span&gt;(c) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; window.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(c).&lt;span style=&#34;color:#a6e22e&#34;&gt;intValue&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; need.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(c).&lt;span style=&#34;color:#a6e22e&#34;&gt;intValue&lt;/span&gt;()) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            formed&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (left &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; right &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; formed &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; required) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            c &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s.&lt;span style=&#34;color:#a6e22e&#34;&gt;charAt&lt;/span&gt;(left);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (right &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; left &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1 &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; minLen) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                minLen &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; right &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; left &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                start &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; left;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            window.&lt;span style=&#34;color:#a6e22e&#34;&gt;put&lt;/span&gt;(c, window.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(c) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; 1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (need.&lt;span style=&#34;color:#a6e22e&#34;&gt;containsKey&lt;/span&gt;(c) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; window.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(c).&lt;span style=&#34;color:#a6e22e&#34;&gt;intValue&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; need.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(c).&lt;span style=&#34;color:#a6e22e&#34;&gt;intValue&lt;/span&gt;()) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                formed&lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            left&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        right&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; minLen &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; Integer.&lt;span style=&#34;color:#a6e22e&#34;&gt;MAX_VALUE&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; : s.&lt;span style=&#34;color:#a6e22e&#34;&gt;substring&lt;/span&gt;(start, start &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; minLen);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;复杂度&lt;/strong&gt;：时间 O(n + m)，空间 O(k)（k 为字符集大小）。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;关键点&lt;/strong&gt;：&lt;code&gt;formed&lt;/code&gt; 记录的是种类数（去重），只有当某个字符的窗口频次 &lt;strong&gt;恰好等于&lt;/strong&gt; 需求频次时才加一，减一同样在恰好小于时发生；收缩时要先更新答案再移出左字符。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;三题对比与启发&#34;&gt;三题对比与启发&#xA;&lt;/h2&gt;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;题目&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;核心技巧&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;数据结构&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;时间复杂度&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;空间复杂度&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;典型特征&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;和为 K 的子数组&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;前缀和 + 哈希表&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;HashMap&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;O(n)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;O(n)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;统计区间和等于目标值的数量&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;滑动窗口最大值&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;单调队列&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Deque&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;O(n)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;O(k)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;维护固定窗口内最值&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;最小覆盖子串&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;双指针滑动窗口 + 频次计数&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;HashMap + 双指针&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;O(n)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;O(k)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;求最短覆盖子串&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;&lt;strong&gt;共同本质&lt;/strong&gt;：三者都利用了某种 &lt;strong&gt;&amp;ldquo;增量维护&amp;rdquo;&lt;/strong&gt; 的思想，在遍历过程中实时更新状态，避免重复计算。前缀和哈希将区间和查询变为差值查询；单调队列在 O(1) 内获取窗口最值；滑动窗口通过双指针和频次计数器动态伸缩。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;不同侧重&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;560：依赖累积和的线性关系，配合哈希表快速查找目标值。&lt;/li&gt;&#xA;&lt;li&gt;239：借助单调性剔除不可能成为答案的元素，保持队列有序。&lt;/li&gt;&#xA;&lt;li&gt;76：利用双指针伸缩窗口，并在满足条件时收缩以寻找最优解。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;总结子串与子数组模块的核心心法&#34;&gt;总结：子串与子数组模块的核心心法&#xA;&lt;/h2&gt;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;&lt;strong&gt;子串/子数组问题的优化核心在于&amp;quot;复用历史信息&amp;quot;。无论是前缀和的累加结果、单调队列维护的极值，还是滑动窗口内的频次状态，都避免了每次重新扫描整个区间。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;解题时的思考路径：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;若问题涉及 &lt;strong&gt;区间求和&lt;/strong&gt; 或 &lt;strong&gt;计数&lt;/strong&gt;，优先考虑前缀和 + 哈希表。&lt;/li&gt;&#xA;&lt;li&gt;若问题涉及 &lt;strong&gt;固定窗口的最值&lt;/strong&gt;，使用单调队列。&lt;/li&gt;&#xA;&lt;li&gt;若问题涉及 &lt;strong&gt;动态窗口的最优覆盖或约束&lt;/strong&gt;，使用双指针滑动窗口，配合状态变量。&lt;/li&gt;&#xA;&lt;li&gt;若上述均不适用，再考虑其他复杂方法（如 DP、分治等）。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;掌握这三道题，你就掌握了数组/字符串子区间问题中最常用的三种优化利器。&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;hr&gt;&#xA;</description>
        </item></channel>
</rss>
