<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>双指针 - 标签 - 豆浆小屋</title><link>https://soybeanmilk.netlify.app/tags/%E5%8F%8C%E6%8C%87%E9%92%88/</link><description>双指针 - 标签 - 豆浆小屋</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.</copyright><lastBuildDate>Tue, 04 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://soybeanmilk.netlify.app/tags/%E5%8F%8C%E6%8C%87%E9%92%88/" rel="self" type="application/rss+xml"/><item><title>Q142 环形链表II</title><link>https://soybeanmilk.netlify.app/q142-%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8ii/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><author><name>作者</name></author><guid>https://soybeanmilk.netlify.app/q142-%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8ii/</guid><description><![CDATA[<blockquote>
<p><strong>题目</strong>：给定一个链表的头节点 <code>head</code>，返回链表开始入环的第一个节点。如果链表无环，返回 <code>null</code>。</p></blockquote>
<h2 id="我的想法" class="headerLink">
    <a href="#%e6%88%91%e7%9a%84%e6%83%b3%e6%b3%95" class="header-mark"></a>1 我的想法</h2><p>最容易踩的坑：以为快慢指针第一次相遇就是答案。<strong>第一次相遇点不是环入口</strong>——相遇后还要从头再走一遍：让 <code>cur</code>（从 head 出发）和 <code>fast</code>（停在相遇点）同步各走 1 步，两者相遇的位置才是环入口。</p>
<h2 id="简要回答" class="headerLink">
    <a href="#%e7%ae%80%e8%a6%81%e5%9b%9e%e7%ad%94" class="header-mark"></a>2 简要回答</h2><ol>
<li>fast 每次 2 步、slow 每次 1 步，若 <code>fast</code> 或 <code>fast-&gt;next</code> 为空 → 无环，返回 null。</li>
<li>第一次 <code>fast == slow</code> → 有环，记下相遇点。</li>
<li><code>cur = head</code>，<code>cur</code> 与 <code>fast</code> 各走 1 步，直到 <code>fast == cur</code> → 返回该节点（环入口）。</li>
</ol>
<ul>
<li>时间复杂度：$O(n)$</li>
<li>空间复杂度：$O(1)$</li>
</ul>
<h2 id="为什么第一次相遇点不是入口" class="headerLink">
    <a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e7%ac%ac%e4%b8%80%e6%ac%a1%e7%9b%b8%e9%81%87%e7%82%b9%e4%b8%8d%e6%98%af%e5%85%a5%e5%8f%a3" class="header-mark"></a>3 为什么第一次相遇点不是入口</h2><p>第一次相遇发生在环内，具体是环内哪个点取决于 <code>a</code> 和 <code>b</code> 的比例，<strong>没有任何规律保证它是入口</strong>。所以第二阶段必须有。</p>
<h2 id="为什么第二轮双指针能在入口相遇" class="headerLink">
    <a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e7%ac%ac%e4%ba%8c%e8%bd%ae%e5%8f%8c%e6%8c%87%e9%92%88%e8%83%bd%e5%9c%a8%e5%85%a5%e5%8f%a3%e7%9b%b8%e9%81%87" class="header-mark"></a>4 为什么第二轮双指针能在入口相遇</h2><p>设 head→环入口距离为 <code>a</code>，环入口→第一次相遇点（沿前进方向）距离为 <code>b</code>，环长为 <code>c</code>。</p>
<p>相遇时（fast 走的路程是 slow 的 2 倍）：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">slow 走：a + b
</span></span><span class="line"><span class="cl">fast 走：2(a + b) = a + b + n·c     （fast 比 slow 多绕了 n 圈）
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">⇒  a + b = n·c
</span></span><span class="line"><span class="cl">⇒  a = n·c - b
</span></span></code></pre></td></tr></table>
</div>
</div><p>含义：</p>
<ul>
<li>从 head 走 <code>a</code> 步 → 到达环入口；</li>
<li>从相遇点走 <code>a</code> 步 → 绕 <code>n</code> 圈后再退 <code>b</code> 步 → 也到达环入口。</li>
</ul>
<p>所以 <code>cur</code>（head 出发）和 <code>fast</code>（相遇点出发）同步各走 1 步，恰好都在走 <code>a</code> 步后到达环入口，相遇。</p>
<h2 id="代码" class="headerLink">
    <a href="#%e4%bb%a3%e7%a0%81" class="header-mark"></a>5 代码</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="k">public</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span> <span class="o">*</span><span class="n">detectCycle</span><span class="p">(</span><span class="n">ListNode</span> <span class="o">*</span><span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ListNode</span><span class="o">*</span> <span class="n">fast</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">ListNode</span><span class="o">*</span> <span class="n">slow</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="p">(</span><span class="n">fast</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="k">nullptr</span><span class="p">;</span>          <span class="c1">// 无环
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>     <span class="c1">// 走 2 步
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="n">slow</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>           <span class="c1">// 走 1 步
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">if</span> <span class="p">(</span><span class="n">fast</span> <span class="o">==</span> <span class="n">slow</span><span class="p">)</span> <span class="p">{</span>          <span class="c1">// 第一次相遇，说明有环
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="n">ListNode</span><span class="o">*</span> <span class="n">cur</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="k">while</span> <span class="p">(</span><span class="n">fast</span> <span class="o">!=</span> <span class="n">cur</span><span class="p">)</span> <span class="p">{</span>    <span class="c1">// 同步走 1 步
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                    <span class="n">cur</span> <span class="o">=</span> <span class="n">cur</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                    <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">cur</span><span class="p">;</span>              <span class="c1">// 环入口
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">nullptr</span><span class="p">;</span>                  <span class="c1">// fast 走到末尾，无环
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>用 <code>1→2→3→4→5→(3)</code>（3 是环入口，环长 3）验证：第一次相遇点在 5，第二阶段从 head 和 5 同步走，在 3 相遇 → 返回 3 ✓。</p>
<h2 id="无环与空指针" class="headerLink">
    <a href="#%e6%97%a0%e7%8e%af%e4%b8%8e%e7%a9%ba%e6%8c%87%e9%92%88" class="header-mark"></a>6 无环与空指针</h2><ul>
<li>无环：<code>fast</code> 先到末尾，<code>fast == nullptr</code> 退出循环，返回 null。</li>
<li>空链表 / 单节点：<code>fast == nullptr</code> 或 <code>fast-&gt;next == nullptr</code>，返回 null。</li>
<li><code>fast-&gt;next-&gt;next</code> 在 <code>fast-&gt;next == nullptr</code> 已排除的前提下是安全的（最多为 null，下一轮循环判断）。</li>
</ul>
<h2 id="易错点" class="headerLink">
    <a href="#%e6%98%93%e9%94%99%e7%82%b9" class="header-mark"></a>7 易错点</h2><ul>
<li><strong>第一次 <code>fast == slow</code> 直接 return 是错的</strong>：那只是环内某个点，不是入口。</li>
<li>第二阶段不需要判空：已确认有环，<code>cur</code> 和 <code>fast</code> 必然相遇。</li>
<li>无环判断必须覆盖 <code>fast == nullptr</code> 和 <code>fast-&gt;next == nullptr</code> 两种。</li>
<li>第一阶段别把 slow 写成走 2 步——快慢都走 2 步永远追不上。</li>
</ul>
]]></description></item><item><title>Q160 链表相交</title><link>https://soybeanmilk.netlify.app/q160-%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><author><name>作者</name></author><guid>https://soybeanmilk.netlify.app/q160-%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4/</guid><description><![CDATA[<blockquote>
<p><strong>题目</strong>：给你两个单链表的头节点 <code>headA</code> 和 <code>headB</code>，找出并返回两个单链表相交的起始节点。如果两个链表没有交点，返回 <code>null</code>。</p></blockquote>
<h2 id="我的想法" class="headerLink">
    <a href="#%e6%88%91%e7%9a%84%e6%83%b3%e6%b3%95" class="header-mark"></a>1 我的想法</h2><p>自己做出来了，但第一版踩了一个坑：提前 <code>return nullptr</code> 的条件写错，导致&quot;长度不等且相交&quot;的用例误判。</p>
<ul>
<li>第一版：<code>(flag1||flag2) &amp;&amp; (cur1==nullptr||cur2==nullptr)</code> → 只要有一个指针换过链，另一个一到 null 就返回 null，提前退出。</li>
<li>修正：改成 <code>(flag1&amp;&amp;flag2)</code>，两个指针都换过链之后，才可能真正没有交点。</li>
</ul>
<p><strong>核心</strong>：双指针各自走完自己的链后切到对方链上，把&quot;长度差&quot;抹平。有交点时两者会在交点相遇；没有交点时两者同时走到 null 退出。<strong>关键：提前 return 的条件必须是 <code>flag1&amp;&amp;flag2</code>，而不是 <code>flag1||flag2</code>。</strong></p>
<h2 id="简要回答" class="headerLink">
    <a href="#%e7%ae%80%e8%a6%81%e5%9b%9e%e7%ad%94" class="header-mark"></a>2 简要回答</h2><ol>
