<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>计算机科学 on 小窝</title><link>https://blog.areacloser.top/categories/cs/</link><description>Recent content in 计算机科学 on 小窝</description><generator>Hugo -- gohugo.io</generator><language>Asia/Shanghai</language><atom:link href="https://blog.areacloser.top/categories/cs/index.xml" rel="self" type="application/rss+xml"/><item><title>KMP算法讲解</title><link>https://blog.areacloser.top/post/kmp-algorithm/</link><pubDate>Sat, 11 Jul 2026 00:00:00 +0000</pubDate><guid>https://blog.areacloser.top/post/kmp-algorithm/</guid><description>&lt;img src="https://raw.gitcode.com/areacloser/hugoblogstack-image/raw/main/algorithm.png" alt="Featured image of post KMP算法讲解" /&gt;&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;KMP算法（Knuth-Morris-Pratt）是字符串匹配领域的“灵魂算法”。它的核心智慧在于：&lt;strong&gt;当匹配失败时，利用已经匹配成功的部分信息，让模式串“智能地”向右滑动，而文本指针绝不回溯。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了让你彻底理解，我们从&lt;strong&gt;痛点&lt;/strong&gt;出发，逐步拆解。&lt;/p&gt;
&lt;h2 id="正文"&gt;正文
&lt;/h2&gt;&lt;h3 id="1-暴力匹配的痛点"&gt;1. 暴力匹配的痛点
&lt;/h3&gt;&lt;p&gt;在暴力匹配中，若文本串 &lt;code&gt;S&lt;/code&gt; 为 &lt;code&gt;AAAAAB&lt;/code&gt;，模式串 &lt;code&gt;P&lt;/code&gt; 为 &lt;code&gt;AAAAB&lt;/code&gt;：
当匹配到 &lt;code&gt;S[4]=A&lt;/code&gt; 与 &lt;code&gt;P[4]=B&lt;/code&gt; 失配时，暴力法会把模式串整体右移一位，从 &lt;code&gt;S[1]&lt;/code&gt; 重新开始比较。
这意味着 &lt;strong&gt;&lt;code&gt;i&lt;/code&gt;（文本指针）发生了回溯&lt;/strong&gt;，之前比较过的字符又被重复比较，时间复杂度高达 &lt;strong&gt;O(n*m)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;KMP的绝招就是：&lt;strong&gt;&lt;code&gt;i&lt;/code&gt; 永远不后退，只让 &lt;code&gt;j&lt;/code&gt;（模式串指针）回退到合适的位置。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="2-核心武器最长相等前后缀lps--next数组"&gt;2. 核心武器：最长相等前后缀（LPS / Next数组）
&lt;/h3&gt;&lt;p&gt;为了让 &lt;code&gt;j&lt;/code&gt; 知道该回退到哪里，我们需要预处理模式串，生成一个 &lt;strong&gt;Next数组&lt;/strong&gt;（也叫部分匹配表，PMT）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：&lt;code&gt;next[i]&lt;/code&gt; 表示 &lt;strong&gt;模式串 &lt;code&gt;P[0...i]&lt;/code&gt; 这个子串中，最长的相等真前缀与真后缀的长度&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;真前缀/后缀&lt;/strong&gt;：不包含字符串本身的前缀/后缀。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;举个经典例子&lt;/strong&gt;：模式串 &lt;code&gt;P = &amp;quot;ABABC&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;子串&lt;/th&gt;
					&lt;th style="text-align: left"&gt;前缀集合&lt;/th&gt;
					&lt;th style="text-align: left"&gt;后缀集合&lt;/th&gt;
					&lt;th style="text-align: left"&gt;最长相等长度 (&lt;code&gt;next&lt;/code&gt;)&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;A&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;无&lt;/td&gt;
					&lt;td style="text-align: left"&gt;无&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;AB&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;{A}&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;{B}&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;ABA&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;{A, AB}&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;{A, BA}&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;1&lt;/strong&gt; (A)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;ABAB&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;{A, AB, ABA}&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;{B, AB, BAB}&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;2&lt;/strong&gt; (AB)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;ABABC&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;{A, AB, ABA, ABAB}&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;{C, BC, ABC, BABC}&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;所以 &lt;code&gt;next = [0, 0, 1, 2, 0]&lt;/code&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="3-匹配时的跳跃逻辑"&gt;3. 匹配时的“跳跃”逻辑
