<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>教材笔记 on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/%E6%95%99%E6%9D%90%E7%AC%94%E8%AE%B0/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Sat, 12 Nov 2022 10:30:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/%E6%95%99%E6%9D%90%E7%AC%94%E8%AE%B0/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>《算法与数据结构》教材学习笔记：一张地图看懂全书，附避坑技巧与典型题</title>
      <link>https://ftmao.com/blog/posts/algorithm-data-structures-textbook-notes/</link>
      <pubDate>Sat, 12 Nov 2022 10:30:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/algorithm-data-structures-textbook-notes/</guid>
      <description>&lt;h1 id=&#34;算法与数据结构教材学习笔记&#34;&gt;《算法与数据结构》教材学习笔记&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;目标读者：正在学（或补）大学《算法与数据结构》这门课的新人。
阅读目标：看完能对全书有一个整体地图；知道每种结构&amp;quot;什么时候用、怎么实现、容易踩什么坑&amp;quot;；能用简单代码解决典型问题。
代码说明：实现采用 Python（简洁易懂、贴近伪代码），但思路与语言无关。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;0-开篇这门课到底在讲什么&#34;&gt;0. 开篇：这门课到底在讲什么&lt;/h2&gt;
&lt;p&gt;《算法与数据结构》整本书其实只回答一个问题：&lt;strong&gt;如何把&amp;quot;数据&amp;quot;组织起来，让&amp;quot;操作&amp;quot;更快。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;教材里的任何一章，都可以拆成三句话：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;逻辑结构&lt;/strong&gt;：数据之间的关系（线性、树形、图状、集合）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存储结构&lt;/strong&gt;：这些关系在内存里怎么放（顺序存储 / 链式存储 / 散列存储）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运算（算法）&lt;/strong&gt;：在这种组织方式上怎么做增删改查，效率如何。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[现实世界的问题] --&amp;gt; B[抽象出逻辑结构]
    B --&amp;gt; C{选存储结构}
    C --&amp;gt; C1[顺序存储&amp;lt;br/&amp;gt;连续内存, 随机访问快]
    C --&amp;gt; C2[链式存储&amp;lt;br/&amp;gt;指针串联, 增删快]
    C --&amp;gt; C3[散列存储&amp;lt;br/&amp;gt;哈希函数, 查找接近O1]
    C --&amp;gt; D[设计运算/算法]
    D --&amp;gt; E[用复杂度评估好坏]
    E --&amp;gt; F[得到可执行的程序]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;新人最容易犯的错误，是上来就背代码。&lt;strong&gt;正确顺序是：先想清楚逻辑关系 → 再选存储方式 → 最后才是写算法。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;评判算法好坏的尺子只有两个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;时间复杂度&lt;/strong&gt;：操作次数随输入规模 n 增长的趋势（O(1) &amp;lt; O(log n) &amp;lt; O(n) &amp;lt; O(n log n) &amp;lt; O(n²) &amp;lt; O(2ⁿ)）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;空间复杂度&lt;/strong&gt;：额外占用了多少内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;避坑 #0：复杂度看的是&amp;quot;趋势&amp;quot;不是&amp;quot;精确次数&amp;quot;。O(2n+100) 就是 O(n)，常数和低阶项全部扔掉。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;1-全书知识地图&#34;&gt;1. 全书知识地图&lt;/h2&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 基础[&amp;#34;数据结构部分&amp;#34;]
        L1[线性表&amp;lt;br/&amp;gt;顺序表/链表]
        L2[栈与队列&amp;lt;br/&amp;gt;受限线性表]
        L3[串与数组&amp;lt;br/&amp;gt;KMP/特殊矩阵]
        L4[树&amp;lt;br/&amp;gt;二叉树/BST/赫夫曼/B树]
        L5[图&amp;lt;br/&amp;gt;遍历/最短路/生成树]
    end
    subgraph 算法[&amp;#34;算法部分&amp;#34;]
        A1[查找&amp;lt;br/&amp;gt;顺序/二分/哈希]
        A2[排序&amp;lt;br/&amp;gt;插入/交换/选择/归并]
        A3[算法思想&amp;lt;br/&amp;gt;递归/分治/贪心/动态规划]
    end
    基础 --&amp;gt; 算法
    L1 --&amp;gt; L2 --&amp;gt; L3 --&amp;gt; L4 --&amp;gt; L5
    L4 --&amp;gt; A1
    L3 --&amp;gt; A2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;学习主线一句话：&lt;strong&gt;线性表是地基，栈队列是线性表的特例，树和图是推广，查找和排序是应用，递归分治等思想贯穿始终。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-线性表一切的起点&#34;&gt;2. 线性表：一切的起点&lt;/h2&gt;
&lt;h3 id=&#34;21-什么时候用哪种&#34;&gt;2.1 什么时候用哪种&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;顺序表（Python 的 list）&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;链表&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;随机访问第 i 个&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(1)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;中间插入/删除&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n)（要搬数据）&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(1)（找到位置后）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;内存&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;连续，按需自动扩容&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;分散，逐个结点申请&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;典型场景&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;频繁按下标读、长度稳定&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;频繁增删、长度不确定&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一句话场景判断：&lt;strong&gt;&amp;ldquo;读多写少用数组，增删多用链表&amp;rdquo;。&lt;/strong&gt;（Python 的 &lt;code&gt;list&lt;/code&gt; 是动态数组，自带扩容；教材里的链表则要自己定义结点类。）&lt;/p&gt;
&lt;h3 id=&#34;22-单链表结构与操作图解&#34;&gt;2.2 单链表结构与操作图解&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    head[头指针] --&amp;gt; H((头结点))
    H --&amp;gt; A1[a₁] --&amp;gt; A2[a₂] --&amp;gt; A3[a₃] --&amp;gt; NULL[∅ None]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;在结点 &lt;code&gt;p&lt;/code&gt; 之后插入新结点 &lt;code&gt;s&lt;/code&gt;，&lt;strong&gt;顺序不能反&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant s as 新结点s
    participant p as 结点p
    participant n as p.next
    Note over s,n: 第一步: s.next = p.next (先接上后面)
    s-&amp;gt;&amp;gt;n: s 指向 p 的后继
    Note over s,p: 第二步: p.next = s (再让 p 指向 s)
    p-&amp;gt;&amp;gt;s: p 指向 s&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;避坑 #1：插入时如果先写 &lt;code&gt;p.next = s&lt;/code&gt;，原来 &lt;code&gt;p.next&lt;/code&gt; 指向的结点就丢了（断链）。永远&lt;strong&gt;先接后继，再改前驱&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;23-简单实现单链表反转&#34;&gt;2.3 简单实现：单链表反转&lt;/h3&gt;
&lt;p&gt;链表反转是理解指针（引用）操作的&amp;quot;Hello World&amp;quot;，也是面试必考：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ListNode&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__init__&lt;/span&gt;(self, val&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, next&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;val &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; val
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;next &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; next
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reverse_list&lt;/span&gt;(head: ListNode) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; ListNode:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;原地反转单链表，返回新的头结点&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    prev, cur &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;, head
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; cur:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        nxt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cur&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;next   &lt;span style=&#34;color:#75715e&#34;&gt;# 1. 先记住下一个，防止断链&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cur&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;next &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; prev  &lt;span style=&#34;color:#75715e&#34;&gt;# 2. 掉头&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        prev &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cur       &lt;span style=&#34;color:#75715e&#34;&gt;# 3. prev 前进&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cur &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nxt        &lt;span style=&#34;color:#75715e&#34;&gt;# 4. cur 前进&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; prev          &lt;span style=&#34;color:#75715e&#34;&gt;# prev 停在原尾结点，即新头&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;避坑 #2：所有链表题，&lt;strong&gt;先建一个&amp;quot;虚拟头结点&amp;quot;（dummy node）&lt;/strong&gt;，可以让&amp;quot;删除头结点&amp;quot;和&amp;quot;删除中间结点&amp;quot;用同一套代码，不用特判，错误率直线下降。
避坑 #3：引用操作完一定要检查边界：对 &lt;code&gt;None&lt;/code&gt; 取 &lt;code&gt;.next&lt;/code&gt; 会报 &lt;code&gt;AttributeError&lt;/code&gt;，循环里每一步都问自己&amp;quot;这个引用可能是 &lt;code&gt;None&lt;/code&gt; 吗&amp;quot;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;3-栈与队列加了规矩的线性表&#34;&gt;3. 栈与队列：加了规矩的线性表&lt;/h2&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 栈Stack[&amp;#34;栈：后进先出 LIFO&amp;#34;]
        direction TB
        in1[入栈 push] --&amp;gt; top
        top[栈顶 top] --&amp;gt; out1[出栈 pop]
    end
    subgraph 队列Queue[&amp;#34;队列：先进先出 FIFO&amp;#34;]
        direction LR
        rear[队尾 rear&amp;lt;br/&amp;gt;入队] --&amp;gt; q1[...] --&amp;gt; front[队首 front&amp;lt;br/&amp;gt;出队]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;31-场景速查&#34;&gt;3.1 场景速查&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;栈&lt;/strong&gt;：括号匹配、表达式求值、函数调用栈、DFS、撤销（Undo）、浏览器后退。Python 里直接用 &lt;code&gt;list&lt;/code&gt;，&lt;code&gt;append()&lt;/code&gt; 入栈、&lt;code&gt;pop()&lt;/code&gt; 出栈。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;队列&lt;/strong&gt;：BFS、消息队列、缓冲区、按层处理（如二叉树层序遍历）。Python 里用 &lt;code&gt;collections.deque&lt;/code&gt;，&lt;code&gt;append()&lt;/code&gt; 入队、&lt;code&gt;popleft()&lt;/code&gt; 出队（&lt;strong&gt;不要用 &lt;code&gt;list.pop(0)&lt;/code&gt;，那是 O(n)&lt;/strong&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;判断口诀：&lt;strong&gt;&amp;ldquo;后进先出想栈，排队公平想队列&amp;rdquo;&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;32-简单实现括号匹配&#34;&gt;3.2 简单实现：括号匹配&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is_match&lt;/span&gt;(s: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; bool:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;判断字符串中的 () [] &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; 是否匹配&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pairs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;(&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;]&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;[&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;}&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{&amp;#39;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    stack &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; s:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;([{&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            stack&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append(c)          &lt;span style=&#34;color:#75715e&#34;&gt;# 左括号入栈&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;elif&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;)]}&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; stack:            &lt;span style=&#34;color:#75715e&#34;&gt;# 坑：栈空还来右括号&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; stack&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pop() &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; pairs[c]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; stack                 &lt;span style=&#34;color:#75715e&#34;&gt;# 坑：别忘了栈里可能剩左括号&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;避坑 #4：括号匹配的两个经典漏判——&lt;strong&gt;栈空时遇到右括号&lt;/strong&gt;（如 &lt;code&gt;&amp;quot;)(&amp;quot;&lt;/code&gt;）和&lt;strong&gt;遍历完栈非空&lt;/strong&gt;（如 &lt;code&gt;&amp;quot;(((&amp;quot;&lt;/code&gt;）。考试和面试最爱在这两个地方埋雷。
避坑 #5：顺序队列用定长数组实现时会有&amp;quot;假溢出&amp;quot;（rear 到顶但前面有空位），解法是把数组首尾相接做成&lt;strong&gt;循环队列&lt;/strong&gt;，用 &lt;code&gt;(rear+1) % MAXSIZE == front&lt;/code&gt; 判满。（Python 的 &lt;code&gt;deque&lt;/code&gt; 内部已处理好这个问题，但考试按教材的循环队列答。）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;4-串与-kmp让字符串匹配不回退&#34;&gt;4. 串与 KMP：让字符串匹配不回退&lt;/h2&gt;
&lt;p&gt;朴素的字符串匹配：主串指针 i 每次失配都要回退，最坏 O(n·m)。&lt;/p&gt;
&lt;p&gt;KMP 的核心思想一句话：&lt;strong&gt;失配时利用&amp;quot;已匹配部分的前后缀相同&amp;quot;信息，让主串指针 i 永不回退，只移动模式串指针 j&lt;/strong&gt;，复杂度降到 O(n+m)。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[i 指向主串, j 指向模式串] --&amp;gt; B{&amp;#34;s[i] == p[j] ?&amp;#34;}
    B -- 相等 --&amp;gt; C[i++, j++]
    B -- 不等且 j&amp;gt;0 --&amp;gt; D[&amp;#34;j = next[j]&amp;lt;br/&amp;gt;(模式串自己回退, i 不动)&amp;#34;]
    B -- 不等且 j==0 --&amp;gt; E[i++]
    C --&amp;gt; F{j 到达模式串末尾?}
    D --&amp;gt; B
    E --&amp;gt; B
    F -- 是 --&amp;gt; G[匹配成功]
    F -- 否 --&amp;gt; B&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;避坑 #6：&lt;code&gt;next&lt;/code&gt; 数组的定义是&amp;quot;模式串前 j 个字符中，最长的相等真前后缀长度&amp;quot;。很多人背了代码却没理解这句话，换道题就不会推。&lt;strong&gt;手工推 next 数组&lt;/strong&gt;是教材必考题，务必练几次。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;5-树最重要的非线性结构&#34;&gt;5. 树：最重要的非线性结构&lt;/h2&gt;
&lt;h3 id=&#34;51-二叉树长什么样&#34;&gt;5.1 二叉树长什么样&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TD
    A((A 根)) --&amp;gt; B((B))
    A --&amp;gt; C((C))
    B --&amp;gt; D((D))
    B --&amp;gt; E((E))
    C --&amp;gt; F((F))&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;三种遍历对同一棵树的不同访问顺序：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;遍历&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;顺序&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;上图结果&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;典型用途&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;前序&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;根→左→右&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;A B D E C F&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;复制树、表达式前缀形式&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;中序&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;左→根→右&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;D B E A F C&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;BST 中序 = 有序序列&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;后序&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;左→右→根&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;D E B F C A&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;释放树、计算目录大小&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;52-简单实现递归遍历&#34;&gt;5.2 简单实现：递归遍历&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TreeNode&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__init__&lt;/span&gt;(self, val&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, left&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;, right&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;val &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; val
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;left &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; left
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;right &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; right
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;preorder&lt;/span&gt;(root: TreeNode):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;前序遍历；把三行的顺序换成 LVR / LRV 就是中序/后序&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; root &lt;span style=&#34;color:#f92672&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;:         &lt;span style=&#34;color:#75715e&#34;&gt;# 递归出口&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    visit(root)              &lt;span style=&#34;color:#75715e&#34;&gt;# V：访问根&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    preorder(root&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;left)      &lt;span style=&#34;color:#75715e&#34;&gt;# L：遍历左子树&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    preorder(root&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;right)     &lt;span style=&#34;color:#75715e&#34;&gt;# R：遍历右子树&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;避坑 #7：树的题 90% 能用递归解决，写递归时先写&lt;strong&gt;递归出口&lt;/strong&gt;（&lt;code&gt;root is None&lt;/code&gt;），再写&amp;quot;我对当前结点做什么、把什么交给子树&amp;quot;。想不清就画一棵三层的树手动模拟。另外注意 Python 默认递归深度约 1000，树很深时要改迭代写法或调 &lt;code&gt;sys.setrecursionlimit&lt;/code&gt;。
避坑 #8：**&amp;ldquo;二叉搜索树（BST）中序遍历结果是升序&amp;rdquo;**这条性质是大量题目的钥匙——验证 BST、找第 K 小、找两结点最近公共祖先都靠它。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;53-教材里的三种重要树&#34;&gt;5.3 教材里的三种重要树&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;赫夫曼树&lt;/strong&gt;：带权路径长度最短的树，用于赫夫曼编码（压缩）。构造方法：每次取权值最小的两棵合并（Python 里用 &lt;code&gt;heapq&lt;/code&gt; 实现非常顺手）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;二叉搜索树（BST）&lt;/strong&gt;：左子树所有值 &amp;lt; 根 &amp;lt; 右子树所有值。查找/插入/删除平均 O(log n)，&lt;strong&gt;但退化成链表时最坏 O(n)&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平衡二叉树（AVL）与 B 树&lt;/strong&gt;：为了解决 BST 退化问题。AVL 靠旋转保持左右子树高度差 ≤ 1；B 树一个结点存多个关键字，矮而胖，&lt;strong&gt;是数据库索引和文件系统的基石&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;避坑 #9：BST 删除有两个孩子的结点时，标准做法是&lt;strong&gt;用中序直接前驱（左子树最大）或中序直接后继（右子树最小）顶替&lt;/strong&gt;，再删除那个顶替者。直接删会把子树搞丢。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;6-图关系最一般的结构&#34;&gt;6. 图：关系最一般的结构&lt;/h2&gt;
&lt;h3 id=&#34;61-怎么存&#34;&gt;6.1 怎么存&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;邻接矩阵&lt;/strong&gt;：&lt;code&gt;g[i][j]&lt;/code&gt; 表示 i 到 j 是否有边。适合稠密图，查边 O(1)，空间 O(n²)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;邻接表&lt;/strong&gt;：每个顶点挂一个邻居列表。适合稀疏图，空间 O(n+e)，&lt;strong&gt;默认首选&lt;/strong&gt;。Python 里用 &lt;code&gt;dict[int, list[int]]&lt;/code&gt; 即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;62-两种遍历&#34;&gt;6.2 两种遍历&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph DFS[&amp;#34;DFS 深度优先&amp;#34;]
        d1[访问v] --&amp;gt; d2[选一个未访问邻居&amp;lt;br/&amp;gt;递归深入] --&amp;gt; d3[无路可走才回溯]
    end
    subgraph BFS[&amp;#34;BFS 广度优先&amp;#34;]
        b1[v 入队] --&amp;gt; b2[出队并访问] --&amp;gt; b3[所有未访问邻居入队] --&amp;gt; b2
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; collections &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; deque
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dfs&lt;/span&gt;(g: dict, v, visited: set):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;DFS：递归 + visited 集合防环&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    visited&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add(v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    visit(v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; w &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; g[v]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; w &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; visited:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            dfs(g, w, visited)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bfs&lt;/span&gt;(g: dict, s):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;BFS：队列 + visited 集合&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    visited &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {s}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    q &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; deque([s])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; q:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; q&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;popleft()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        visit(v)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; w &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; g[v]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; w &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; visited:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                visited&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add(w)   &lt;span style=&#34;color:#75715e&#34;&gt;# 坑：入队时就标记，不是出队时&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                q&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append(w)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;避坑 #10：图遍历&lt;strong&gt;必须配 visited&lt;/strong&gt;，漏了它遇到环就死循环。而且要在&lt;strong&gt;入队时&lt;/strong&gt;（不是出队时）标记 visited，否则同一结点会被多次入队。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;63-图的经典应用速查&#34;&gt;6.3 图的经典应用速查&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;问题&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;算法&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;一句话说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;无权图最短路径&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;BFS&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;按层扩展，第一次到达即最短&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;带权（非负）最短路&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Dijkstra&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;每次挑当前距离最小的点&amp;quot;定稿&amp;quot;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;最小生成树&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Prim / Kruskal&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;连通所有点的最小代价（布线、修路）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;课程先修顺序&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;拓扑排序&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;反复找入度为 0 的点输出&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;关键路径&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;AOE 网&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;工程中最长路径决定工期&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;64-简单实现dijkstra-最短路径&#34;&gt;6.4 简单实现：Dijkstra 最短路径&lt;/h3&gt;
&lt;p&gt;思想一句话：&lt;strong&gt;每次从未定稿的点里挑距离最小的点&amp;quot;定稿&amp;quot;，再用它去松弛所有出边&lt;/strong&gt;（好比涟漪一圈圈扩散，最近的点最先确定）。用最小堆（&lt;code&gt;heapq&lt;/code&gt;）把&amp;quot;挑最小&amp;quot;从 O(n) 降到 O(log n)，总复杂度 O((n+e) log n)。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; heapq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dijkstra&lt;/span&gt;(g: dict, s) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; dict:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;g[u] = [(v, w), ...] 表示 u-&amp;gt;v 有一条权值为 w 的边（要求 w &amp;gt;= 0）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    返回 s 到各点的最短距离，不可达的点不在结果中&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dist &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {s: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pq &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, s)]                      &lt;span style=&#34;color:#75715e&#34;&gt;# (当前距离, 顶点)，最小堆&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    done &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; set()                       &lt;span style=&#34;color:#75715e&#34;&gt;# 已&amp;#34;定稿&amp;#34;的点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; pq:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        d, u &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; heapq&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;heappop(pq)       &lt;span style=&#34;color:#75715e&#34;&gt;# 挑出距离最小的点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; u &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; done:                  &lt;span style=&#34;color:#75715e&#34;&gt;# 坑：堆里可能有同一点的过期记录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        done&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add(u)                    &lt;span style=&#34;color:#75715e&#34;&gt;# 定稿：d 就是 s 到 u 的最短距离&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; v, w &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; g&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(u, []):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; done &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; d &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; w &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; dist&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(v, float(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;inf&amp;#39;&lt;/span&gt;)):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                dist[v] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; d &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; w        &lt;span style=&#34;color:#75715e&#34;&gt;# 松弛：找到更短的路&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                heapq&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;heappush(pq, (dist[v], v))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; dist
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 示例：g = {&amp;#39;A&amp;#39;: [(&amp;#39;B&amp;#39;, 5), (&amp;#39;C&amp;#39;, 2)], &amp;#39;B&amp;#39;: [(&amp;#39;C&amp;#39;, 1)], &amp;#39;C&amp;#39;: [(&amp;#39;B&amp;#39;, 3)]}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# dijkstra(g, &amp;#39;A&amp;#39;) -&amp;gt; {&amp;#39;A&amp;#39;: 0, &amp;#39;C&amp;#39;: 2, &amp;#39;B&amp;#39;: 5}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;要点解释：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;松弛&lt;/strong&gt;：如果&amp;quot;经过 u 再到 v&amp;quot;比已知的 v 距离更短，就更新 v 的距离——&lt;code&gt;dist[v] = d + w&lt;/code&gt; 那一行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;懒惰删除&lt;/strong&gt;：堆里的记录可能已被更新（过期），出堆时用 &lt;code&gt;done&lt;/code&gt; 集合跳过，避免入堆记录删不掉的麻烦。&lt;/li&gt;
&lt;li&gt;想要&lt;strong&gt;具体路径&lt;/strong&gt;而不只是距离？再维护一个 &lt;code&gt;prev[v] = u&lt;/code&gt; 前驱字典，最后从终点倒推即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;避坑 #11：&lt;strong&gt;Dijkstra 不能处理负权边&lt;/strong&gt;（&amp;ldquo;定稿&amp;quot;假设一旦成立就被负边打破），有负权要用 Bellman-Ford。这是考研和面试的经典判断题。
避坑 #12：拓扑排序排不完（输出点数 &amp;lt; 总点数）说明&lt;strong&gt;图中有环&lt;/strong&gt;，工程上意味着任务依赖出现了死锁。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;7-查找&#34;&gt;7. 查找&lt;/h2&gt;
&lt;h3 id=&#34;71-三种基本查找&#34;&gt;7.1 三种基本查找&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;方法&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;前提&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;平均复杂度&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;顺序查找&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;无&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;数据少、无序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;二分查找&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;有序 + 顺序存储&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(log n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;静态有序数据&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;散列（哈希）查找&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;建哈希表&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;接近 O(1)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;海量数据快速查询&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;72-简单实现二分查找正确写法&#34;&gt;7.2 简单实现：二分查找（正确写法）&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;binary_search&lt;/span&gt;(a: list, key) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;在有序数组 a 中找 key，找到返回下标，否则返回 -1&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    l, r &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, len(a) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; l &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; r:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        mid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; l &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; (r &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; l) &lt;span style=&#34;color:#f92672&#34;&gt;//&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;# 通用写法，见避坑 #13&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; a[mid] &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; key:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; mid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;elif&lt;/span&gt; a[mid] &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; key:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            l &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mid &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            r &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mid &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;避坑 #13：Python 的整数不会溢出，但 C/Java 里 &lt;code&gt;mid = (l + r) / 2&lt;/code&gt; 在 l、r 很大时会&lt;strong&gt;整数溢出&lt;/strong&gt;；统一写成 &lt;code&gt;l + (r - l) // 2&lt;/code&gt; 是跨语言都安全的好习惯。（Python 工程代码直接用标准库 &lt;code&gt;bisect&lt;/code&gt; 模块，但手写二分是基本功。）
避坑 #14：二分的边界要全程统一——&lt;code&gt;while l &amp;lt;= r&lt;/code&gt; 配 &lt;code&gt;l = mid + 1 / r = mid - 1&lt;/code&gt;（闭区间写法），不要中途混用左闭右开的条件，否则差一错误（off-by-one）必现。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;73-哈希的冲突处理&#34;&gt;7.3 哈希的冲突处理&lt;/h3&gt;
&lt;p&gt;哈希查找快的前提是处理好冲突（两个关键字映射到同一位置）：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    K[关键字 key] --&amp;gt; H[哈希函数 h key]
    H --&amp;gt; C{位置被占?}
    C -- 否 --&amp;gt; S[直接存放/命中]
    C -- 是 --&amp;gt; M1[开放定址法&amp;lt;br/&amp;gt;向后探测空位]
    C -- 是 --&amp;gt; M2[链地址法&amp;lt;br/&amp;gt;同位置挂链表]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开放定址法&lt;/strong&gt;：冲突了就顺延找下一个空位（教材重点，删除要设&amp;quot;墓碑&amp;quot;标记）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链地址法&lt;/strong&gt;：同位置元素串成链表（工程主流，Python 的 &lt;code&gt;dict&lt;/code&gt; 和 Java 的 &lt;code&gt;HashMap&lt;/code&gt; 都用类似思路）。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;避坑 #15：哈希表的效率取决于&lt;strong&gt;装填因子 α = 元素数 / 表长&lt;/strong&gt;。α 越大冲突越多。工程上 α 超过 0.7 左右就该扩容了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;8-排序教材的重头戏&#34;&gt;8. 排序：教材的重头戏&lt;/h2&gt;
&lt;h3 id=&#34;81-分类地图&#34;&gt;8.1 分类地图&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    S[内部排序] --&amp;gt; I[插入类]
    S --&amp;gt; X[交换类]
    S --&amp;gt; C[选择类]
    S --&amp;gt; M[归并类]
    I --&amp;gt; I1[直接插入 O n²]
    I --&amp;gt; I2[希尔排序 O n^1.3]
    X --&amp;gt; X1[冒泡 O n²]
    X --&amp;gt; X2[快速排序 O n log n&amp;lt;br/&amp;gt;平均最快]
    C --&amp;gt; C1[简单选择 O n²]
    C --&amp;gt; C2[堆排序 O n log n]
    M --&amp;gt; M1[归并排序 O n log n&amp;lt;br/&amp;gt;稳定]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;82-一张表记住所有考点&#34;&gt;8.2 一张表记住所有考点&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;排序&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;平均&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;最坏&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;空间&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;稳定?&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;一句话记忆&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;直接插入&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n²)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n²)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(1)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;✅&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;打扑克插牌&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;希尔&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n^1.3)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n²)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(1)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;❌&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;分组插入&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;冒泡&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n²)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n²)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(1)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;✅&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;相邻交换，轻的浮上去&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;快速&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n log n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n²)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(log n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;❌&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;分治：选定枢轴分两边&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;简单选择&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n²)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n²)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(1)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;❌&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;每轮挑最小的放前面&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;堆&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n log n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n log n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(1)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;❌&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用堆反复取最值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;归并&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n log n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n log n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;O(n)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;✅&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;先分后合，合并两个有序段&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;避坑 #16：&amp;ldquo;稳定&amp;quot;指&lt;strong&gt;相等元素的相对顺序排序后不变&lt;/strong&gt;。常见坑：快排、堆排、简单选择、希尔都&lt;strong&gt;不稳定&lt;/strong&gt;；插入、冒泡、归并稳定。需要稳定性时（比如先按成绩排再按学号排），选归并。（Python 内置的 &lt;code&gt;sorted()&lt;/code&gt; 是 Timsort，稳定，工程直接用它。）
避坑 #17：快速排序在&lt;strong&gt;输入已基本有序 + 选第一个元素做枢轴&lt;/strong&gt;时退化成 O(n²)，实际工程中要随机选枢轴或三数取中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;83-简单实现快速排序&#34;&gt;8.3 简单实现：快速排序&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;quick_sort&lt;/span&gt;(a: list, l: int, r: int):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;快排：分治思想。partition 把枢轴放到最终位置，左边都比它小，右边都比它大&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; l &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; r:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    p &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; partition(a, l, r)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    quick_sort(a, l, p &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)   &lt;span style=&#34;color:#75715e&#34;&gt;# 递归左半&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    quick_sort(a, p &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, r)   &lt;span style=&#34;color:#75715e&#34;&gt;# 递归右半&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;partition&lt;/span&gt;(a: list, l: int, r: int) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pivot &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; a[l]              &lt;span style=&#34;color:#75715e&#34;&gt;# 选首元素做枢轴（教学版）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; l &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; r:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; l &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; r &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; a[r] &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; pivot:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            r &lt;span style=&#34;color:#f92672&#34;&gt;-=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        a[l] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; a[r]           &lt;span style=&#34;color:#75715e&#34;&gt;# 小的补到左边&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; l &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; r &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; a[l] &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; pivot:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            l &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        a[r] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; a[l]           &lt;span style=&#34;color:#75715e&#34;&gt;# 大的补到右边&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    a[l] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pivot              &lt;span style=&#34;color:#75715e&#34;&gt;# 枢轴归位&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; l&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;9-算法思想递归分治贪心动态规划&#34;&gt;9. 算法思想：递归、分治、贪心、动态规划&lt;/h2&gt;
&lt;p&gt;教材后半部分的灵魂。四者关系一句话：&lt;strong&gt;递归是手段，分治是&amp;quot;拆开再合并&amp;rdquo;，贪心是&amp;quot;每步选当前最好&amp;rdquo;，动态规划是&amp;quot;记住算过的子问题别重算&amp;quot;。&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    P[大问题] --&amp;gt; D{能否拆成&amp;lt;br/&amp;gt;同类子问题?}
    D -- 能, 子问题独立 --&amp;gt; DC[分治&amp;lt;br/&amp;gt;如归并排序/快排]
    D -- 能, 子问题重叠 --&amp;gt; DP[动态规划&amp;lt;br/&amp;gt;存表避免重算]
    P --&amp;gt; G{每步局部最优&amp;lt;br/&amp;gt;能推出全局最优?}
    G -- 能 --&amp;gt; GR[贪心&amp;lt;br/&amp;gt;如赫夫曼/Kruskal]
    G -- 不能 --&amp;gt; DP&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;91-简单实现爬楼梯dp-入门第一题&#34;&gt;9.1 简单实现：爬楼梯（DP 入门第一题）&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;climb_stairs&lt;/span&gt;(n: int) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;一次爬 1 或 2 级台阶，n 级有多少种爬法？&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; n &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    a, b &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;               &lt;span style=&#34;color:#75715e&#34;&gt;# dp[1]=1, dp[2]=2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, n &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        a, b &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; b, a &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; b       &lt;span style=&#34;color:#75715e&#34;&gt;# dp[i] = dp[i-1] + dp[i-2]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; b&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;避坑 #18：写动态规划&lt;strong&gt;先别动手写代码&lt;/strong&gt;，先用一句中文说清&amp;quot;dp[i] 表示什么&amp;quot;（状态定义），再写状态转移方程。这两步想清楚了，代码是机械翻译。直接上手写代码的，十有八九死在边界初始化上。（递归版 DP 记得加 &lt;code&gt;@functools.lru_cache&lt;/code&gt;，否则指数级重复计算。）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;10-典型问题速查表&#34;&gt;10. 典型问题速查表&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;典型问题&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;所属章节&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;解题钥匙&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;单链表反转 / 找倒数第 K 个结点&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;线性表&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;三指针原地反转 / 快慢指针&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;括号匹配、表达式求值&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;栈&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;左括号入栈，右括号出栈比对&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;约瑟夫问题&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;线性表/队列&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;循环链表模拟，或队列反复出队入队&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;汉诺塔&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;递归&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;把 n-1 个盘移到辅助柱 → 移大盘 → 再移回&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;判断/还原二叉树&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;树&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;前序+中序可唯一确定一棵树&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;求树高、叶子数&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;树&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;递归：&lt;code&gt;1 + max(左高, 右高)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;赫夫曼编码&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;树&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;每次合并最小两个权值（&lt;code&gt;heapq&lt;/code&gt;）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;迷宫问题&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;栈/DFS&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;栈记录路径，走不通就回溯&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;无权最短路&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;图/BFS&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;BFS 按层扩展&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;课程表能否修完&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;图/拓扑&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;拓扑排序 + 判环&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;前 K 大元素&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;堆&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;维护大小为 K 的小顶堆（&lt;code&gt;heapq&lt;/code&gt;）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;合并 K 个有序数组&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;归并&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;两两归并或堆&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;11-全书避坑清单考前面试前过一遍&#34;&gt;11. 全书避坑清单（考前/面试前过一遍）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;复杂度只看最高阶，扔掉常数。&lt;/li&gt;
&lt;li&gt;链表插入：先接后继，再改前驱；万能技巧：虚拟头结点。&lt;/li&gt;
&lt;li&gt;括号匹配：查&amp;quot;栈空遇右括号&amp;quot;和&amp;quot;遍历完栈非空&amp;quot;两种漏判。&lt;/li&gt;
&lt;li&gt;循环队列判满：&lt;code&gt;(rear+1) % MAX == front&lt;/code&gt;；队列出队用 &lt;code&gt;deque.popleft()&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;KMP 的 next 数组要会手工推。&lt;/li&gt;
&lt;li&gt;树的递归：先写递归出口；注意 Python 递归深度限制。&lt;/li&gt;
&lt;li&gt;记住：BST 中序遍历 = 升序。&lt;/li&gt;
&lt;li&gt;图遍历必须 visited，BFS 在入队时标记。&lt;/li&gt;
&lt;li&gt;Dijkstra 不支持负权边；拓扑排不完 = 有环。&lt;/li&gt;
&lt;li&gt;二分：&lt;code&gt;mid = l + (r - l) // 2&lt;/code&gt;，区间定义全程统一。&lt;/li&gt;
&lt;li&gt;哈希关注装填因子；开放定址法删除要打标记不能真删空。&lt;/li&gt;
&lt;li&gt;快排/堆排/简单选择/希尔不稳定；快排怕有序输入。&lt;/li&gt;
&lt;li&gt;动态规划：先说清 dp[i] 的含义，再写转移方程，最后处理初始化。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;12-学习路线建议&#34;&gt;12. 学习路线建议&lt;/h2&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    W1[第1-2周&amp;lt;br/&amp;gt;复杂度+线性表] --&amp;gt; W2[第3-4周&amp;lt;br/&amp;gt;栈/队列/串]
    W2 --&amp;gt; W3[第5-6周&amp;lt;br/&amp;gt;树与二叉树]
    W3 --&amp;gt; W4[第7-8周&amp;lt;br/&amp;gt;图]
    W4 --&amp;gt; W5[第9-10周&amp;lt;br/&amp;gt;查找+排序综合]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;三点经验之谈：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;每个结构都亲手实现一遍&lt;/strong&gt;。看懂和会写之间隔着一条鸿沟，哪怕写得慢，也要自己敲出链表、栈、二叉树遍历、快排这&amp;quot;四大件&amp;quot;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;画图比读代码快&lt;/strong&gt;。指针题、树题、图题，先在纸上画出结构变化，再翻译成代码，出错率低一半。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;题做不出来别死磕&lt;/strong&gt;。20 分钟没思路就看解析，重点搞懂&amp;quot;人家为什么想到用这个结构&amp;quot;，第二天独立重写一遍。吃透一类题，胜过囫囵刷一百道。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;结语&#34;&gt;结语&lt;/h2&gt;
&lt;p&gt;《算法与数据结构》这本书看起来章节多，其实主线非常清晰：&lt;strong&gt;数据怎么组织（结构）→ 操作怎么实现（算法）→ 效率怎么评估（复杂度）&lt;/strong&gt;。把这三问套到每一章，全书就从&amp;quot;一堆要背的知识&amp;quot;变成&amp;quot;一张可以推理的地图&amp;quot;。&lt;/p&gt;
&lt;p&gt;希望这份笔记能帮你把地图先装进脑子里，剩下的，就是动手写、动手画、动手刷。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