<li><code>cur1</code>、<code>cur2</code> 分别从 <code>headA</code>、<code>headB</code> 出发，同步一次走一个节点。</li>
<li>谁走到 <code>null</code> 就换到另一条链的头部继续走（<code>cur1</code> 走完 A 切到 B，<code>cur2</code> 走完 B 切到 A）。</li>
<li>相遇点就是交点；若最终都变成 null 则无交点，返回 null。</li>
</ol>
<ul>
<li>时间复杂度：$O(n + m)$（n、m 为两链长度，最坏各走两条链）</li>
<li>空间复杂度：$O(1)$</li>
</ul>
<h2 id="为什么换链能抹平长度差" class="headerLink">
    <a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e6%8d%a2%e9%93%be%e8%83%bd%e6%8a%b9%e5%b9%b3%e9%95%bf%e5%ba%a6%e5%b7%ae" class="header-mark"></a>3 为什么&quot;换链&quot;能抹平长度差</h2><p>两条链长度不同时，<code>cur1</code>、<code>cur2</code> 不可能在交点同步相遇。但换链之后：</p>
<ul>
<li><code>cur1</code> 总共走完 <code>lenA + lenB</code> 个节点；</li>
<li><code>cur2</code> 同样总共走完 <code>lenB + lenA</code> 个节点。</li>
</ul>
<p>两者总步数相同，于是：</p>
<ul>
<li><strong>有交点</strong>：在各自总步数到达交点时（差量被抹平）相遇。</li>
<li><strong>无交点</strong>：两者在最后一步<strong>同时</strong>走到 <code>null</code>，<code>cur1 == cur2 == nullptr</code>，循环退出。</li>
</ul>
<h2 id="代码" class="headerLink">
    <a href="#%e4%bb%a3%e7%a0%81" class="header-mark"></a>4 代码</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span> <span class="o">*</span><span class="nf">getIntersectionNode</span><span class="p">(</span><span class="n">ListNode</span> <span class="o">*</span><span class="n">headA</span><span class="p">,</span> <span class="n">ListNode</span> <span class="o">*</span><span class="n">headB</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">headA</span> <span class="o">==</span> <span class="k">nullptr</span> <span class="o">||</span> <span class="n">headB</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">nullptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span> <span class="n">cur1</span> <span class="o">=</span> <span class="n">headA</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span> <span class="n">cur2</span> <span class="o">=</span> <span class="n">headB</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">flag1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">flag2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">cur1</span> <span class="o">!=</span> <span class="n">cur2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">cur1</span> <span class="o">=</span> <span class="n">cur1</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">cur2</span> <span class="o">=</span> <span class="n">cur2</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">((</span><span class="n">flag1</span> <span class="o">&amp;&amp;</span> <span class="n">flag2</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">cur1</span> <span class="o">==</span> <span class="k">nullptr</span> <span class="o">||</span> <span class="n">cur2</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">nullptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">cur1</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">cur1</span> <span class="o">=</span> <span class="n">headB</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">flag2</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">cur2</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">cur2</span> <span class="o">=</span> <span class="n">headA</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">flag1</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">cur1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="更简洁的等价写法" class="headerLink">
    <a href="#%e6%9b%b4%e7%ae%80%e6%b4%81%e7%9a%84%e7%ad%89%e4%bb%b7%e5%86%99%e6%b3%95" class="header-mark"></a>5 更简洁的等价写法</h2><p>不需要 flag，利用&quot;换链 + 循环退出条件&quot;本身就覆盖了无交点的情况：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span> <span class="o">*</span><span class="nf">getIntersectionNode</span><span class="p">(</span><span class="n">ListNode</span> <span class="o">*</span><span class="n">headA</span><span class="p">,</span> <span class="n">ListNode</span> <span class="o">*</span><span class="n">headB</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span> <span class="n">cur1</span> <span class="o">=</span> <span class="n">headA</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span> <span class="n">cur2</span> <span class="o">=</span> <span class="n">headB</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">cur1</span> <span class="o">!=</span> <span class="n">cur2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">cur1</span> <span class="o">=</span> <span class="n">cur1</span> <span class="o">?</span> <span class="n">cur1</span><span class="o">-&gt;</span><span class="nl">next</span> <span class="p">:</span> <span class="n">headB</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">cur2</span> <span class="o">=</span> <span class="n">cur2</span> <span class="o">?</span> <span class="n">cur2</span><span class="o">-&gt;</span><span class="nl">next</span> <span class="p">:</span> <span class="n">headA</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">cur1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>无交点时两个指针同时变为 <code>null</code>，<code>while</code> 退出返回 <code>null</code>，天然正确。</li>
<li>空链也能安全处理：<code>cur1 ? ...</code> 不会对 <code>null</code> 解引用，也就不需要开头的空链判断。</li>
<li>注意：两个版本都只保证&quot;相遇或同时为 null&quot;，不能提前在某一个为 null 时就断定无交点。</li>
</ul>
<h2 id="易错点" class="headerLink">
    <a href="#%e6%98%93%e9%94%99%e7%82%b9" class="header-mark"></a>6 易错点</h2><ul>
<li>提前 return 的条件写错是最容易犯的错：<code>flag1||flag2</code> 会在&quot;长度不等且相交&quot;时提前返回 null（先走完的那条链先到 null，但另一个指针还差几步，交点还没走到）。</li>
<li>换成 <code>flag1&amp;&amp;flag2</code> 后，两个指针都换过链，才开始判断 null；且两指针总步数相同，会同时为 null，判断是安全的。</li>
<li>flag 命名容易混淆：这里 <code>flag1</code> 实际记录的是&quot;cur2 换链&quot;，<code>flag2</code> 记录的是&quot;cur1 换链&quot;，阅读时要当心。</li>
<li>直接对 <code>null</code> 解引用 <code>cur1-&gt;next</code> 会段错误：若用带 flag 的写法，务必在开头判空；用三元写法则天然安全。</li>
</ul>
]]></description></item><item><title>Q19 删除链表的倒数第N个节点</title><link>https://soybeanmilk.netlify.app/q19-%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACn%E4%B8%AA%E8%8A%82%E7%82%B9/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><author><name>作者</name></author><guid>https://soybeanmilk.netlify.app/q19-%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACn%E4%B8%AA%E8%8A%82%E7%82%B9/</guid><description><![CDATA[<blockquote>
<p><strong>题目</strong>：给你一个链表，删除链表的倒数第 n 个结点，并且返回链表的头结点。</p></blockquote>
<blockquote>
<p><strong>我的想法</strong>
自己独立做出来了。过程中解决了两个疑问：</p>
<ul>
<li>fast 先走会不会越界？模拟后确认不会——fast 恰好走到 nullptr 这个合法终点就停。</li>
<li>删除后 return 不好 return？因为头可能被删，答案必须从 dummy-&gt;next 拿；而且顺序是：先重接、再删除；先读答案、再删 dummy。</li>
</ul></blockquote>
<blockquote>
<p><strong>这篇笔记的核心</strong>
虚拟头 + 快慢指针：fast 先走 n+1 步，再快慢一起走，slow 正好停在&quot;目标节点的前驱&quot;。删除顺序：<strong>先重接，再删除；先读答案，再删 dummy。</strong></p></blockquote>
<h2 id="简要回答" class="headerLink">
    <a href="#%e7%ae%80%e8%a6%81%e5%9b%9e%e7%ad%94" class="header-mark"></a>1 简要回答</h2><ol>
<li><code>fast</code> 从 dummy 出发先走 n+1 步。</li>
<li><code>fast</code>、<code>slow</code> 一起走，直到 <code>fast == nullptr</code>。此时 <code>slow</code> 是倒数第 n 个节点的前驱。</li>
<li>重接链表、删除目标节点，返回 <code>dummy-&gt;next</code>。</li>
</ol>
<ul>
<li>时间复杂度 $O(n)$，空间复杂度 $O(1)$。</li>
</ul>
<h2 id="详细回答" class="headerLink">
    <a href="#%e8%af%a6%e7%bb%86%e5%9b%9e%e7%ad%94" class="header-mark"></a>2 详细回答</h2><h3 id="为什么-fast-先走-n1-步不会越界" class="headerLink">
    <a href="#%e4%b8%ba%e4%bb%80%e4%b9%88-fast-%e5%85%88%e8%b5%b0-n1-%e6%ad%a5%e4%b8%8d%e4%bc%9a%e8%b6%8a%e7%95%8c" class="header-mark"></a>2.1 为什么 fast 先走 n+1 步不会越界</h3><p>假设链表长度是 L，n 最大等于 L。从 dummy 出发走 n+1 步，最多走 L+1 步：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dummy(0) → 1(1) → 2(2) → … → nodeL(L) → nullptr(L+1)
</span></span></code></pre></td></tr></table>
</div>
</div><p>最后一步是在 nodeL 上执行 <code>fast = fast-&gt;next</code>，结果是 nullptr——<strong>nullptr 是合法终点，不是越界</strong>。真正的越界只发生在对 nullptr 解引用时（比如 fast 已经是 nullptr 还写 <code>fast-&gt;next</code>）。只要步数设计成&quot;恰好停在 nullptr&quot;，并且后续循环先检查 <code>fast != nullptr</code>，就不会崩。</p>
<h3 id="代码" class="headerLink">
    <a href="#%e4%bb%a3%e7%a0%81" class="header-mark"></a>2.2 代码</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">removeNthFromEnd</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">dummy</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ListNode</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">head</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">fast</span> <span class="o">=</span> <span class="n">dummy</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">slow</span> <span class="o">=</span> <span class="n">dummy</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>   <span class="c1">// fast 先走 n+1 步
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">fast</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>        <span class="c1">// 快慢一起走
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">slow</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 现在 slow 是目标节点的前驱
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">ListNode</span><span class="o">*</span> <span class="n">target</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>   <span class="c1">// ① 记住要删的节点
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>   <span class="c1">// ② 先重接链表（摘下来）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">delete</span> <span class="n">target</span><span class="p">;</span>                   <span class="c1">// ③ 再删除目标
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">result</span> <span class="o">=</span> <span class="n">dummy</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>  <span class="c1">// ④ 先读答案
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">delete</span> <span class="n">dummy</span><span class="p">;</span>                    <span class="c1">// ⑤ 再删 dummy（可选）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="我的实现验证通过" class="headerLink">
    <a href="#%e6%88%91%e7%9a%84%e5%ae%9e%e7%8e%b0%e9%aa%8c%e8%af%81%e9%80%9a%e8%bf%87" class="header-mark"></a>2.3 我的实现（验证通过）</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">removeNthFromEnd</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">dummyhead</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ListNode</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">head</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">fast</span> <span class="o">=</span> <span class="n">dummyhead</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">slow</span> <span class="o">=</span> <span class="n">dummyhead</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>                 <span class="c1">// 先手动走 1 步
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>      <span class="c1">// 再走 n 步，合计 n+1 步
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">fast</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">slow</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">auto</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">delete</span> <span class="n">temp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">dummyhead</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>和标准写法等价：手动 <code>fast = fast-&gt;next</code> + for 循环 n 步 = 从 dummy 一共走 n+1 步。</li>
<li>没 <code>delete dummyhead</code> 也没关系（LeetCode 不检查泄漏）；如果要删，先 <code>result = dummyhead-&gt;next</code> 再删。</li>
</ul>
<h3 id="删除与返回的顺序我卡过的地方" class="headerLink">
    <a href="#%e5%88%a0%e9%99%a4%e4%b8%8e%e8%bf%94%e5%9b%9e%e7%9a%84%e9%a1%ba%e5%ba%8f%e6%88%91%e5%8d%a1%e8%bf%87%e7%9a%84%e5%9c%b0%e6%96%b9" class="header-mark"></a>2.4 删除与返回的顺序（我卡过的地方）</h3><ul>
<li><strong>先重接，再删除</strong>：必须先把 <code>slow-&gt;next</code> 指向目标的下一个，目标才能从链表里摘下来；先 <code>delete target</code> 的话，链表还挂着指向已释放内存的指针 → use-after-free（之前见过的 ASan 报错）。</li>
<li><strong>先读答案，再删 dummy</strong>：<code>result = dummy-&gt;next</code> 必须在 <code>delete dummy</code> 之前；顺序反了就是读已释放内存。不删 dummy 也不会错（LeetCode 不检查泄漏），删了是好习惯。</li>
<li><strong>为什么答案从 dummy-&gt;next 拿</strong>：当 n == 链表长度时，删除的是原头节点，<code>head</code> 指向的节点已经没了；而 <code>dummy-&gt;next</code> 在重接时自动更新成新头，所以它永远是&quot;当前真实头&quot;。</li>
</ul>
<h2 id="知识扩展" class="headerLink">
    <a href="#%e7%9f%a5%e8%af%86%e6%89%a9%e5%b1%95" class="header-mark"></a>3 知识扩展</h2><blockquote>
<p><strong>易错点</strong></p>
<ul>
<li>删除目标节点前，必须先重接链表。</li>
<li>n 等于链表长度时，删的是头：此时 <code>slow</code> 就是 dummy，<code>dummy-&gt;next</code> 自动变成原第二个节点。</li>
<li>先走 n 步还是 n+1 步，取决于循环条件：n+1 步 + <code>while (fast)</code> 和 n 步 + <code>while (fast-&gt;next)</code> 等价，选一种记熟。</li>
<li>空链表（head 为 null）时循环条件要能安全退出。</li>
</ul></blockquote>
<h3 id="相关笔记" class="headerLink">
    <a href="#%e7%9b%b8%e5%85%b3%e7%ac%94%e8%ae%b0" class="header-mark"></a>3.1 相关笔记</h3><ul>
<li><a href="/posts/q206-%e5%8f%8d%e8%bd%ac%e9%93%be%e8%a1%a8/" rel="">Q206 反转链表</a>（dummy 的用法）</li>
<li><a href="/posts/q24-%e4%b8%a4%e4%b8%a4%e4%ba%a4%e6%8d%a2%e9%93%be%e8%a1%a8%e4%b8%ad%e7%9a%84%e8%8a%82%e7%82%b9/" rel="">Q24 两两交换链表中的节点</a>（先重接再删除/交换）</li>
<li><a href="/posts/%e7%a9%ba%e6%8c%87%e9%92%88%e4%b8%8e%e8%99%9a%e6%8b%9f%e5%a4%b4%e8%8a%82%e7%82%b9/" rel="">空指针与虚拟头节点</a>（dummy 站岗，dummy-&gt;next 交卷）</li>
<li><a href="/posts/%e6%8c%87%e9%92%88%e4%ba%a4%e6%8e%a5%e7%9e%ac%e9%97%b4/" rel="">指针交接瞬间</a>（改指针前先防断链）</li>
<li>链表常用操作总结</li>
</ul>
<h3 id="自测" class="headerLink">
    <a href="#%e8%87%aa%e6%b5%8b" class="header-mark"></a>3.2 自测</h3><ul>
<li><i class="far fa-square fa-fw"></i> 能解释 fast 先走 n+1 步为什么不会越界</li>
<li><i class="far fa-square fa-fw"></i> 能说出删除三步的顺序：记住目标 → 重接 → 删除</li>
<li><i class="far fa-square fa-fw"></i> 能解释为什么答案必须从 dummy-&gt;next 拿</li>
<li><i class="far fa-square fa-fw"></i> 能说出 n == 链表长度时，slow 停在哪里</li>
<li><i class="far fa-square fa-fw"></i> 手写一遍完整代码</li>
</ul>
]]></description></item><item><title>Q206 反转链表</title><link>https://soybeanmilk.netlify.app/q206-%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><author><name>作者</name></author><guid>https://soybeanmilk.netlify.app/q206-%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8/</guid><description><![CDATA[<blockquote>
<p><strong>题目</strong>：给你单链表的头节点 <code>head</code>，请你反转链表，并返回反转后的链表。输入：<code>1 → 2 → 3 → 4 → 5</code>，输出：<code>5 → 4 → 3 → 2 → 1</code>。</p></blockquote>
<h2 id="简要回答" class="headerLink">
    <a href="#%e7%ae%80%e8%a6%81%e5%9b%9e%e7%ad%94" class="header-mark"></a>1 简要回答</h2><p>递归版把问题拆成两步：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">反转 1→2→3→4