&lt;/h3&gt;&lt;p&gt;当我们在文本 &lt;code&gt;S&lt;/code&gt; 中匹配 &lt;code&gt;P&lt;/code&gt; 时，假设匹配到 &lt;code&gt;S[i]&lt;/code&gt; 与 &lt;code&gt;P[j]&lt;/code&gt; 失配了（&lt;code&gt;j&lt;/code&gt; 是当前模式串要比较的位置）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果 &lt;code&gt;j &amp;gt; 0&lt;/code&gt;，说明 &lt;code&gt;P[0...j-1]&lt;/code&gt; 这一段是匹配成功的。&lt;/li&gt;
&lt;li&gt;我们查看 &lt;code&gt;next[j-1]&lt;/code&gt;，设其值为 &lt;code&gt;k&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;这意味着，在已匹配的前缀 &lt;code&gt;P[0...j-1]&lt;/code&gt; 中，&lt;strong&gt;最前面的 &lt;code&gt;k&lt;/code&gt; 个字符&lt;/strong&gt; 和 &lt;strong&gt;最后面的 &lt;code&gt;k&lt;/code&gt; 个字符&lt;/strong&gt; 是一样的。&lt;/li&gt;
&lt;li&gt;因此，我们可以直接把 &lt;code&gt;j&lt;/code&gt; 跳到 &lt;code&gt;k&lt;/code&gt;（即 &lt;code&gt;j = next[j-1]&lt;/code&gt;），然后继续用当前的 &lt;code&gt;S[i]&lt;/code&gt; 和新的 &lt;code&gt;P[j]&lt;/code&gt; 比较。&lt;strong&gt;文本指针 &lt;code&gt;i&lt;/code&gt; 不动！&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="4-手把手模拟运行看清不回溯"&gt;4. 手把手模拟运行（看清“不回溯”）
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文本 S&lt;/strong&gt;：&lt;code&gt;ABABABC&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模式 P&lt;/strong&gt;：&lt;code&gt;ABABC&lt;/code&gt; (next = [0, 0, 1, 2, 0])&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;步骤详解&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;i=0, j=0&lt;/code&gt;：&lt;code&gt;S[0]=A&lt;/code&gt; vs &lt;code&gt;P[0]=A&lt;/code&gt; → 匹配，&lt;code&gt;i=1, j=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=1, j=1&lt;/code&gt;：&lt;code&gt;S[1]=B&lt;/code&gt; vs &lt;code&gt;P[1]=B&lt;/code&gt; → 匹配，&lt;code&gt;i=2, j=2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=2, j=2&lt;/code&gt;：&lt;code&gt;S[2]=A&lt;/code&gt; vs &lt;code&gt;P[2]=A&lt;/code&gt; → 匹配，&lt;code&gt;i=3, j=3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=3, j=3&lt;/code&gt;：&lt;code&gt;S[3]=B&lt;/code&gt; vs &lt;code&gt;P[3]=B&lt;/code&gt; → 匹配，&lt;code&gt;i=4, j=4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=4, j=4&lt;/code&gt;：&lt;code&gt;S[4]=A&lt;/code&gt; vs &lt;code&gt;P[4]=C&lt;/code&gt; → &lt;strong&gt;失配！&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;此时 &lt;code&gt;j=4 &amp;gt; 0&lt;/code&gt;，查 &lt;code&gt;next[3] = 2&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;我们令 &lt;code&gt;j = 2&lt;/code&gt;。&lt;strong&gt;注意：&lt;code&gt;i&lt;/code&gt; 依然停在 4 不动。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;逻辑含义：模式串右移，利用已知的 &lt;code&gt;&amp;quot;AB&amp;quot;&lt;/code&gt; 前缀，直接对齐文本中已匹配的后缀 &lt;code&gt;&amp;quot;AB&amp;quot;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;继续比较：&lt;code&gt;S[4]=A&lt;/code&gt; 与 &lt;code&gt;P[2]=A&lt;/code&gt; → 匹配，&lt;code&gt;i=5, j=3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=5, j=3&lt;/code&gt;：&lt;code&gt;S[5]=B&lt;/code&gt; vs &lt;code&gt;P[3]=B&lt;/code&gt; → 匹配，&lt;code&gt;i=6, j=4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=6, j=4&lt;/code&gt;：&lt;code&gt;S[6]=C&lt;/code&gt; vs &lt;code&gt;P[4]=C&lt;/code&gt; → 匹配，&lt;code&gt;j == 5&lt;/code&gt;，&lt;strong&gt;匹配成功！&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="5-最难啃的骨头如何高效构建-next-数组"&gt;5. 最难啃的骨头：如何高效构建 Next 数组？
&lt;/h3&gt;&lt;p&gt;构建 Next 数组的过程，&lt;strong&gt;本质上是模式串自己与自己进行 KMP 匹配&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们用双指针：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;len&lt;/code&gt; 表示当前最长的相等前后缀长度（也是前缀指针）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt; 从 1 遍历到末尾（后缀指针）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;构建逻辑（伪代码思路）&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;next[0] = 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;len = 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;i = 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;while i &amp;lt; m:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if P[i] == P[len]:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; len += 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; next[i] = len
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; i += 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; else:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if len &amp;gt; 0:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # 关键回退！利用已经算好的 next
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; len = next[len - 1]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; else:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; next[i] = 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; i += 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;手动演算 &lt;code&gt;P = &amp;quot;AAACAAAA&amp;quot;&lt;/code&gt;（让你体会回退的精髓）&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;i=1, len=0&lt;/code&gt;：P[1]=A vs P[0]=A → 匹配，&lt;code&gt;next[1]=1&lt;/code&gt;, &lt;code&gt;len=1&lt;/code&gt;, &lt;code&gt;i=2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=2, len=1&lt;/code&gt;：P[2]=A vs P[1]=A → 匹配，&lt;code&gt;next[2]=2&lt;/code&gt;, &lt;code&gt;len=2&lt;/code&gt;, &lt;code&gt;i=3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=3, len=2&lt;/code&gt;：P[3]=C vs P[2]=A → 失配！
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;len &amp;gt; 0&lt;/code&gt;，所以 &lt;code&gt;len = next[1] = 1&lt;/code&gt;（回退）。&lt;/li&gt;
&lt;li&gt;继续比较：P[3]=C vs P[1]=A → 失配！&lt;/li&gt;
&lt;li&gt;&lt;code&gt;len &amp;gt; 0&lt;/code&gt;，所以 &lt;code&gt;len = next[0] = 0&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;继续比较：P[3]=C vs P[0]=A → 失配！&lt;/li&gt;
&lt;li&gt;&lt;code&gt;len == 0&lt;/code&gt;，&lt;code&gt;next[3] = 0&lt;/code&gt;, &lt;code&gt;i=4&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i=4, len=0&lt;/code&gt;：P[4]=A vs P[0]=A → 匹配，&lt;code&gt;next[4]=1&lt;/code&gt;, &lt;code&gt;len=1&lt;/code&gt; &amp;hellip; 以此类推。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="6-终极总结面试考试速记"&gt;6. 终极总结（面试/考试速记）
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;时间复杂度&lt;/strong&gt;：&lt;strong&gt;O(n + m)&lt;/strong&gt;（预处理 O(m)，匹配 O(n)）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;空间复杂度&lt;/strong&gt;：O(m)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核心口诀&lt;/strong&gt;：

 &lt;blockquote&gt;
 &lt;p&gt;匹配失败看前一位，&lt;br&gt;