</span></span><span class="line"><span class="cl">= 先反转 2→3→4（得到 4→3→2），再把 1 接到 2 的后面
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>每次递归返回：<strong>反转后链表的头节点</strong>（也就是原链表的尾节点，全程不变）。</li>
<li>自己这一层只做两件事：<code>head-&gt;next-&gt;next = head</code>（把原后继反过来指向自己）、<code>head-&gt;next = nullptr</code>（断开旧指针，防止成环）。</li>
<li>时间复杂度 $O(n)$，空间复杂度 $O(n)$（递归栈深度）。</li>
</ul>
<h2 id="递归三步法把它当成数学归纳法" class="headerLink">
    <a href="#%e9%80%92%e5%bd%92%e4%b8%89%e6%ad%a5%e6%b3%95%e6%8a%8a%e5%ae%83%e5%bd%93%e6%88%90%e6%95%b0%e5%ad%a6%e5%bd%92%e7%ba%b3%e6%b3%95" class="header-mark"></a>2 递归三步法：把它当成数学归纳法</h2><ol>
<li><strong>基例</strong>：空链表或只有一个节点，反转后还是它自己，直接返回。</li>
<li><strong>假设子问题已解决</strong>：<code>reverseList(head-&gt;next)</code> 返回的 <code>last</code>，就是 <code>head</code> 后面那段链表反转后的新头。</li>
<li><strong>只处理自己</strong>：把 <code>head</code> 挂到新链表末尾，并断开原来的 <code>next</code>。</li>
</ol>
<p>关键是第 2 步的&quot;信任&quot;。递归不是让你跟踪每一层调用，而是假设&quot;更短的链表已经被别人正确反转好了&quot;。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">reverseList</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">head</span> <span class="o">==</span> <span class="k">nullptr</span> <span class="o">||</span> <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">head</span><span class="p">;</span>                          <span class="c1">// 基例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">last</span> <span class="o">=</span> <span class="n">reverseList</span><span class="p">(</span><span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">);</span> <span class="c1">// 假设后面已经反转好
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>                  <span class="c1">// 把自己挂到末尾
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="k">nullptr</span><span class="p">;</span>                     <span class="c1">// 断开旧指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="n">last</span><span class="p">;</span>                              <span class="c1">// 新头始终不变
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="为什么-head-next-next--head-就完成了挂到末尾" class="headerLink">
    <a href="#%e4%b8%ba%e4%bb%80%e4%b9%88-head-next-next--head-%e5%b0%b1%e5%ae%8c%e6%88%90%e4%ba%86%e6%8c%82%e5%88%b0%e6%9c%ab%e5%b0%be" class="header-mark"></a>2.1 为什么 head-&gt;next-&gt;next = head 就完成了&quot;挂到末尾&quot;</h3><p>递归返回后，<code>head-&gt;next</code> 仍然是原来的后继节点，但它已经变成<strong>反转后子链表的最后一个节点</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">反转前：          head → head-&gt;next → ... → last
</span></span><span class="line"><span class="cl">调用后（还没处理 head 时）：
</span></span><span class="line"><span class="cl">                  head → (4 → 3 → 2)        ← head-&gt;next 现在指向 2，正好是子链表尾巴
</span></span></code></pre></td></tr></table>
</div>
</div><p>所以 <code>head-&gt;next-&gt;next = head</code> 的意思是：&ldquo;让子链表的尾巴再指向我&rdquo;，于是 <code>head</code> 就被接到了末尾。</p>
<h3 id="完整回溯过程1--2--3--4" class="headerLink">
    <a href="#%e5%ae%8c%e6%95%b4%e5%9b%9e%e6%ba%af%e8%bf%87%e7%a8%8b1--2--3--4" class="header-mark"></a>2.2 完整回溯过程（1 → 2 → 3 → 4）</h3><p>递归先一路走到 <code>4</code>，返回 <code>4</code>（基例）。然后从 <code>3</code> 开始逐层往回处理：</p>
<table>
  <thead>
      <tr>
          <th>层</th>
          <th>执行前</th>
          <th>执行 <code>head-&gt;next-&gt;next = head</code></th>
          <th>再执行 <code>head-&gt;next = nullptr</code></th>
          <th>返回</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>head=3</td>
          <td><code>1→2→3→4→∅</code></td>
          <td><code>1→2→3→4→3</code>（暂时成环）</td>
          <td><code>1→2→3→∅</code>，<code>4→3</code></td>
          <td><code>4</code></td>
      </tr>
      <tr>
          <td>head=2</td>
          <td><code>1→2→3→∅</code>，<code>4→3</code></td>
          <td><code>1→2→3→2</code>（暂时成环）</td>
          <td><code>1→2→∅</code>，<code>4→3→2</code></td>
          <td><code>4</code></td>
      </tr>
      <tr>
          <td>head=1</td>
          <td><code>1→2→∅</code>，<code>4→3→2</code></td>
          <td><code>1→2→1</code>（暂时成环）</td>
          <td><code>1→∅</code>，<code>4→3→2→1</code></td>
          <td><code>4</code></td>
      </tr>
  </tbody>
</table>
<p>最终：<code>4→3→2→1→∅</code>，返回的 <code>last</code> 一直是 <code>4</code>。</p>
<p>关键直觉：<strong>每个节点在回溯时只做一件小事</strong>——&ldquo;让后面的节点指回我，然后我断掉旧指针&rdquo;。所有节点都做完，整条链就反过来了。</p>
<h2 id="迭代版对照组" class="headerLink">
    <a href="#%e8%bf%ad%e4%bb%a3%e7%89%88%e5%af%b9%e7%85%a7%e7%bb%84" class="header-mark"></a>3 迭代版（对照组）</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">reverseList</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">pre</span> <span class="o">=</span> <span class="k">nullptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">cur</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">cur</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ListNode</span><span class="o">*</span> <span class="n">next</span> <span class="o">=</span> <span class="n">cur</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>  <span class="c1">// 先保存下一个，防止断链
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">cur</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">pre</span><span class="p">;</span>             <span class="c1">// 反转当前指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">pre</span> <span class="o">=</span> <span class="n">cur</span><span class="p">;</span>                   <span class="c1">// pre 前进
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">cur</span> <span class="o">=</span> <span class="n">next</span><span class="p">;</span>                  <span class="c1">// cur 前进
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">pre</span><span class="p">;</span>                      <span class="c1">// 结束时 pre 是原链表尾，即新链表头
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>迭代版是&quot;从前往后&quot;逐条改箭头；递归版是&quot;从后往前&quot;逐层改箭头，顺序正好相反。</p>
<h2 id="双指针改递归不靠想象靠机械改写" class="headerLink">
    <a href="#%e5%8f%8c%e6%8c%87%e9%92%88%e6%94%b9%e9%80%92%e5%bd%92%e4%b8%8d%e9%9d%a0%e6%83%b3%e8%b1%a1%e9%9d%a0%e6%9c%ba%e6%a2%b0%e6%94%b9%e5%86%99" class="header-mark"></a>4 双指针改递归：不靠想象，靠机械改写</h2><p>如果&quot;信任&quot;递归有困难，别急着理解经典版。把迭代版机械改写成递归，两者完全等价，每一步都摊在明面上。</p>
<p>改写只有四条规则：</p>
<table>
  <thead>
      <tr>
          <th>迭代里的东西</th>
          <th>改写成</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>循环变量 <code>pre</code>、<code>cur</code></td>
          <td>函数参数 <code>reverse(pre, cur)</code></td>
      </tr>
      <tr>
          <td>循环条件 <code>cur != nullptr</code></td>
          <td>开头 <code>if (cur == nullptr) return pre;</code></td>
      </tr>
      <tr>
          <td>循环体</td>
          <td>原样搬进函数体</td>
      </tr>
      <tr>
          <td>循环末尾 <code>pre = cur; cur = temp;</code></td>
          <td>递归调用 <code>return reverse(cur, temp);</code></td>
      </tr>
  </tbody>
</table>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">reverse</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">pre</span><span class="p">,</span> <span class="n">ListNode</span><span class="o">*</span> <span class="n">cur</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">cur</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span> <span class="k">return</span> <span class="n">pre</span><span class="p">;</span>      <span class="c1">// 循环退出条件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">ListNode</span><span class="o">*</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">cur</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>          <span class="c1">// 保存下一个，防止断链
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">cur</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">pre</span><span class="p">;</span>                     <span class="c1">// 反转当前指针
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="n">reverse</span><span class="p">(</span><span class="n">cur</span><span class="p">,</span> <span class="n">temp</span><span class="p">);</span>           <span class="c1">// 相当于 pre = cur; cur = temp; 进入下一轮
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">reverseList</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">reverse</span><span class="p">(</span><span class="k">nullptr</span><span class="p">,</span> <span class="n">head</span><span class="p">);</span>       <span class="c1">// 相当于 pre = nullptr; cur = head;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>把它展开看，就是一串循环：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">reverse(NULL, 1) → reverse(1, 2) → reverse(2, 3) → reverse(3, 4) → reverse(4, NULL)
</span></span></code></pre></td></tr></table>
</div>
</div><p>最后一层 <code>cur == NULL</code> 返回 <code>pre</code>（就是 4），一路原样传回，和迭代版 <code>return pre</code> 完全一致。</p>
<blockquote>
<p>信任的本质：递归不需要你&quot;想象&quot;全过程，只需要验证两件事——<strong>基例对不对</strong>（空链表或最后一个节点返回正确），<strong>当前层在子问题正确的假设下对不对</strong>。两个都验证过，递归就永远正确。</p>
<p>经典版里 <code>reverseList(head-&gt;next)</code> 返回的 <code>last</code>，就是&quot;循环跑完时的 <code>pre</code>&quot;，全程不变。</p></blockquote>
<h2 id="虚拟头--头插法把每个节点变成同一种节点" class="headerLink">
    <a href="#%e8%99%9a%e6%8b%9f%e5%a4%b4--%e5%a4%b4%e6%8f%92%e6%b3%95%e6%8a%8a%e6%af%8f%e4%b8%aa%e8%8a%82%e7%82%b9%e5%8f%98%e6%88%90%e5%90%8c%e4%b8%80%e7%a7%8d%e8%8a%82%e7%82%b9" class="header-mark"></a>5 虚拟头 + 头插法：把每个节点变成同一种节点</h2><p>加一个虚拟头 dummy，每次把当前节点插到 dummy 后面（头插），所有节点的操作完全一样，不用特判头节点：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">reverseList</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">dummy</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ListNode</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">head</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ListNode</span><span class="o">*</span> <span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>   <span class="c1">// 保存下一个，防止断链
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">dummy</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>      <span class="c1">// 把当前节点插到 dummy 后面
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">dummy</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">head</span> <span class="o">=</span> <span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">dummy</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>                <span class="c1">// dummy 站岗，dummy-&gt;next 交卷
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>用 <code>1→2→3</code> 走一遍：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dummy → 1              （插 1）
</span></span><span class="line"><span class="cl">dummy → 2 → 1          （插 2）
</span></span><span class="line"><span class="cl">dummy → 3 → 2 → 1      （插 3）
</span></span><span class="line"><span class="cl">返回 3 → 2 → 1
</span></span></code></pre></td></tr></table>
</div>
</div><p>和 <code>pre = nullptr</code> 的写法是同一个思想：nullptr/虚拟头让&quot;第一个节点&quot;也被统一处理。这套头插法也是反转区间、K 个一组反转的基础。</p>
<blockquote>
<p>易错：② 让新节点先接住&quot;当前最前面的节点&quot;（已反转的那段链），③ 才把新节点放到最前面。顺序不能反：先 ③ 后 ② 会让新节点的 <code>next</code> 指向自己，成环。规则和&quot;改指针前先保存/接好后面的链&quot;是同一个——<strong>先接后面，再改前面</strong>。</p></blockquote>
<h2 id="易错点" class="headerLink">
    <a href="#%e6%98%93%e9%94%99%e7%82%b9" class="header-mark"></a>6 易错点</h2><ul>
<li>忘记 <code>head-&gt;next = nullptr</code>：<code>1→2→1</code> 会成环，遍历直接死循环。<code>head-&gt;next-&gt;next = head;</code> 和 <code>head-&gt;next = nullptr;</code> 必须成对出现。</li>
<li>返回了 <code>head</code> 而不是 <code>last</code>：会得到&quot;局部反转 + 后半段丢失&quot;的错链。</li>
<li>基例只写 <code>head == nullptr</code> 不够：单节点链表也要直接返回，否则 <code>head-&gt;next-&gt;next</code> 会解引用空指针。</li>
<li>链表很长（如 $10^5$ 级）时递归会爆栈，工程上优先用迭代。</li>
</ul>
<h3 id="遇到-addresssanitizer-heap-use-after-free-怎么定位" class="headerLink">
    <a href="#%e9%81%87%e5%88%b0-addresssanitizer-heap-use-after-free-%e6%80%8e%e4%b9%88%e5%ae%9a%e4%bd%8d" class="header-mark"></a>6.1 遇到 <code>AddressSanitizer: heap-use-after-free</code> 怎么定位</h3><p>LeetCode 判题器跑完你的代码后会释放链表（<code>freeList</code>）。如果反转后的链表里有环，<code>freeList</code> 会先删掉某个节点，稍后又从环的另一条路走到这个<strong>已经删除</strong>的节点——于是报 <code>heap-use-after-free</code>（读到了已释放的内存）。</p>
<p>读报错三步：</p>
<ol>
<li>看错误类型和位置：<code>heap-use-after-free</code> + 出错函数是 <code>freeList</code> → 不是你的代码当场崩，而是<strong>返回的链表结构坏了</strong>。</li>
<li>想 <code>freeList</code> 怎么写的：<code>while (head) { next = head-&gt;next; delete head; head = next; }</code>——它会读 <code>head-&gt;next</code>，只有链表<strong>成环</strong>（或一个节点被两条链指着）才会读到已删除节点的 <code>next</code>。</li>
<li>回代码找&quot;谁可能制造环&quot;：反转链表里制造反向指针的是 <code>head-&gt;next-&gt;next = head</code>，如果不同时 <code>head-&gt;next = nullptr</code>，就成了 <code>1→2→1</code> 的环。</li>
</ol>
<blockquote>
<p>细节：报错里的 <code>16-byte region</code> 正好是一个 <code>ListNode</code>（<code>val</code> + <code>next</code> 各 8 字节），<code>READ of size 8</code> 读的正是 <code>next</code> 指针。这些信息都在印证：freeList 走到一个被删过的节点上了。</p></blockquote>
<p>自查方法：本地打印反转后的链表，最多走 $n+1$ 步；如果没遇到 <code>nullptr</code> 还在走，就是环。</p>
]]></description></item><item><title>Q24 两两交换链表中的节点</title><link>https://soybeanmilk.netlify.app/q24-%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><author><name>作者</name></author><guid>https://soybeanmilk.netlify.app/q24-%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9/</guid><description><![CDATA[<blockquote>
<p><strong>题目</strong>：给定一个链表，两两交换其中相邻的节点，并返回交换后的链表。不能只改节点内部的值，必须实际交换节点。输入：<code>1 → 2 → 3 → 4</code>，输出：<code>2 → 1 → 4 → 3</code>。</p></blockquote>
<h2 id="我的想法" class="headerLink">
    <a href="#%e6%88%91%e7%9a%84%e6%83%b3%e6%b3%95" class="header-mark"></a>1 我的想法</h2><p>想写一个函数：接受一个起点，把后面的两个节点&quot;翻转&quot;一下。第一次草稿卡在：</p>
<ul>
<li><code>while()</code> 空条件、<code>x</code> 未定义，编译不过；</li>
<li>更关键的是：交换完一对之后，不知道这一对怎么接回前面的链、怎么连到下一对；</li>
<li>于是用 <code>flag</code>、<code>heade</code> 去补，越补越乱。</li>
</ul>
<p><strong>核心</strong>：两两交换 = 每次处理&quot;一对&quot;，但必须记住<strong>这一对的前一个节点 <code>prev</code></strong>，否则交换完接不回去。用虚拟头 dummy 统一第一对。</p>
<h2 id="简要回答" class="headerLink">
    <a href="#%e7%ae%80%e8%a6%81%e5%9b%9e%e7%ad%94" class="header-mark"></a>2 简要回答</h2><p>用虚拟头节点 <code>dummy</code>，维护指针 <code>prev</code>（当前这一对的前一个节点）。每一轮：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">prev -&gt; a -&gt; b -&gt; rest     交换成     prev -&gt; b -&gt; a -&gt; rest
</span></span></code></pre></td></tr></table>
</div>
</div><p>然后 <code>prev</code> 跳到 <code>a</code>（这一对的新尾巴），继续处理下一对。</p>
<ul>
<li>时间复杂度 $O(n)$</li>
<li>空间复杂度 $O(1)$（迭代版；递归版为 $O(n)$ 栈空间）</li>
</ul>
<h2 id="为什么需要-prev" class="headerLink">
    <a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81-prev" class="header-mark"></a>3 为什么需要 prev</h2><p>只交换 a、b 本身不难（<code>a-&gt;next = b-&gt;next; b-&gt;next = a;</code>），难的是<strong>把这一对接回前面的链</strong>。交换完成后，前面的链还指着原来的 a，必须把它的 <code>next</code> 改成 b——所以必须提前握着&quot;这一对的前一个节点&quot;。</p>