Next 值决定 j 回退到几，&lt;br&gt;
主串指针永不回头，&lt;br&gt;
前缀函数自己匹配自己。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;代码实现（Python）&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;next_arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# 前缀长度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next_arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 回退&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;next_arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;next_arr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;kmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;next_arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next_arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# 返回起始索引&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 如果想找所有匹配：j = next_arr[j-1]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Ubuntu Server 22.04 避坑和配置指南</title><link>https://blog.areacloser.top/post/tips-for-ubuntu-vm/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0000</pubDate><guid>https://blog.areacloser.top/post/tips-for-ubuntu-vm/</guid><description>&lt;img src="https://raw.gitcode.com/areacloser/images-for-hugo-blog/raw/main/DM-20241006112629-001.png" alt="Featured image of post Ubuntu Server 22.04 避坑和配置指南" /&gt;&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;先展示一下成果 ~&lt;/p&gt;
&lt;p&gt;&lt;img alt="Neofetch一下" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://raw.gitcode.com/areacloser/images-for-hugo-blog/raw/main/nf.png"&gt; &lt;img alt="LX Music" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://raw.gitcode.com/areacloser/images-for-hugo-blog/raw/main/lx.png"&gt;&lt;/p&gt;
&lt;p&gt;仔细算算，我花在这个虚拟机上的时间已经超过了15个小时，真可谓道阻且长！&lt;/p&gt;
&lt;p&gt;话不多说，下面就是正文了&lt;/p&gt;
&lt;h2 id="开始之前"&gt;开始之前
&lt;/h2&gt;&lt;h3 id="系统信息"&gt;系统信息
&lt;/h3&gt;&lt;p&gt;我使用的宿主机是Windows7系统，硬件比较古早，这里只展示部分信息：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;项目&lt;/th&gt;
					&lt;th style="text-align: left"&gt;值&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;CPU&lt;/td&gt;
					&lt;td style="text-align: left"&gt;Intel i5-2400&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;内存&lt;/td&gt;
					&lt;td style="text-align: left"&gt;8 GB&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;显示适配器&lt;/td&gt;
					&lt;td style="text-align: left"&gt;Intel(R) HD Graphics&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="软件安装"&gt;软件安装