<p>这正好呼应&quot;写一个函数接受起点&quot;的想法：函数参数不应该是这一对的第一个节点，而应该是<strong>这一对的前一个节点</strong>。</p>
<h2 id="虚拟头到底是不是必须的" class="headerLink">
    <a href="#%e8%99%9a%e6%8b%9f%e5%a4%b4%e5%88%b0%e5%ba%95%e6%98%af%e4%b8%8d%e6%98%af%e5%bf%85%e9%a1%bb%e7%9a%84" class="header-mark"></a>4 虚拟头到底是不是&quot;必须&quot;的</h2><p>不是必须的，它是把&quot;头节点特判&quot;变成&quot;统一处理&quot;的技巧。头节点特殊在：<strong>它没有前驱</strong>。凡是&quot;通过前一个节点操作&quot;的写法，头节点都没有前一个可用。</p>
<p>什么时候可以用 <code>nullptr</code> 当虚拟头，什么时候必须 <code>new</code> 一个真节点，看一件事——<strong>你要不要通过它修改 next</strong>：</p>
<table>
  <thead>
      <tr>
          <th>场景</th>
          <th>能不能用 nullptr</th>
          <th>原因</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>反转链表：只读 pre（<code>cur-&gt;next = pre</code>）</td>
          <td>可以</td>
          <td>只是把 pre 的值赋给别人，pre 本身不参与修改</td>
      </tr>
      <tr>
          <td>两两交换 / 删除节点：要写 prev-&gt;next（<code>prev-&gt;next = b</code>）</td>
          <td>不行</td>
          <td><code>nullptr-&gt;next</code> 没法赋值，前一个节点必须真实存在</td>
      </tr>
  </tbody>
</table>
<p>不引入 dummy 也能写 swapPairs，但第一对要单独特判：先手动交换 <code>head</code> 和 <code>head-&gt;next</code>，再进循环处理后面的对——多一段代码，多一个出错点。dummy 让第一对也走同一个 <code>swapTwo</code>，特殊 case 直接消失。</p>
<h2 id="核心代码" class="headerLink">
    <a href="#%e6%a0%b8%e5%bf%83%e4%bb%a3%e7%a0%81" class="header-mark"></a>5 核心代码</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// 交换 prev 后面的两个节点