&lt;/h3&gt;&lt;h4 id="安装之前的准备"&gt;安装之前的准备
&lt;/h4&gt;&lt;p&gt;在最最开始前，必不可少的是打开CPU功能中的虚拟化功能（Intel VT-x 或 Hyper-V），不然虚拟机的功能无法正常实现。不过好像这个功能大部分计算机是默认开启的（比如我就读高中的班级电脑），可是我家电脑却不默认开启。&lt;/p&gt;
&lt;p&gt;想要开启它，须要进入BIOS设置界面，常规做法是在开机出现Logo时按下F2键，但我家电脑要按Del键，这由主板型号而定。具体可参考&lt;a class="link" href="https://zhuanlan.zhihu.com/p/34223088" target="_blank" rel="noopener"
 &gt;这篇文章&lt;/a&gt;。&lt;/p&gt;
&lt;h4 id="ssh--vnc-连接软件"&gt;SSH &amp;amp; VNC 连接软件
&lt;/h4&gt;&lt;p&gt;虚拟机自带的用户界面实在难以入眼，加之后续需要建立VNC连接，找一个合适的远程连接软件是必要的。&lt;/p&gt;
&lt;p&gt;大部分人SSH连接都会选择使用 XShell， 但它有两个缺点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不支持VNC连接&lt;/li&gt;
&lt;li&gt;终端配色有时会出问题（如运行Neovim时）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因而此处我推荐使用 MobaXterm 作为替代，它虽然没有汉化，但能完美解决 XShell 的问题。&lt;/p&gt;
&lt;h4 id="虚拟机软件"&gt;虚拟机软件
&lt;/h4&gt;&lt;p&gt;市面上常用的虚拟机软件有两个：&lt;code&gt;VirtualBox&lt;/code&gt; 和 &lt;code&gt;VMWare&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果各位和我一样是Windows7的钉子户的话，那么请务必 不 要 使用&lt;code&gt;VirtualBox&lt;/code&gt;！虽然它免费开源，但它出的问题不是我们能够解决的（不支持Windows7）。至于收费的&lt;code&gt;VMWare&lt;/code&gt;，我想大家应当能各显神通，找到合适的学习版。不过使用Windows7的同学们又要注意了，&lt;code&gt;VMWare&lt;/code&gt;在 Workstation 15 之后的版本后都不再支持Windows7，所以请不要找更高的版本了！&lt;/p&gt;
&lt;h4 id="镜像文件"&gt;镜像文件
&lt;/h4&gt;&lt;p&gt;官网的下载速度十分令人堪忧，建议使用&lt;a class="link" href="https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/jammy/ubuntu-22.04.5-live-server-amd64.iso" target="_blank" rel="noopener"
 &gt;清华镜像源&lt;/a&gt;来获取系统镜像。&lt;/p&gt;
&lt;h2 id="cli界面"&gt;CLI界面
&lt;/h2&gt;&lt;h3 id="安装系统"&gt;安装系统
&lt;/h3&gt;&lt;p&gt;具体教程可参考一下几篇教程，都写得很详细：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.cnblogs.com/calvinit/p/16350378.html" target="_blank" rel="noopener"
 &gt;VMware 虚拟机图文安装和配置 Ubuntu Server 22.04 LTS 教程 - 博客园&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.cnblogs.com/abc1069/p/16296050.html" target="_blank" rel="noopener"
 &gt;vmware中安装 ubuntu 22.04 live-server - 博客园&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://zhuanlan.zhihu.com/p/627023160" target="_blank" rel="noopener"
 &gt;vmware 安装 ubuntu server 22.04.2 LTS记录 - 知乎&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里基本按着文章里的做就可以了，但有两点我要提醒：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;配置网络连接时建议先用DHCP（后面可以改回固定IP），不然可能会导致IP冲突。&lt;/li&gt;
&lt;li&gt;配置磁盘空间时一定要至少分配40G的空间！不然后续安装图形化界面时会空间不足！这是我亲身经历的，它让我被迫一切从头开始，损失惨重！并且建议将所有的剩余空间（free-space）都用掉，反正留着也没用，不如都分配给根目录（/）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="配置ssh连接"&gt;配置SSH连接
&lt;/h3&gt;&lt;p&gt;在进行SSH连接前，要先配置端口转发。同样，推荐一些文章教程：&lt;/p&gt;
&lt;h4 id="端口转发"&gt;端口转发
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.csdn.net/weixin_49047967/article/details/132555042" target="_blank" rel="noopener"
 &gt;VMware做NAT端口转发(全网最详细步骤) - CSDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.cnblogs.com/testgo/p/10368999.html" target="_blank" rel="noopener"
 &gt;VMware虚拟机配置端口转发（端口映射） - 博客园&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后是SSH配置：&lt;/p&gt;
&lt;h4 id="ssh-配置"&gt;SSH 配置
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.csdn.net/gmaaa123/article/details/135162819" target="_blank" rel="noopener"
 &gt;Ubuntu 22.04.3 Server 安装sshd和开启root账号ssh远程 - CSDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://developer.aliyun.com/article/1488008" target="_blank" rel="noopener"
 &gt;如何在 Ubuntu 上启用 SSH（适用于 20.04、22.04）？ - 阿里云&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同样，我有一点要提醒，在SSH连接时，有可能出现&lt;code&gt;Error503&lt;/code&gt;问题，即建立SSH连接后无法进入命令行界面。虽然其中的原因尚不明确，但是更换端口转发时的IP地址然后重新连接就能解决问题。&lt;/p&gt;