</span></span></span><span class="line"><span class="cl"><span class="c1">// 调用前：prev -&gt; a -&gt; b -&gt; rest
</span></span></span><span class="line"><span class="cl"><span class="c1">// 调用后：prev -&gt; b -&gt; a -&gt; rest
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">swapTwo</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">prev</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">a</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">b</span> <span class="o">=</span> <span class="n">a</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">a</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">b</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>      <span class="c1">// a 先接到 rest
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">b</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">a</span><span class="p">;</span>            <span class="c1">// b 指回 a
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">prev</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">b</span><span class="p">;</span>         <span class="c1">// 前面的链接上 b
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">swapPairs</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span><span class="o">*</span> <span class="n">dummy</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ListNode</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">head</span><span class="p">);</span>  <span class="c1">// 虚拟头，让第一对也有 prev
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">ListNode</span><span class="o">*</span> <span class="n">prev</span> <span class="o">=</span> <span class="n">dummy</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">prev</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">!=</span> <span class="k">nullptr</span> <span class="o">&amp;&amp;</span> <span class="n">prev</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">swapTwo</span><span class="p">(</span><span class="n">prev</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">prev</span> <span class="o">=</span> <span class="n">prev</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>   <span class="c1">// 下一对的前一个节点 = a
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">dummy</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>用 <code>1→2→3→4</code> 走一遍：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dummy -&gt; 1 -&gt; 2 -&gt; 3 -&gt; 4
</span></span><span class="line"><span class="cl">第 1 轮：dummy -&gt; 2 -&gt; 1 -&gt; 3 -&gt; 4，prev 跳到 1
</span></span><span class="line"><span class="cl">第 2 轮：dummy -&gt; 2 -&gt; 1 -&gt; 4 -&gt; 3，prev 跳到 3
</span></span></code></pre></td></tr></table>
</div>
</div><p>奇数个节点时，最后一对凑不齐（<code>prev-&gt;next-&gt;next == nullptr</code>），剩下的单个节点不动，天然正确。</p>
<h2 id="递归版呼应-q206-的信任" class="headerLink">
    <a href="#%e9%80%92%e5%bd%92%e7%89%88%e5%91%bc%e5%ba%94-q206-%e7%9a%84%e4%bf%a1%e4%bb%bb" class="header-mark"></a>6 递归版（呼应 Q206 的&quot;信任&quot;）</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">swapPairs</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">head</span> <span class="o">==</span> <span class="k">nullptr</span> <span class="o">||</span> <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span> <span class="k">return</span> <span class="n">head</span><span class="p">;</span>  <span class="c1">// 基例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">ListNode</span><span class="o">*</span> <span class="n">second</span> <span class="o">=</span> <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">swapPairs</span><span class="p">(</span><span class="n">second</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">);</span>   <span class="c1">// 信任子问题：后面的已经交换好
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">second</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>                    <span class="c1">// 这一层只交换前两个
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">return</span> <span class="n">second</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>基例 + &ldquo;假设后面已交换好&rdquo; + 只做一步——和反转链表的信任模型完全一样。</p>
<h3 id="递归版逐层拆解" class="headerLink">
    <a href="#%e9%80%92%e5%bd%92%e7%89%88%e9%80%90%e5%b1%82%e6%8b%86%e8%a7%a3" class="header-mark"></a>6.1 递归版逐层拆解</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">swapPairs(1→2→3→4)
</span></span><span class="line"><span class="cl">  ├─ head=1, second=2
</span></span><span class="line"><span class="cl">  ├─ 先算 swapPairs(3→4)     ← 小问题 = 从第3个节点起的整段
</span></span><span class="line"><span class="cl">  │    ├─ head=3, second=4
</span></span><span class="line"><span class="cl">  │    ├─ swapPairs(nullptr)  ← 空链表 → 返回 nullptr（基例）
</span></span><span class="line"><span class="cl">  │    ├─ 3-&gt;next = nullptr
</span></span><span class="line"><span class="cl">  │    ├─ 4-&gt;next = 3
</span></span><span class="line"><span class="cl">  │    └─ 返回 4             （3→4 已变 4→3）
</span></span><span class="line"><span class="cl">  ├─ 回到第一层：1-&gt;next = 4   ← 4 接在 1 后面，链变成 1→4→3
</span></span><span class="line"><span class="cl">  ├─ 2-&gt;next = 1              ← 最外层现在才交换 1 和 2
</span></span><span class="line"><span class="cl">  └─ 返回 2                   （最终 2→1→4→3 ✓）
</span></span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p><strong>递归的箭头是从里往外接的</strong>：最深处的子调用先接好，再一层层回溯补上&quot;前两个节点&quot;的交换。每一层只保证前两个节点的顺序对，后面整段全部丢给子调用、信任它已排好——和反转链表、fib 是同一个归纳模型。不需要 dummy。</p></blockquote>
<blockquote>
<p><strong>迭代 vs 递归的建链方向</strong>：</p>
<ul>
<li>迭代版：从前往后建链，处理完一对推进 <code>prev</code>，需要 dummy 兜第一对。</li>
<li>递归版：从后往前组装，最深处先接好再回溯补前面的，不需要 dummy。</li>
</ul></blockquote>
<h2 id="我的草稿为什么乱" class="headerLink">
    <a href="#%e6%88%91%e7%9a%84%e8%8d%89%e7%a8%bf%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b9%b1" class="header-mark"></a>7 我的草稿为什么乱</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">while</span><span class="p">(){</span> <span class="p">...</span> <span class="p">}</span>                    <span class="c1">// 空条件，编译不过
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="n">new_cur</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>                <span class="c1">// x 没定义
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>更本质的问题：交换完一对后，这一对的<strong>新尾巴</strong>（原第一个节点）必须接到下一对的头；草稿里没有 <code>prev</code> 这个概念，只能用 <code>flag</code>、<code>heade</code> 硬补，越补越乱。加了 <code>prev</code> + <code>dummy</code> 之后，<code>flag</code> 和 <code>heade</code> 都不需要了。</p>
<h2 id="易错点" class="headerLink">
    <a href="#%e6%98%93%e9%94%99%e7%82%b9" class="header-mark"></a>8 易错点</h2><ul>
<li>循环条件必须是 <code>prev-&gt;next != nullptr &amp;&amp; prev-&gt;next-&gt;next != nullptr</code>：保证这一对真的有两个节点。</li>
<li>交换后 <code>prev = prev-&gt;next-&gt;next</code>，即这一对的新尾巴 a；写错位置会漏节点或死循环。</li>
<li>不要只交换 val：题目明确要求实际交换节点。</li>
<li>返回 <code>dummy-&gt;next</code>，不是 <code>head</code>（head 可能已经被换到第二位了）。</li>
</ul>
]]></description></item><item><title>滑动窗口模板</title><link>https://soybeanmilk.netlify.app/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%A8%A1%E6%9D%BF/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><author><name>作者</name></author><guid>https://soybeanmilk.netlify.app/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%A8%A1%E6%9D%BF/</guid><description><![CDATA[<h2 id="核心思想" class="headerLink">
    <a href="#%e6%a0%b8%e5%bf%83%e6%80%9d%e6%83%b3" class="header-mark"></a>1 核心思想</h2><p>维护一个窗口 [left, right]，right 不断向右扩展，满足条件时 left 向右收缩，窗口内的元素始终满足某个条件。</p>