&lt;h3 id="更换地区和语言"&gt;更换地区和语言
&lt;/h3&gt;&lt;p&gt;正常情况下，刚安装好的Ubuntu的默认语言是英语，即&lt;code&gt;locale&lt;/code&gt;是&lt;code&gt;en&lt;/code&gt;。更换为中文不是必需的，但我仍然建议大家换掉，因为这会影响后续图形化的语言配置。当然，如果对自己的英语水平有足够的信心，就当我没说。&lt;/p&gt;
&lt;p&gt;想要更换语言，需要在命令行中执行以下操作&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install language-pack-zh-hans
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo update-locale &lt;span class="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;zh_CN.UTF-8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;最后重启系统即可。&lt;/p&gt;
&lt;h2 id="gui-界面"&gt;GUI 界面
&lt;/h2&gt;&lt;p&gt;由于最开始安装的是Server版，所以此时的Ubuntu是没有图形化界面的，但是我们可以为其安装一个（甚至多个）桌面环境！而想要多快好省地完成这一重任，我们就要请出下面这个神器：&lt;/p&gt;
&lt;p&gt;TMOE（天萌管理器）&lt;/p&gt;
&lt;p&gt;&lt;img alt="没找到TMOE的图标就用二萌的头像代替了" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://raw.gitcode.com/areacloser/images-for-hugo-blog/raw/main/2moe.png"&gt;&lt;/p&gt;
&lt;h3 id="题外话"&gt;题外话
&lt;/h3&gt;&lt;p&gt;说到这里，我不得不提一下TMOE的作者2moe。TA虽然基本不再更新管理器，但一直在gitee社区活跃出现，而且十分负责地答疑解惑，确实非常有责任心！&lt;/p&gt;
&lt;p&gt;（在线催更TMOE2025）&lt;/p&gt;
&lt;h3 id="进入tmoe之前"&gt;进入TMOE之前
&lt;/h3&gt;&lt;p&gt;在开始图形化之前，墙裂建议各位先切换为普通用户，如果一直使用root用户来安装软件会遇到许多不便（很多软件会因安全问题而停止运行）&lt;/p&gt;
&lt;h3 id="进入tmoe"&gt;进入TMOE
&lt;/h3&gt;&lt;h4 id="安装桌面"&gt;安装桌面
&lt;/h4&gt;&lt;p&gt;Ubuntu虚拟机应该是默认自带&lt;code&gt;curl&lt;/code&gt;下载器的，如果没有请使用以下命令安装&lt;code&gt;curl&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install -y curl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后键入以下命令安装TMOE管理器&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash -c &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -L gitee.com/mo2/linux/raw/2/2&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;接下来就是漫长的安装过程了，这里按照提示走就行，记得把下载源设置为gitee，不然速度会更酸爽。桌面环境我选择了Xfce，因为它够轻量，而且可定制性很强。还有一点，设置VNC时最好使用&lt;code&gt;TigerVNC&lt;/code&gt;它的优化和功能都比&lt;code&gt;TightVNC&lt;/code&gt;要好。&lt;/p&gt;
&lt;p&gt;还有一点，在配置完VNC后，记得回到虚拟机处再配置相应的端口转发。&lt;/p&gt;
&lt;h4 id="体验强大功能"&gt;体验强大功能
&lt;/h4&gt;&lt;p&gt;到这里时，桌面应该就能在VNC中正常显示了，但可以看到它仍处于百废待兴的状态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VNC显示比例不合适&lt;/li&gt;
&lt;li&gt;界面比较丑陋&lt;/li&gt;
&lt;li&gt;默认浏览器打不开&lt;/li&gt;
&lt;li&gt;应用十分稀少&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而这些，TMOE中早已有了对策————所有这些问题都可以在上面一站式解决！（其实还需要一点场外援助）&lt;/p&gt;
&lt;p&gt;下面就可以自由探索TMOE并美化自己的终端和桌面了！在这里我提供一些思路供参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;去&lt;a class="link" href="https://www.xfce-look.org/browse/" target="_blank" rel="noopener"
 &gt;xfce-looks网站&lt;/a&gt;上下载主题和图标包并使用TMOE本地主题安装器来安装（推荐Orchis-Dark主题和Papirus-Dark图标包）&lt;/li&gt;
&lt;li&gt;安装Chromium或Edge-dev浏览器&lt;/li&gt;
&lt;li&gt;安装Terminology终端模拟器并&lt;a class="link" href="https://developer.baidu.com/article/detail.html?id=3116569" target="_blank" rel="noopener"
 &gt;将其设置为默认终端&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;安装Bingle以获取必应每日精选壁纸（有WE的去安装Steam更好）&lt;/li&gt;
&lt;li&gt;安装Tmoe-Zsh强大Shell&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="更多"&gt;更多
&lt;/h2&gt;&lt;h3 id="一些问题解决方案"&gt;一些问题&amp;amp;解决方案
&lt;/h3&gt;&lt;h4 id="自动死机"&gt;自动死机
&lt;/h4&gt;&lt;p&gt;这是我遇到的一个奇怪的问题。在桌面环境闲置一段时间后整个虚拟机会被自动挂起（suspend），即SSH和VNC乃至虚拟机界面全都卡死无法操作。在我眼中这跟死机没有任何不同，但之前在手机上使用PRoot容器配置桌面环境时从未出现过这个问题&lt;/p&gt;
&lt;p&gt;我尝试过禁用虚拟机的挂起功能，也曾尝试修改&lt;code&gt;/etc/systemd/logind.conf&lt;/code&gt;{: .filepath}&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;，还查看过Xfce设置中的电源选项，但都无功而返。&lt;/p&gt;
&lt;p&gt;最后禁用了系统休眠服务就解决了，方法如下&lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在终端中输入命令：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;查看服务是否禁用成功：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl status sleep.target suspend.target hibernate.target hybrid-sleep.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="终端字体显示乱码"&gt;终端字体显示乱码
&lt;/h4&gt;&lt;p&gt;在安装Tmoe-Zsh（尤其是使用Powerlevel10k主题）后终端可能会出现乱码，像这样：&lt;/p&gt;
&lt;p&gt;&lt;img alt="X11的自带终端是真飞舞" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://raw.gitcode.com/areacloser/images-for-hugo-blog/raw/main/uxterm.png"&gt;&lt;/p&gt;
&lt;p&gt;这时我们就需要找到一款合适的字体来显示其中的符号了，那就是————&lt;a class="link" href="https://github.com/ryanoasis/nerd-fonts/releases" target="_blank" rel="noopener"
 &gt;Nerd Fonts&lt;/a&gt;！&lt;/p&gt;
&lt;p&gt;这里推荐几款不错的字体，只要下载并安装它们，你的终端就会变得炫酷无比！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/Inconsolata.zip" target="_blank" rel="noopener"
 &gt;Inconsolata&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/JetBrainsMono.zip" target="_blank" rel="noopener"
 &gt;JetBrains Mono&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/FiraCode.zip" target="_blank" rel="noopener"
 &gt;FiraCode&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="root情况下electron应用打不开"&gt;root情况下Electron应用打不开