<p><strong>适用场景：</strong> 子数组 / 子串问题，求最长 / 最短 / 数量</p>
<hr>
<h2 id="一模板框架" class="headerLink">
    <a href="#%e4%b8%80%e6%a8%a1%e6%9d%bf%e6%a1%86%e6%9e%b6" class="header-mark"></a>2 一、模板框架</h2><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">slidingWindow</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 窗口状态变量（计数、求和等）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">right</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">right</span> <span class="o">&lt;</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">right</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 1. 右端点进入窗口，更新窗口状态
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="p">(</span><span class="err">窗口不满足条件</span><span class="p">)</span> <span class="p">{</span>  <span class="c1">// 或 if，看题目
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="c1">// 2. 左端点移出窗口，更新窗口状态
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="n">left</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// 3. 此时窗口是合法的，更新答案
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">ans</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span> <span class="n">right</span> <span class="o">-</span> <span class="n">left</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="二经典题型" class="headerLink">
    <a href="#%e4%ba%8c%e7%bb%8f%e5%85%b8%e9%a2%98%e5%9e%8b" class="header-mark"></a>3 二、经典题型</h2><h3 id="题型-1最长无重复子串leetcode-3" class="headerLink">
    <a href="#%e9%a2%98%e5%9e%8b-1%e6%9c%80%e9%95%bf%e6%97%a0%e9%87%8d%e5%a4%8d%e5%ad%90%e4%b8%b2leetcode-3" class="header-mark"></a>3.1 题型 1：最长无重复子串（LeetCode 3）</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">lengthOfLongestSubstring</span><span class="p">(</span><span class="n">string</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">unordered_map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">window</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">right</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">right</span> <span class="o">&lt;</span> <span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">right</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">char</span> <span class="n">c</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">right</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="n">window</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="p">(</span><span class="n">window</span><span class="p">[</span><span class="n">c</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>  <span class="c1">// 出现重复，收缩
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="kt">char</span> <span class="n">d</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">left</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="n">window</span><span class="p">[</span><span class="n">d</span><span class="p">]</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">left</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">ans</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span> <span class="n">right</span> <span class="o">-</span> <span class="n">left</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="题型-2最小覆盖子串leetcode-76" class="headerLink">
    <a href="#%e9%a2%98%e5%9e%8b-2%e6%9c%80%e5%b0%8f%e8%a6%86%e7%9b%96%e5%ad%90%e4%b8%b2leetcode-76" class="header-mark"></a>3.2 题型 2：最小覆盖子串（LeetCode 76）</h3><p>找 s 中包含 t 所有字符的最短子串。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">string</span> <span class="nf">minWindow</span><span class="p">(</span><span class="n">string</span> <span class="n">s</span><span class="p">,</span> <span class="n">string</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">unordered_map</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">need</span><span class="p">,</span> <span class="n">window</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">char</span> <span class="nl">c</span> <span class="p">:</span> <span class="n">t</span><span class="p">)</span> <span class="n">need</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">valid</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">start</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">minLen</span> <span class="o">=</span> <span class="n">INT_MAX</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">right</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">right</span> <span class="o">&lt;</span> <span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">right</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">char</span> <span class="n">c</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">right</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">need</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">c</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">window</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">window</span><span class="p">[</span><span class="n">c</span><span class="p">]</span> <span class="o">==</span> <span class="n">need</span><span class="p">[</span><span class="n">c</span><span class="p">])</span> <span class="n">valid</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="p">(</span><span class="n">valid</span> <span class="o">==</span> <span class="n">need</span><span class="p">.</span><span class="n">size</span><span class="p">())</span> <span class="p">{</span>  <span class="c1">// 满足条件，收缩找最小
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="k">if</span> <span class="p">(</span><span class="n">right</span> <span class="o">-</span> <span class="n">left</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&lt;</span> <span class="n">minLen</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">minLen</span> <span class="o">=</span> <span class="n">right</span> <span class="o">-</span> <span class="n">left</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">start</span> <span class="o">=</span> <span class="n">left</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="kt">char</span> <span class="n">d</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">left</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">need</span><span class="p">.</span><span class="n">count</span><span class="p">(</span><span class="n">d</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">window</span><span class="p">[</span><span class="n">d</span><span class="p">]</span> <span class="o">==</span> <span class="n">need</span><span class="p">[</span><span class="n">d</span><span class="p">])</span> <span class="n">valid</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">window</span><span class="p">[</span><span class="n">d</span><span class="p">]</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="n">left</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">minLen</span> <span class="o">==</span> <span class="n">INT_MAX</span> <span class="o">?</span> <span class="s">&#34;&#34;</span> <span class="o">:</span> <span class="n">s</span><span class="p">.</span><span class="n">substr</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">minLen</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="题型-3和为-k-的子数组个数前缀和哈希" class="headerLink">
    <a href="#%e9%a2%98%e5%9e%8b-3%e5%92%8c%e4%b8%ba-k-%e7%9a%84%e5%ad%90%e6%95%b0%e7%bb%84%e4%b8%aa%e6%95%b0%e5%89%8d%e7%bc%80%e5%92%8c%e5%93%88%e5%b8%8c" class="header-mark"></a>3.3 题型 3：和为 K 的子数组个数（前缀和+哈希）</h3><p>注意：<strong>有负数时不能用滑动窗口</strong>，因为窗口不单调，要用前缀和+哈希。</p>
<hr>
<h2 id="三什么时候用滑动窗口" class="headerLink">
    <a href="#%e4%b8%89%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e7%94%a8%e6%bb%91%e5%8a%a8%e7%aa%97%e5%8f%a3" class="header-mark"></a>4 三、什么时候用滑动窗口？</h2><h3 id="能用滑动窗口的条件" class="headerLink">
    <a href="#%e8%83%bd%e7%94%a8%e6%bb%91%e5%8a%a8%e7%aa%97%e5%8f%a3%e7%9a%84%e6%9d%a1%e4%bb%b6" class="header-mark"></a>4.1 能用滑动窗口的条件</h3><ul>
<li>数组元素都是<strong>正数</strong>（窗口扩展和增大，收缩和减小）</li>
<li>求<strong>子数组</strong>的最长 / 最短 / 数量</li>
<li>条件具有<strong>单调性</strong>：窗口变大条件从满足变不满足（或反过来）</li>
</ul>
<h3 id="不能用滑动窗口" class="headerLink">
    <a href="#%e4%b8%8d%e8%83%bd%e7%94%a8%e6%bb%91%e5%8a%a8%e7%aa%97%e5%8f%a3" class="header-mark"></a>4.2 不能用滑动窗口</h3><ul>
<li>有<strong>负数</strong>（窗口增大和不一定增大）</li>
<li>求<strong>子序列</strong>（不连续）</li>
<li>条件不单调</li>
</ul>
<hr>
<h2 id="四固定窗口大小" class="headerLink">
    <a href="#%e5%9b%9b%e5%9b%ba%e5%ae%9a%e7%aa%97%e5%8f%a3%e5%a4%a7%e5%b0%8f" class="header-mark"></a>5 四、固定窗口大小</h2><p>窗口大小固定为 k，滑动遍历：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// 大小为 k 的子数组最大和
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kt">int</span> <span class="nf">maxSum</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">,</span> <span class="kt">int</span> <span class="n">k</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">k</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">sum</span> <span class="o">+=</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>  <span class="c1">// 第一个窗口
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="n">sum</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">k</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">sum</span> <span class="o">+=</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="n">k</span><span class="p">];</span>  <span class="c1">// 滑一格：加新的，减出去的
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">ans</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span> <span class="n">sum</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="五题目分类速查" class="headerLink">
    <a href="#%e4%ba%94%e9%a2%98%e7%9b%ae%e5%88%86%e7%b1%bb%e9%80%9f%e6%9f%a5" class="header-mark"></a>6 五、题目分类速查</h2><table>
  <thead>
      <tr>
          <th>类型</th>
          <th>代表题</th>
          <th>思路</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>最长无重复</td>
          <td>LeetCode 3</td>
          <td>哈希表计数，重复就收缩</td>
      </tr>
      <tr>
          <td>最小覆盖子串</td>
          <td>LeetCode 76</td>
          <td>need + window + valid</td>
      </tr>
      <tr>
          <td>字母异位词</td>
          <td>LeetCode 438</td>
          <td>固定窗口，比较计数</td>
      </tr>
      <tr>
          <td>最长重复字符替换</td>
          <td>LeetCode 424</td>
          <td>窗口内最多字符数 + k</td>
      </tr>
      <tr>
          <td>水果成篮</td>
          <td>LeetCode 904</td>
          <td>最多两种水果，最长子数组</td>
      </tr>
      <tr>
          <td>和为 s 的最短子数组</td>
          <td>LeetCode 209</td>
          <td>正整数，收缩求最短</td>
      </tr>
      <tr>
          <td>乘积小于 K 的子数组</td>
          <td>LeetCode 713</td>
          <td>正数，收缩计数</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="六解题步骤" class="headerLink">
    <a href="#%e5%85%ad%e8%a7%a3%e9%a2%98%e6%ad%a5%e9%aa%a4" class="header-mark"></a>7 六、解题步骤</h2><ol>
<li>初始化 left = 0，答案变量</li>
<li>遍历 right 从 0 到 n-1</li>
<li>右端点加入窗口，更新状态</li>
<li>窗口不合法时，while 循环收缩左端点</li>
<li>窗口合法时，更新答案</li>
</ol>
<blockquote>
<p>口诀：<strong>右扩左缩，边扩边更，缩完算答</strong></p></blockquote>
]]></description></item><item><title>双指针技巧总结</title><link>https://soybeanmilk.netlify.app/%E5%8F%8C%E6%8C%87%E9%92%88%E6%8A%80%E5%B7%A7%E6%80%BB%E7%BB%93/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><author><name>作者</name></author><guid>https://soybeanmilk.netlify.app/%E5%8F%8C%E6%8C%87%E9%92%88%E6%8A%80%E5%B7%A7%E6%80%BB%E7%BB%93/</guid><description><![CDATA[<h2 id="一快慢指针floyd-判圈算法" class="headerLink">
    <a href="#%e4%b8%80%e5%bf%ab%e6%85%a2%e6%8c%87%e9%92%88floyd-%e5%88%a4%e5%9c%88%e7%ae%97%e6%b3%95" class="header-mark"></a>1 一、快慢指针（Floyd 判圈算法）</h2><p>一个快指针走两步，一个慢指针走一步，常用于链表问题。</p>
<h3 id="应用-1判断链表是否有环" class="headerLink">
    <a href="#%e5%ba%94%e7%94%a8-1%e5%88%a4%e6%96%ad%e9%93%be%e8%a1%a8%e6%98%af%e5%90%a6%e6%9c%89%e7%8e%af" class="header-mark"></a>1.1 应用 1：判断链表是否有环</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">hasCycle</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span> <span class="o">*</span><span class="n">slow</span> <span class="o">=</span> <span class="n">head</span><span class="p">,</span> <span class="o">*</span><span class="n">fast</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">fast</span> <span class="o">&amp;&amp;</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">slow</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">slow</span> <span class="o">==</span> <span class="n">fast</span><span class="p">)</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="应用-2找环的入口" class="headerLink">
    <a href="#%e5%ba%94%e7%94%a8-2%e6%89%be%e7%8e%af%e7%9a%84%e5%85%a5%e5%8f%a3" class="header-mark"></a>1.2 应用 2：找环的入口</h3><p>相遇后，一个从头开始，一个从相遇点开始，同速走，再次相遇就是入口。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">detectCycle</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span> <span class="o">*</span><span class="n">slow</span> <span class="o">=</span> <span class="n">head</span><span class="p">,</span> <span class="o">*</span><span class="n">fast</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">fast</span> <span class="o">&amp;&amp;</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">slow</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">slow</span> <span class="o">==</span> <span class="n">fast</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">slow</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">while</span> <span class="p">(</span><span class="n">slow</span> <span class="o">!=</span> <span class="n">fast</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">slow</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">slow</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">nullptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="应用-3找链表中点" class="headerLink">
    <a href="#%e5%ba%94%e7%94%a8-3%e6%89%be%e9%93%be%e8%a1%a8%e4%b8%ad%e7%82%b9" class="header-mark"></a>1.3 应用 3：找链表中点</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">middleNode</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span> <span class="o">*</span><span class="n">slow</span> <span class="o">=</span> <span class="n">head</span><span class="p">,</span> <span class="o">*</span><span class="n">fast</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">fast</span> <span class="o">&amp;&amp;</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">slow</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">slow</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="应用-4找倒数第-k-个节点" class="headerLink">
    <a href="#%e5%ba%94%e7%94%a8-4%e6%89%be%e5%80%92%e6%95%b0%e7%ac%ac-k-%e4%b8%aa%e8%8a%82%e7%82%b9" class="header-mark"></a>1.4 应用 4：找倒数第 k 个节点</h3><p>快指针先走 k 步，然后同速走，快到末尾时慢就是倒数第 k 个。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ListNode</span><span class="o">*</span> <span class="nf">getKthFromEnd</span><span class="p">(</span><span class="n">ListNode</span><span class="o">*</span> <span class="n">head</span><span class="p">,</span> <span class="kt">int</span> <span class="n">k</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ListNode</span> <span class="o">*</span><span class="n">fast</span> <span class="o">=</span> <span class="n">head</span><span class="p">,</span> <span class="o">*</span><span class="n">slow</span> <span class="o">=</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">k</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">fast</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">fast</span> <span class="o">=</span> <span class="n">fast</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">slow</span> <span class="o">=</span> <span class="n">slow</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">slow</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="二左右指针对撞指针" class="headerLink">
    <a href="#%e4%ba%8c%e5%b7%a6%e5%8f%b3%e6%8c%87%e9%92%88%e5%af%b9%e6%92%9e%e6%8c%87%e9%92%88" class="header-mark"></a>2 二、左右指针（对撞指针）</h2><p>一个在头，一个在尾，往中间走。</p>
<h3 id="应用-1两数之和-ii有序数组" class="headerLink">
    <a href="#%e5%ba%94%e7%94%a8-1%e4%b8%a4%e6%95%b0%e4%b9%8b%e5%92%8c-ii%e6%9c%89%e5%ba%8f%e6%95%b0%e7%bb%84" class="header-mark"></a>2.1 应用 1：两数之和 II（有序数组）</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">twoSum</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">numbers</span><span class="p">,</span> <span class="kt">int</span> <span class="n">target</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="n">numbers</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">numbers</span><span class="p">[</span><span class="n">left</span><span class="p">]</span> <span class="o">+</span> <span class="n">numbers</span><span class="p">[</span><span class="n">right</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">sum</span> <span class="o">==</span> <span class="n">target</span><span class="p">)</span> <span class="k">return</span> <span class="p">{</span><span class="n">left</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">right</span> <span class="o">+</span> <span class="mi">1</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="nf">if</span> <span class="p">(</span><span class="n">sum</span> <span class="o">&lt;</span> <span class="n">target</span><span class="p">)</span> <span class="n">left</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="n">right</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="应用-2盛最多水的容器" class="headerLink">
    <a href="#%e5%ba%94%e7%94%a8-2%e7%9b%9b%e6%9c%80%e5%a4%9a%e6%b0%b4%e7%9a%84%e5%ae%b9%e5%99%a8" class="header-mark"></a>2.2 应用 2：盛最多水的容器</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">maxArea</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">height</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="n">height</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">ans</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">area</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">height</span><span class="p">[</span><span class="n">left</span><span class="p">],</span> <span class="n">height</span><span class="p">[</span><span class="n">right</span><span class="p">])</span> <span class="o">*</span> <span class="p">(</span><span class="n">right</span> <span class="o">-</span> <span class="n">left</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">ans</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span> <span class="n">area</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 移动矮的那边才有可能更大
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="n">height</span><span class="p">[</span><span class="n">left</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">height</span><span class="p">[</span><span class="n">right</span><span class="p">])</span> <span class="n">left</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="n">right</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="应用-3三数之和" class="headerLink">
    <a href="#%e5%ba%94%e7%94%a8-3%e4%b8%89%e6%95%b0%e4%b9%8b%e5%92%8c" class="header-mark"></a>2.3 应用 3：三数之和</h3><p>排序 + 固定一个数 + 双指针找另外两个：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">threeSum</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">sort</span><span class="p">(</span><span class="n">nums</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">nums</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">ans</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="k">continue</span><span class="p">;</span>  <span class="c1">// 去重
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kt">int</span> <span class="n">sum</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">]</span> <span class="o">+</span> <span class="n">nums</span><span class="p">[</span><span class="n">right</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">sum</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">ans</span><span class="p">.</span><span class="n">push_back</span><span class="p">({</span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="n">right</span><span class="p">]});</span>
</span></span><span class="line"><span class="cl">                <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;</span> <span class="n">right</span> <span class="o">&amp;&amp;</span> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">]</span> <span class="o">==</span> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span> <span class="n">left</span><span class="o">++</span><span class="p">;</span>   <span class="c1">// 去重
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;</span> <span class="n">right</span> <span class="o">&amp;&amp;</span> <span class="n">nums</span><span class="p">[</span><span class="n">right</span><span class="p">]</span> <span class="o">==</span> <span class="n">nums</span><span class="p">[</span><span class="n">right</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="n">right</span><span class="o">--</span><span class="p">;</span> <span class="c1">// 去重
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="n">left</span><span class="o">++</span><span class="p">;</span> <span class="n">right</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="p">(</span><span class="n">sum</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">left</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="n">right</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="应用-4反转字符串--回文判断" class="headerLink">
    <a href="#%e5%ba%94%e7%94%a8-4%e5%8f%8d%e8%bd%ac%e5%ad%97%e7%ac%a6%e4%b8%b2--%e5%9b%9e%e6%96%87%e5%88%a4%e6%96%ad" class="header-mark"></a>2.4 应用 4：反转字符串 / 回文判断</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">isPalindrome</span><span class="p">(</span><span class="n">string</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">left</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">left</span> <span class="o">&lt;</span> <span class="n">right</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">left</span><span class="p">]</span> <span class="o">!=</span> <span class="n">s</span><span class="p">[</span><span class="n">right</span><span class="p">])</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">left</span><span class="o">++</span><span class="p">;</span> <span class="n">right</span><span class="o">--</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="三滑动窗口指针" class="headerLink">
    <a href="#%e4%b8%89%e6%bb%91%e5%8a%a8%e7%aa%97%e5%8f%a3%e6%8c%87%e9%92%88" class="header-mark"></a>3 三、滑动窗口指针</h2><p>本质也是双指针，left 和 right 维护一个窗口。详见「滑动窗口模板」。</p>
<hr>
<h2 id="四快慢指针在数组中的应用" class="headerLink">
    <a href="#%e5%9b%9b%e5%bf%ab%e6%85%a2%e6%8c%87%e9%92%88%e5%9c%a8%e6%95%b0%e7%bb%84%e4%b8%ad%e7%9a%84%e5%ba%94%e7%94%a8" class="header-mark"></a>4 四、快慢指针在数组中的应用</h2><h3 id="原地删除重复元素leetcode-26" class="headerLink">
    <a href="#%e5%8e%9f%e5%9c%b0%e5%88%a0%e9%99%a4%e9%87%8d%e5%a4%8d%e5%85%83%e7%b4%a0leetcode-26" class="header-mark"></a>4.1 原地删除重复元素（LeetCode 26）</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">removeDuplicates</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">nums</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">slow</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">fast</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">fast</span> <span class="o">&lt;</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">fast</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="n">fast</span><span class="p">]</span> <span class="o">!=</span> <span class="n">nums</span><span class="p">[</span><span class="n">slow</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">slow</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">nums</span><span class="p">[</span><span class="n">slow</span><span class="p">]</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">fast</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">slow</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="移动零leetcode-283" class="headerLink">
    <a href="#%e7%a7%bb%e5%8a%a8%e9%9b%b6leetcode-283" class="header-mark"></a>4.2 移动零（LeetCode 283）</h3><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">moveZeroes</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">nums</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">slow</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">fast</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">fast</span> <span class="o">&lt;</span> <span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">fast</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="n">fast</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">swap</span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="n">slow</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="n">fast</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">            <span class="n">slow</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="五双指针题型速查" class="headerLink">
    <a href="#%e4%ba%94%e5%8f%8c%e6%8c%87%e9%92%88%e9%a2%98%e5%9e%8b%e9%80%9f%e6%9f%a5" class="header-mark"></a>5 五、双指针题型速查</h2><table>
  <thead>
      <tr>
          <th>类型</th>
          <th>指针运动方式</th>
          <th>典型题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>快慢指针</td>
          <td>同方向，速度不同</td>
          <td>链表环、中点、倒数第k个</td>
      </tr>
      <tr>
          <td>左右指针</td>
          <td>两端向中间</td>
          <td>两数之和、盛水、三数之和、回文</td>
      </tr>
      <tr>
          <td>滑动窗口</td>
          <td>同方向，维护窗口</td>
          <td>子串、子数组问题</td>
      </tr>
      <tr>
          <td>原地修改</td>
          <td>慢存快扫</td>
          <td>去重、移动零</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="六判断技巧" class="headerLink">
    <a href="#%e5%85%ad%e5%88%a4%e6%96%ad%e6%8a%80%e5%b7%a7" class="header-mark"></a>6 六、判断技巧</h2><ul>
<li><strong>链表问题</strong> → 先想快慢指针</li>
<li><strong>有序数组求和</strong> → 先想左右指针</li>
<li><strong>子数组/子串</strong> → 先想滑动窗口</li>
<li><strong>原地修改数组</strong> → 先想快慢指针（慢存快扫）</li>
</ul>
]]></description></item></channel></rss>