&lt;/h4&gt;&lt;p&gt;这个解决方法比较简单，只需要在启动参数最后面加上&lt;code&gt;--no-sandbox&lt;/code&gt;就可以了，不过浏览器会在顶部弹出警告栏，让人心烦。&lt;/p&gt;
&lt;h3 id="未完成的事情"&gt;未完成的事情
&lt;/h3&gt;&lt;h4 id="配置编辑器"&gt;配置编辑器
&lt;/h4&gt;&lt;p&gt;由于Ubuntu软件源比较落后，很多程序用&lt;code&gt;apt&lt;/code&gt;都下不了最新版本，比如Neovim，通用稳定版都出到0.10了，Ubuntu还在倒腾0.6的版本。无奈我只能使用Unstable不稳定源，结果就是电脑上Neovim每天都更新而且bug奇多。&lt;/p&gt;
&lt;p&gt;&lt;img alt="已经彻底废了" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://raw.gitcode.com/areacloser/images-for-hugo-blog/raw/main/nvim.png"&gt;&lt;/p&gt;
&lt;p&gt;至于Emacs，我之前在手机上也曾尝试过配置，但仍以失败告终，现在它在我桌面上只是个摆设了。&lt;/p&gt;
&lt;p&gt;还有VSCode，我认为我的电脑没有这个能力运行。&lt;/p&gt;
&lt;h4 id="本地搭建个人网站"&gt;本地搭建个人网站
&lt;/h4&gt;&lt;p&gt;正如你所看到的，这个网站是经由Github Actions搭建，以及Github Pages部署和托管而成的，我曾尝试将工作环境转移到这台虚拟机上，但种种问题使得我的计划不了了之：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本地Ruby包依赖管理器Bundler与Github不匹配，但受制于网络，无法自动获取对应版本的Bundler&lt;/li&gt;
&lt;li&gt;Obsidian编辑器在虚拟机上无法正常工作&lt;/li&gt;
&lt;li&gt;无法正常输入中文（见下一节）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="设置中文输入法"&gt;设置中文输入法
&lt;/h4&gt;&lt;p&gt;网上关于配置中文输入法是无论是iBus框架还是Fcitx框架，都需要在“语言支持”选项中切换语言为汉语，但不知为何我的语言选项中汉语被禁用了，但又处于已安装状态，这导致我不能在虚拟机内输入中文而必须要在外部创建一个文本交换文件，用着真的很不方便。&lt;/p&gt;
&lt;p&gt;&lt;img alt="这是为什么呢" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://raw.gitcode.com/areacloser/images-for-hugo-blog/raw/main/lang.png"&gt;&lt;/p&gt;
&lt;h4 id="配置开机自启动脚本"&gt;配置开机自启动脚本
&lt;/h4&gt;
 &lt;blockquote&gt;
 &lt;p&gt;起因：每次登录进Ubuntu是桌面环境都是默认关闭的，需要手动输入startvnc命令才能开始VNC连接，如果提前连接MobaXterm会卡死，因此想让虚拟机一开机就启动桌面环境。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;许多开机自启动的教程都是像这样：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.cnblogs.com/king-dom/p/17371747.html" target="_blank" rel="noopener"
 &gt;Ubuntu22.04 rc-local 配置开机自启动脚本 - 博客园&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.cnblogs.com/ALice1024/p/17302426.html" target="_blank" rel="noopener"
 &gt;ubuntu22.04 添加开机启动脚本 - 博客园&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其基本思路不外乎修改或创建系统服务，但是在Ubuntu虚拟机上这行不通。修改&lt;code&gt;rc-local.service&lt;/code&gt;服务后，我的虚拟机卡在开机界面进不去，自己创建的服务又无法正常工作（事实上桌面会直接卡死）。&lt;/p&gt;
&lt;p&gt;最后只能使用&lt;code&gt;.bashrc&lt;/code&gt;，好像也没什么用（我的默认终端是Zsh，可能是要修改&lt;code&gt;.zshrc&lt;/code&gt;）。&lt;/p&gt;
&lt;h2 id="后记"&gt;后记
&lt;/h2&gt;&lt;p&gt;明天叕要开学了，假期过得真是快呀。还有很多的东西要学，还有很多的东西想学，不知何时能够再更一次？&lt;/p&gt;
&lt;p&gt;本来还想发一期WxPython学习笔记的，现在只好作罢。&lt;/p&gt;
&lt;p&gt;总之，下次再会吧！&lt;/p&gt;
&lt;h2 id="脚注"&gt;脚注
&lt;/h2&gt;&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;a class="link" href="https://zhuanlan.zhihu.com/p/641482808" target="_blank" rel="noopener"
 &gt;ubuntu 22.04 server设置中文 - 知乎&lt;/a&gt;&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;&lt;a class="link" href="https://haohe.fun/2021/04/tmoe-linux%EF%BC%9A%E5%9C%A8android-%E5%92%8Cwindows10%E4%B8%8A%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85-gnu-linux%E5%AE%B9%E5%99%A8" target="_blank" rel="noopener"
 &gt;Tmoe-linux：在Android 和Windows10上一键安装 GNU/Linux容器 - 我的旅游记录&lt;/a&gt;&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;&lt;a class="link" href="https://www.cnblogs.com/nangongergou/p/18042535" target="_blank" rel="noopener"
 &gt;ubuntu使用－ubuntu22.04关闭自动挂起功能 - 博客园&lt;/a&gt;&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.csdn.net/VictoriaLy/article/details/134684502" target="_blank" rel="noopener"
 &gt;Ubuntu防止休眠和挂起（笔记） - CSDN&lt;/a&gt;&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description></item></channel></rss>