<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>TraceofLight (ZH)</title><description>게임 개발, 그래픽스 프로그래밍, 데이터베이스 엔지니어링을 기록하는 TraceofLight의 기술 아카이브입니다.</description><link>https://www.traceoflight.dev/</link><language>zh</language><atom:link href="https://www.traceoflight.dev/zh/rss.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Wed, 06 May 2026 01:18:04 GMT</lastBuildDate><item><title>2026 年团结路演的收获</title><link>https://www.traceoflight.dev/zh/blog/unity-roadshow-2026/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/unity-roadshow-2026/</guid><description>参加 &quot;团结 &quot;路演活动，并快速记录所学内容</description><pubDate>Sun, 19 Apr 2026 13:17:51 GMT</pubDate><content:encoded>&lt;h2&gt;内存基础知识&lt;/h2&gt;
&lt;h3&gt;基本内容&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;我们使用虚拟内存 (Virtual Memory, 以下 VM)、不直接控制物理内存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;VM 由页面构成，根据操作系统不同可能有差异&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Window / Linux 4kb&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;iOS, macOS, Android 16kb&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与页面对应的物理内存帧存在&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;根据内存压力等级，把虚拟内存合并到物理内存&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Page Fault&lt;/h3&gt;
&lt;p&gt;当需要的页面没有加载在物理内存中时被称为 Page Fault&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Clean Page: 原始数据未变化的页面，OS 可以随时释放，回收容易&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dirty Page: 应用程序新写入或修改后信息的页面，无法直接从内存退出&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Memory Footprint&lt;/p&gt;
&lt;p&gt;表达实际内存压力的指标，是把所有 dirty page 大小相加的结果&lt;/p&gt;
&lt;p&gt;Memory Footprint != 物理内存使用量、常驻内存使用量&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;内存管理方法 (Windows vs Linux)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;预约: 不使用物理内存、只分配虚拟内存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提交: 分配与实际虚拟内存等量的物理帧&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;取消提交: 保留预约空间的同时释放物理帧&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Windows: 提供显式 API (virtual alloc, virtual free)&lt;/p&gt;
&lt;p&gt;UNIX Like: 预约和提交没有显式分离&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;mmap 调用是隐式预约内存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;直接访问页面时会发生延迟提交&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有显式 API、取消提交以提示形式工作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OS 决定何时回收页面&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Unity GC 中的处理&lt;/h2&gt;
&lt;h3&gt;Managed Heap&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;C# 内存分配全部在这里进行&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由 Garbage Collector 管理&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 Unity Profiler 中显示为 GC.Alloc&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Garbage Collector&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;定期从 Heap 中回收没有有效引用的 Object&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;执行 GC 也不会减少虚拟内存的总使用量&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;已回收的对象空间，从 OS 角度也是 Dirty&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Segment&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;把连续的页面集合定义为 Segment&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Managed Heap 使用的是 Segment、不是 Raw Page&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个 Segment 中可能分配多个 Object&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;把它分配后再释放，内部即使有未使用的状态，也会显示为 RAM 使用 (因为是 Dirty)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;大多数情况完全没有问题、并且会很快被复用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;太久空着的情况会浪费常驻内存，所以 Unity GC 间歇性地处理&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Unity GC 所做的工作&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;使用 remap 战略&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 GC 多次执行之后，对 Old Empty Segment 执行 Drop、然后分配同样大小的 New Segment&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows Remap 战略: 不释放 Segment、仅 Decommit (因为可以显式处理)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UNIX Like Remap 战略: 通过 munmap &amp;amp; mmap 实现 Remap (Hot Page 效果使缓存命中率高)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过这种方式可以减少常驻内存的使用，是优点&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;不应反复执行 GC.Collect 的理由&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不要强行执行 segment release&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Collect 的开销大、可能导致应用冻结&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;它本身的意图是 decommit 长时间空闲的 segment&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;短暂空着的 segment decommit 与意图不符&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;强制 decommit 不会带来性能改善、只会产生 CPU 成本&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;反正下一帧就会被复用的 segment 也会被 decommit&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Managed Heap 的 VM 使用量只增不减&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Heap 只会增大、不会缩小&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boehm GC 本来的特性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有理由 Trim 虚拟内存的分配量&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;大的虚拟内存 != 大的物理内存使用量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Segment 反正会被复用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;游戏对象每帧都频繁创建和销毁&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每次对象销毁就缩小 segment、只会浪费 CPU 性能&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Unity Boehm GC&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Unity 的 Incremental Boehm GC 是保守 GC (Conservative GC)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这是因为 Unity 提供了用于把过去写的 C# 代码转换为 C++ 的 IL2CPP，从那时起开始主要被使用&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过 IL2CPP 可以支持各种环境，但与 C# 不同，内存 GC 不会自动化，所以采用了开源 GC Boehm GC 看起来如此&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以稳定性为中心而不是性能，把所有看起来像指针的值都视为引用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 GC 期间不改变对象的位置 -&amp;gt; 没有 Compaction、容易出现内存碎片&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;关于 Compaction&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;有利于解决内存碎片的内存压缩工作。把所有未使用的空间清空并重新排列&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于需要精确的引用信息、保守的 GC 中无法实现&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;移动对象的位置会产生成本 (Stop The World + 实际移动)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;CoreCLR GC&lt;/h3&gt;
&lt;p&gt;CoreCLR GC 是 Precise GC、是准确知道内存栈和寄存器中哪些值是引用的方式的 GC&lt;/p&gt;
&lt;p&gt;而 .NET 把 CoreCLR 作为核心引擎使用 (CLR: Common Language Runtime)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;CoreCLR 支持的内容&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CoreCLR GC&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JIT 编译器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Excecption Control&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;misc...&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;该 CoreCLR GC (以下 .NET GC) 使用基于代际的内存管理方式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;把 Heap 分为 3 代来管理&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gen 0: 主要包含刚创建的新对象、频繁且快速的 GC 在这里发生 (大多数对象都在这里消亡)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gen 1: 在 Gen 0 中存活下来的对象转移到这里、起 Buffer 作用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gen 2: 长期存活的较重的对象所在的位置、GC 整理这里的成本相对较大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LOH: 非常大的对象会放到这个空间&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在晋升过程中处理 memory Compaction、可以减少碎片化&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;LOH 由于 STW 较长，过去不进行 Compaction、但现在以显式选项化方式进行处理&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;转换的价值？&lt;/h3&gt;
&lt;p&gt;基本上 Unity 转向 .NET 时发生的副作用是 GC 改变、并且强调 GC 不是主要内容。但寻找其价值的话…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;支持 Compaction、可以减少内存碎片化&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以让 GC 成本变得可预测&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>关于容器环境的简要说明</title><link>https://www.traceoflight.dev/zh/blog/difference-btw-container-vm/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/difference-btw-container-vm/</guid><description>记录容器和虚拟机之间的差异及其他经验教训</description><pubDate>Thu, 02 Apr 2026 06:58:20 GMT</pubDate><content:encoded>&lt;h3&gt;&lt;strong&gt;容器的工作原理&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;共享主机操作系统的内核，但像进程一样隔离它&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;内核不兼容怎么办？&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;当然无法运行，但它之所以能在 MAC、WINDOW 等操作系统上运行，是因为它增加了一层额外的虚拟机。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为什么在 Windows 上安装 docker desktop 会告诉你要安装 wsl2？这似乎是因为你需要安装 MS 的 Linux 虚拟机才能让这个基于层的容器运行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;即使问题出在内核版本上，它也会崩溃（试图使用因版本差异而不存在的功能等）。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;结论&lt;/strong&gt;。&lt;/h3&gt;
&lt;p&gt;内核类型必须匹配，功能支持必须没有问题，CPU 架构必须匹配，容器才能运行。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;虚拟机&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;带有管理程序的独立系统，使用单独的内核。有裸机/托管之分，我们使用的主要是托管，由于管理程序位于操作系统之上，因此会有性能损失。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;卷绑定&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;用于确保数据的持久性，通过在主机上挂载特定目录来处理。Linux 本机直接写入 VFS，其他操作系统烧录内部虚拟网络，速度可能相对较慢。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;为什么 Windows 会忽略 chmod&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Windows 使用 ACL（访问控制列表）管理权限，不了解 chmod 如何工作。&lt;/p&gt;
</content:encoded></item><item><title>来自卡夫顿丛林游戏技术实验室的感言</title><link>https://www.traceoflight.dev/zh/blog/jungle-gametech-lab-review/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/jungle-gametech-lab-review/</guid><description>我完成卡夫顿丛林游戏技术实验室第二年工作的故事</description><pubDate>Thu, 26 Mar 2026 18:02:12 GMT</pubDate><content:encoded>&lt;h2&gt;in&lt;/h2&gt;
&lt;p&gt;完成课程后，我推迟了大约半年才开始真正的生活，所以我有点担心何时写这篇评论。&lt;/p&gt;
&lt;p&gt;不过，我想在我的记忆变得有点模糊之前，我应该把它写下来，所以就写在这里了。&lt;/p&gt;
&lt;p&gt;我还在上面的媒体中加入了演讲的重播，因为我相信读到这篇文章的人一定还在回味。&lt;/p&gt;
&lt;h2&gt;口腔和口腔前的忧虑&lt;/h2&gt;
&lt;p&gt;首先，我不知道自己是否想直接上牙科学校。我对 2025 年下半年的工作有很多计划。&lt;/p&gt;
&lt;p&gt;但是，我选择了入学，因为我觉得这些计划一般都没有结果，而我有一个相当不错的选择。&lt;/p&gt;
&lt;/p
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;https://traceoflight.dev/media/image/240d3d9a-5133-45d9-a584-df6d6f8dc511-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我有几次面试都不太顺利，所以我一直在想如何弥补自己经验上的不足。&lt;/p&gt;
&lt;p&gt;我以前从未接触过市面上的实时 3D 引擎，因此无法解释其整体功能，更不用说内部逻辑了。&lt;/p&gt;
&lt;p&gt;因此，当我带着从与人工智能斗争中获得的所有知识站在面试官面前时，我只能做出肤浅的解释。&lt;/p&gt;
&lt;p&gt;现在回想起来，面试官听到这些答案时一定会怎么想，我觉得非常尴尬。&lt;/p&gt;
&lt;/p
&lt;p&gt;当时，我认为参加课程有两方面的风险。&lt;/p&gt;
&lt;p&gt;我不知道课程是什么样的，也不知道结果会怎样，因为我之前只参加过一次课程，而且还没有完成。&lt;/p&gt;
&lt;p&gt;第二个风险是我不得不放弃这个课程，因为我感兴趣的游戏公司通常在下半年招聘实习生。&lt;/p&gt;
&lt;p&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;权衡再三之后，我决定留在系里。现在回想起来，我觉得我参加的信息交流会影响很大。&lt;/p&gt;
&lt;p&gt;丛林课程中有一个游戏实验室，所以我一直在考虑是否要选修这门课程，如果要选修，又应该报考哪门课程。&lt;/p&gt;
&lt;h2&gt;关于课程&lt;/h2&gt;
&lt;p&gt;我不确定课程的结果如何，但到目前为止，我对这次经历非常满意。&lt;/p&gt;
&lt;p&gt;我不会太详细地介绍我们在课程中做的事情和遇到的情况，因为用教练的话来说，这会 &amp;quot;扫了丛林战士的兴&amp;quot;。&lt;/p&gt;
&lt;p&gt;不过，我可以告诉大家，TechLab 并不是一个简单的过程。几乎不可能同时兼顾其他任务，而且整个课程期间教室里很少熄灯。&lt;/p&gt;
&lt;p&gt;不过，可以肯定地说，在离开课程时，您将掌握大量的知识，并对商用实时 3D 引擎有深刻的了解。&lt;/p&gt;
&lt;h2&gt;谁应该参加？&lt;/h2&gt;
&lt;p&gt;带一份演示文稿可能是最直观的做法。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;https://traceoflight.dev/media/image/2572851e-3357-4318-803f-1cac3e951f91-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我觉得想更多了解这些事情的人应该来。你会有更多的了解。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;https://traceoflight.dev/media/image/b21999e7-643c-4d5f-bfbf-f3c801e197f3-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我知道我说过我不会涉及这些，但对这里的一些图形和开发环境感到好奇的人应该考虑参加技术实验室。&lt;/p&gt;
&lt;p&gt;上完课之后，你至少能背诵农历，还能分享关于它们的简单提卡。&lt;/p&gt;
&lt;h2&gt;最后的想法&lt;/h2&gt;
&lt;p&gt;现在我已经完成了课程，我很高兴我完成了课程，但我还有很多事情需要在未来安排，因为我在这么短的时间内经历了很多事情。&lt;/p&gt;
&lt;p&gt;不过，在消化了所有内容之后，我想我将成为一名更加成熟的开发人员。&lt;/p&gt;
&lt;p&gt;很多人都在谈论人工智能的发展会导致行业劳动力的萎缩，但我会尽我所能。&lt;/p&gt;
&lt;p&gt;最近也有很多关于成长气馁的议论，但我肯定看到了我周围的人不断成长的好事，所以我认为我们将能在一段时间内保持这种势头。&lt;/p&gt;
</content:encoded></item><item><title>构建 Windows / macOS 统一终端环境</title><link>https://www.traceoflight.dev/zh/blog/cross-platform-terminal-setting/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/cross-platform-terminal-setting/</guid><description>在 Windows 和 macOS 上均可运行的跨平台终端环境搭建指南</description><pubDate>Thu, 26 Mar 2026 12:18:01 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;br /&gt;
&lt;p&gt;由于最近升级了MacBook Air，我感到有必要重新配置系统环境。&lt;/p&gt;
&lt;p&gt;虽然从M1到M5的性能提升令人满意，但在尝试恢复原有使用环境时，我发现这需要花费大量精力，因此决定借此机会将整个过程记录下来，以便日后能更轻松地进行配置。&lt;/p&gt;
&lt;h3&gt;[2026 Mac 终端完美配置（Ghostty + Starship + AI 编程环境）](&lt;a href=&quot;https://blog.dnd.ac/settings-mac-terminal-2026/&quot;&gt;https://blog.dnd.ac/settings-mac-terminal-2026/&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;)&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;在这个过程中，给我留下深刻印象的文档就是该链接中的资料，作者将整洁且精心配置的环境以脚本形式留存下来，对我帮助很大。&lt;/p&gt;
&lt;p&gt;先说结论，最终我成功构建了如下形式的终端环境：&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;https://traceoflight.dev/media/image/f0670bf2-9240-4320-ad5e-6367803485d2-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;。其内部架构主要基于 Wezterm + Nushell + LazyVim 进行配置。&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;您可以在 [Github 链接](&lt;a href=&quot;https://www.github.com/TraceofLight/global-terminal-settings&quot;&gt;https://www.github.com/TraceofLight/global-terminal-settings&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;) 中查看完整的配置指南，该指南旨在帮助您在 Windows 和 MacOS 上构建完全一致的环境。&lt;/p&gt;
&lt;h2&gt;目标设定&lt;/h2&gt;
&lt;br /&gt;
&lt;p&gt;该项目的目标非常明确：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在 Windows / MacOS 上使用相同的终端环境&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基于 LazyVim 的编辑器能够无障碍运行&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与现有使用环境差异不大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 tmux 等多窗口管理工具时&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;不会遇到困难 为了实现这些目标，我着手进行了相关工作。&lt;/p&gt;
&lt;h2&gt;实施过程&lt;/h2&gt;
&lt;br /&gt;
&lt;p&gt;首先需要选择技术方案。目前终端模拟器的趋势是具备GPU加速渲染能力的GUI工具，这类工具之所以备受青睐，正是因为其运行速度快且支持自定义主题。正如上文链接所示，构建终端环境需要这些特性，因此我最终选择了其中的Wezterm。&lt;/p&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;终端模拟器&lt;/p&gt;
&lt;p&gt;由于需要在跨平台环境下提供一致的用户体验，我认为具备成熟生态系统的跨平台终端模拟器主要有Alacritty和Wezterm。追求极简风格的Alacritty在扩展性上略显不足，因此最终选择了Wezterm。它内置多路复用器也是一大优势。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Shell&lt;/p&gt;
&lt;p&gt;为了确保在两个平台上提供一致的使用体验，我最初计划统一使用支持 Unix 命令的环境，因此决定在 Windows 上使用 bash，在 macOS 上使用 zsh。但随后遇到了一些问题，最终方案是基于 Nushell 进行统一。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LazyVim&lt;/p&gt;
&lt;p&gt;实际上，这部分我原本就已使用相关工具，且在大部分环境下都能无缝集成，因此并不困难。 虽然原本使用的是SpaceVim，但该工具已[停止维护](&lt;a href=&quot;https://wsdjeg.net/why-spacevim-is-archived/&quot;&gt;https://wsdjeg.net/why-spacevim-is-archived/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;)，且我转用LazyVim已有段时间。加上我主要使用IDE，LazyVim仅作为辅助工具，因此安装过程相当顺利。&lt;/p&gt;
&lt;h2&gt;遇到的问题&lt;/h2&gt;
&lt;p&gt;在此过程中存在几个问题，其中两个都与转用Nushell有关。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在 Windows 上，bash 的运行速度慢得令人难以忍受&lt;/p&gt;
&lt;p&gt;事实上，后来确认这似乎是意料之中的结果。我发现，在 Windows 环境下，为了处理 POSIX 风格的操作，系统会额外增加一层兼容性处理机制。因此，虽然也曾考虑过切换到 WSL2 环境，但那最终与直接使用 Linux 并无二致，所以被排除在外。&lt;/p&gt;
&lt;p&gt;-&amp;gt; 为解决这一问题，引入了 nushell 作为工具。考虑到了它与 Unix 命令有大量兼容之处、基于 Rust 设计因此在性能上有所保障，以及在 macOS 上也能进行相同的环境配置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows 版 nushell 中 navi 插件无法运行&lt;/p&gt;
&lt;p&gt;navi是一款用于参考终端命令速查表的插件。虽然使用频率不高，但如果该工具的功能完全无法运行会带来不便，因此我们尝试了多种解决方法。最终，我们通过分叉navi来解决该问题，并改用重新构建的插件。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;原因：即使用户shell发生变更，内部仍会应用基于bash的语法，导致在使用nushell时出现故障&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解决方案：不再通过 shellscript 命令处理该部分，而是通过以下方式移除相关依赖：在原本需要使用 wget 的地方改用 Rust HTTP 客户端，在原本需要使用 bash 的地方改用 pwsh，以此消除内部辅助程序对 bash 的依赖&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[详细修改记录](&lt;a href=&quot;https://github.com/TraceofLight/navi/tree/fix/nushell-usability&quot;&gt;https://github.com/TraceofLight/navi/tree/fix/nushell-usability&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;)&lt;/p&gt;
&lt;h2&gt;结论&lt;/h2&gt;
&lt;p&gt;开发人员使用终端的频率相当高，如果环境能够统一，使用起来自然会更方便。因此，支持跨平台且保持一致使用体验的 JetBrains IDE 难道不具有优势吗？同样地，如果自己在终端方面追求的是在各种环境下保持统一的使用体验，那么尝试这种方式似乎也不错。&lt;/p&gt;
</content:encoded></item><item><title>std::variant &amp;amp; std::visit</title><link>https://www.traceoflight.dev/zh/blog/variant-and-visit/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/variant-and-visit/</guid><description>关于 C++17 中新增的 variant 和 visit 的内容总结</description><pubDate>Mon, 28 Jul 2025 14:13:37 GMT</pubDate><content:encoded>&lt;h3&gt;其他信息&lt;/h3&gt;
&lt;p&gt;[相关文档](&lt;a href=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0088r3.html&quot;&gt;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0088r3.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;)&lt;/p&gt;
&lt;p&gt;上述链接中介绍了从 C++17 开始新增的 Variant 及其添加原因。简而言之，由于 Boost 库中相关功能已被使用太久，因此有人提议不要再拖延，应尽快将其纳入标准，将其作为 std::optional 引入。&lt;/p&gt;
&lt;h3&gt;内部结构&lt;/h3&gt;
&lt;h4&gt;1. Variant&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;数据缓冲区
用于存储模板参数中最大类型所需的足够大内存空间，通常通过 Union 实现&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;标识符
用于表示当前数据缓冲区中存储了何种类型的对象的索引或标识符。通过使用该标识符，std::variant 能够保证类型安全性&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;凭借充足的内存空间，variant 类型能够实现如下行为。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;
	&lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Tracer&lt;/span&gt;
	{
		std::string name;

		&lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;const&lt;/span&gt; std::string&amp;amp; n) : &lt;span class=&quot;hljs-built_in&quot;&gt;name&lt;/span&gt;(n)
		{
			std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;  [+] &amp;#x27;&amp;quot;&lt;/span&gt; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27; Tracer created (Constructor)\n&amp;quot;&lt;/span&gt;;
		}

		&lt;span class=&quot;hljs-comment&quot;&gt;// Copy Constructor&lt;/span&gt;
		&lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;const&lt;/span&gt; Tracer&amp;amp; other) : &lt;span class=&quot;hljs-built_in&quot;&gt;name&lt;/span&gt;(other.name)
		{
			std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;  [*] &amp;#x27;&amp;quot;&lt;/span&gt; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27; Tracer copy-constructed (Copy Constructor)\n&amp;quot;&lt;/span&gt;;
		}

		~&lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;()
		{
			std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;  [-] &amp;#x27;&amp;quot;&lt;/span&gt; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27; Tracer destroyed (Destructor)\n&amp;quot;&lt;/span&gt;;
		}
	};

	&lt;span class=&quot;hljs-comment&quot;&gt;// 1. Initialize the variant with a Tracer type.&lt;/span&gt;
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;1. Initializing variant with Tracer(\&amp;quot;Apple\&amp;quot;).\n&amp;quot;&lt;/span&gt;;
	std::variant&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;, Tracer&amp;gt; var = &lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Apple&amp;quot;&lt;/span&gt;);
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;   Variant now holds Tracer(\&amp;quot;Apple\&amp;quot;).\n\n&amp;quot;&lt;/span&gt;;

	&lt;span class=&quot;hljs-comment&quot;&gt;// 2. Assign a value of a different type (int).&lt;/span&gt;
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2. Assigning integer 100 to the variant.\n&amp;quot;&lt;/span&gt;;
	var = &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt;;
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;   Variant now holds integer 100.\n\n&amp;quot;&lt;/span&gt;;

	&lt;span class=&quot;hljs-comment&quot;&gt;// 3. Assign another Tracer type value again.&lt;/span&gt;
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3. Assigning Tracer(\&amp;quot;Banana\&amp;quot;) to the variant.\n&amp;quot;&lt;/span&gt;;
	var = &lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Banana&amp;quot;&lt;/span&gt;);
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;   Variant now holds Tracer(\&amp;quot;Banana\&amp;quot;).\n\n&amp;quot;&lt;/span&gt;;

	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;4. main function is about to end.\n&amp;quot;&lt;/span&gt;;
	&lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行此类代码将得到如下结果。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1. Initializing variant with Tracer(&amp;quot;Apple&amp;quot;).
  [+] &amp;#x27;Apple&amp;#x27; Tracer created (Constructor)
  [*] &amp;#x27;Apple&amp;#x27; Tracer copy-constructed (Copy Constructor)
  [-] &amp;#x27;Apple&amp;#x27; Tracer destroyed (Destructor)
   Variant now holds Tracer(&amp;quot;Apple&amp;quot;).

2. Assigning integer 100 to the variant.
  [-] &amp;#x27;Apple&amp;#x27; Tracer destroyed (Destructor)
   Variant now holds integer 100.

3. Assigning Tracer(&amp;quot;Banana&amp;quot;) to the variant.
  [+] &amp;#x27;Banana&amp;#x27; Tracer created (Constructor)
  [*] &amp;#x27;Banana&amp;#x27; Tracer copy-constructed (Copy Constructor)
  [-] &amp;#x27;Banana&amp;#x27; Tracer destroyed (Destructor)
   Variant now holds Tracer(&amp;quot;Banana&amp;quot;).

4. main function is about to end.
  [-] &amp;#x27;Banana&amp;#x27; Tracer destroyed (Destructor)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以观察到，先调用原有值的析构函数，随后在栈上创建临时对象，最后将复制生成的值移入自身内存缓冲区。&lt;/p&gt;
&lt;p&gt;因此，如果内部通过联合体（union）保留存储最大尺寸类的空间，无论variant类型中传入什么，都能确保其正常使用！&lt;/p&gt;
&lt;h4&gt;2. 访问机制&lt;/h4&gt;
&lt;p&gt;虽然不同库的实现各异，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;函数指针表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch 语句&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但通常可分为这两种形式。实际上，除了实现方式、开销以及编译器优化方面存在些许差异外，基本都可以理解为：通过检查标识符，根据激活的类型调用相应的函数。&lt;/p&gt;
</content:encoded></item><item><title>[钟曼手册] 02.故障排除策略</title><link>https://www.traceoflight.dev/zh/blog/jongmanbook02/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/jongmanbook02/</guid><description>算法的故障排除策略 第 2 章小结</description><pubDate>Wed, 18 Dec 2024 04:27:16 GMT</pubDate><content:encoded>&lt;h2&gt;故障排除过程&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;阅读并理解问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用熟悉的术语重新定义问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;计划如何解决问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;验证你的计划。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将其作为一项计划加以实施。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;反思你是如何解决问题的，并寻找改进方法。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1) 阅读并理解问题&lt;/h3&gt;
&lt;p&gt;为了避免犯误读问题的错误，你应该积极阅读问题，并努力充分理解问题的要求。如果你错过了一个小的限制条件，往往就无法解决这个问题，而竞赛往往不会放过任何一个小错误。&lt;/p&gt;
&lt;h3&gt;2) 重新定义和抽象&lt;/h3&gt;
&lt;p&gt;使用你容易处理的概念，用你自己的语言重新表述问题，这是直观理解问题对你的要求所必需的，问题越复杂，这一点就越重要。
对于做同样事情的程序，不同的人可能会有不同的理解，这取决于你如何重构问题的本质。
可以说，抽象化决定了程序的发展方向，因为它可以让难题变得更容易解决，让容易解决的难题变得更难解决。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;抽象：将现实世界的概念转化为我们更容易处理的数学/计算概念的过程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3) 规划&lt;/h3&gt;
&lt;p&gt;决定如何解决问题，选择要使用的算法和数据结构。这是整个过程中最重要的部分，如果你不能立即找到问题的解决方案，你将在这部分花费最多的时间。&lt;/p&gt;
&lt;h4&gt;4) 验证你的计划&lt;/h4&gt;
&lt;p&gt;在开始实施之前，我们需要验证我们的计划。我们需要证明，我们设计的算法在所有情况下都能正确执行要求，并且执行所需的时间和使用的内存都在问题的限制范围内。&lt;/p&gt;
&lt;h4&gt;5) 实施计划&lt;/h4&gt;
&lt;p&gt;在执行计划时，要始终牢记效率和准确性。&lt;/p&gt;
&lt;h3&gt;6) 进行回顾总结&lt;/h3&gt;
&lt;p&gt;这一步可能不会立即产生直接影响，但从长远来看影响最大。
当你重新解决以前解决过的问题时，你可能会找到更高效的算法，写出更简洁的代码，甚至找到更直观的方法来推导相同的算法。
进行回顾的最有效方法是写下每次解决问题的经验。&lt;/p&gt;
&lt;p&gt;记录下你的方法、关键的顿悟、错误答案的原因等，可以减少错误，有助于形成模式。查看其他人解决过的代码也能提供你可能没有想到的见解。&lt;/p&gt;
&lt;p&gt;一段时间后，即使你还没有解决它，也可以参考其他人的代码或解决方案，但一定要回顾它。&lt;/p&gt;
&lt;h2&gt;疑难解答策略&lt;/h2&gt;
&lt;h3&gt;1) 直觉和系统方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;你以前解决过类似的问题吗？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你应该能够理解和转换原理，而不仅仅是解决原理。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;你能从简单的方法入手吗？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;能在不知道的情况下求解吗？还有一种方法，可以从最简单的算法入手，并对其进行优化，从而实现&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能否建立算法效率基线？&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能否制定解决问题的过程？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在解题过程中举例说明，等等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;我能简化问题吗？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先解决给定问题的一个较容易的变式&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能否举例说明？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;几何图形更直观易懂&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能否用公式表示？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;纯文本 → 公式有助于解决问题&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题能否分解？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如何将问题转化为更易解决的形式，如分解约束条件&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能否通过逆向思维解决问题？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;典型例子：梯子游戏&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;你能从下往上而不是尝试前面的所有路径来减少阶梯的数量吗？&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能否强制执行顺序？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如何在没有顺序的问题中执行顺序？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;举例说明：对一个变量而言，是否存在两种情况/顺序无关紧要 → 决定是否按顺序变换。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能否只考虑某些形式的答案？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;规范化技术&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如何将形式不同但结果相同的答案分组，并只考虑组中的代表。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[有效 C++] 项目 02</title><link>https://www.traceoflight.dev/zh/blog/effective-cpp-02/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/effective-cpp-02/</guid><description>要写 #define，就要想到 const、枚举和内联。</description><pubDate>Tue, 12 Mar 2024 14:40:14 GMT</pubDate><content:encoded>&lt;h3&gt;优先选择 Const、枚举和 Inline，而不是 #define&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;表示编译器优于预处理&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;#define FOO 1.024&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;上述情况是预处理器在编译前替换字符串。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;上述符号 FOO 可以在编译器不知道其存在的情况下被移除，因此它可能在错误中作为常量出现，所以如果存在与此相关的 bug，追查起来会很费时间。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;const double FOO = 1.024；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;解决方法是用常量替换宏。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编译器可以清楚地观察到常量，也可以清楚地在符号表中输入常量。此外，如果通过预处理器进行批量替换，可能会创建多个对象副本，但如果是常量，创建的副本不会超过一个。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[有效 C++] 项目 01</title><link>https://www.traceoflight.dev/zh/blog/effective-cpp-01/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/effective-cpp-01/</guid><description>将 C++ 视为一个语言家族至关重要</description><pubDate>Tue, 12 Mar 2024 14:01:04 GMT</pubDate><content:encoded>&lt;h3&gt;C++ 是多范式编程语言&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;最初是从加入面向对象功能的 C 开始的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;目前支持过程式、面向对象、函数式、泛型乃至元编程&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;泛型编程: 不受数据类型束缚、让一个值可以拥有多种数据类型从而最大化复用性的编程范式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;元编程: 把自身或其他程序作为数据来对待并编写、修改程序的方式。也指把运行时需要执行的部分工作放到编译期完成的方式&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;需要把 C++ 看作不是一门单独的语言、而是语言的联合体，并按照各自的规则去使用&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;C: 很多东西源自 C，但 C++ 提供更好方案的情况很多，所以可以在更受限且更安全的范围内使用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;面向对象 C++: 类存在的 C++ 核心，是面向对象设计最直接作用的部分&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Template C++: 不是经常接触的部分，与主流 C++ 几乎不相互作用，但催生了 TMP 这种强大的范式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;STL: 虽然是 Template 库但属于非常特殊的情况，使用 STL 时有特定的方式，必须遵循其规则&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一旦在上述子语言之间切换，可能会面临要改变策略的情况&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果理解 C++ 不是单一规则、而是各自拥有专属规则的子语言的集合体，就会更容易理解 C++&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[有效 C++] 进入</title><link>https://www.traceoflight.dev/zh/blog/effective-cpp-00/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/effective-cpp-00/</guid><description>有效学习 C++ 的故事</description><pubDate>Tue, 12 Mar 2024 12:45:19 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-fb3d40db998200c1-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;好久没发学习相关的帖子了。&lt;/p&gt;
&lt;p&gt;我还没有全部誊写，但我目前在一家公司从事系统开发工作，在与我写及格推荐信的公司进行比较后，我认为这家公司会更好。&lt;/p&gt;
&lt;p&gt;公司里有人说要学习这本书，所以我觉得在学习的同时利用现有的平台也不错，我会继续写下去。我想通过对这本书的学习，把工作做得更好，但感觉还有点遗憾，因为这本书离我还很远......&lt;/p&gt;
&lt;p&gt;我将为每个项目发布一篇文章。화이팅！&lt;/p&gt;
</content:encoded></item><item><title>42Seoul 拉菲辛体验分享</title><link>https://www.traceoflight.dev/zh/blog/42seoul-la-piscine/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/42seoul-la-piscine/</guid><description>参加第10期首尔拉菲辛第一阶段课程的感想</description><pubDate>Sat, 23 Sep 2023 17:19:05 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;在求职过程中，今年年中SSAFY即将结束之际，出于对备考周期可能延长的不确定性，我在向企业投递简历的同时，也花时间了解了各种编程训练营和培训课程。&lt;/p&gt;
&lt;p&gt;最终，我认为最适合我的课程是42Seoul，于是决定报名参加。&lt;/p&gt;
&lt;p&gt;虽然理由有很多，但其中最吸引我的是：相比其他编程训练营，它更注重自主学习且时间安排灵活，并且主要涉及相对底层的编程语言。&lt;/p&gt;
&lt;h3&gt;拉菲辛课程进行中&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-1b1c639d3d343b20-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;在完成报到并成功申请拉菲辛课程后，我一边等待课程开始，一边收到了几家企业的最终录用通知。 原本打算放弃课程，但考虑到在职42学员的经验分享以及42的教学体系，我认为完全可以兼顾，于是初期全力投入，之后便开始边工作边学习。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-7a35603c5af347f5-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;了解过42课程的人应该都知道，入学前有一段被称为“拉菲辛”的预备课程。这段课程相当严苛……&lt;/p&gt;
&lt;p&gt;如果是非专业背景且毫无基础的人，恐怕连跟上进度都会很吃力；而对于具备一定编程知识的非专业人士，只要努力的话，应该能取得预期的成果。至于专业背景的人，只要不是因为其他原因无法集中精力，或者没有遭遇不公对待，我认为进入正式课程应该并不困难。&lt;/p&gt;
&lt;p&gt;虽然只是个人看法，但我认为42提供的教育与大学课程有相当大的相似性，因此对非专业背景的人来说可能反而更好。如果已经在大学里系统地学过相关课程，那么对专业背景的人来说，除了42提供的助学金和其他制度外，其优势似乎比其他编程训练营相对不足。&lt;/p&gt;
&lt;p&gt;我之所以考虑入学，除了资助金之外，还因为认为这是一个能弥补专业知识缺失的优质课程；而且这一基本前提在就业后也没有改变，所以我才能坚持完成拉菲辛课程。&lt;/p&gt;
&lt;p&gt;（当然，就业后就无法再领取资助金了……）&lt;/p&gt;
&lt;h3&gt;结果&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-881466acbebffd64-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;幸运的是，我取得了好成绩，得以作为42Seoul第10期学员参加本课程。由于课程使用的技术栈与我目前在公司负责的岗位相似，预计能形成良性循环，对此我充满期待。&lt;/p&gt;
&lt;h3&gt;问答&lt;/h3&gt;
&lt;p&gt;针对大家常问的一些问题，我来回答一下：&lt;/p&gt;
&lt;h4&gt;1. 零基础的非专业背景者能通过吗？&lt;/h4&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;虽然早期批次可能有例外，但现在可以重新挑战，而且随着信息的大量公开，几乎是不可能的&lt;/p&gt;
&lt;h4&gt;2. 你会向什么样的人推荐这个课程？&lt;/h4&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;还有大量本科学习时间的专业学生，以及不考虑就业、打算长期积累基础知识的非专业人士。&lt;/p&gt;
&lt;h4&gt;3. 报名前最好了解哪些内容？&lt;/h4&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;了解C语言的基础概念以及初次接触时可能难以理解的指针等知识，知道得越多越好。虽然大家都强调Shell的使用方法，但我还想补充一条建议：务必掌握Git的使用方法。&lt;/p&gt;
&lt;h4&gt;4. 在课程进行过程中，有什么特别想让大家尝试的吗？&lt;/h4&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;就我个人而言，第一届Rush的团队成员都是非常棒的人，作为和他们一起坚持到最后的成员，虽然与他人交流并非绝对必要，但如果机会来了，请务必把握住并积极融入……对于开发者来说，沟通能力与编程能力同样重要！&lt;/p&gt;
</content:encoded></item><item><title>[术语表] 文件系统</title><link>https://www.traceoflight.dev/zh/blog/file-system/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/file-system/</guid><description>文件系统相关工作术语表</description><pubDate>Thu, 14 Sep 2023 14:36:39 GMT</pubDate><content:encoded>&lt;h4&gt;在&lt;/h4&gt;
&lt;p&gt;我意识到，在我目前的工作中，我对基础术语的了解还有些欠缺，因此我决定做一点研究，并将我所知道的术语做一个简要总结。&lt;/p&gt;
&lt;h3&gt;文件描述符&lt;/h3&gt;
&lt;p&gt;在 Linux 和类 Unix 系统中
进程处理文件时使用的一种类型的值&lt;/p&gt;
&lt;p&gt;当进程打开一个文件时，内核会为其分配处理器文件描述符编号中最小的未使用值，以便后续使用系统调用访问打开的文件时可以使用描述符值来引用该文件。&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;默认分配的描述符&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;标准输入（标准输入）
标准输出
标准错误&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Inode&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;索引节点的简称，是快速定位文件的节点。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Inode 是一个节点，它为 Linux 中的所有文件编制索引，并保存这些文件的元数据。Inode 保存着 list 命令输出的元数据。&lt;/p&gt;
&lt;h3&gt;符号链接&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;带有指向源文件 inode 信息的文件。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在内部，通过 inode 号访问文件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有一个新的 inode，其中不包含任何有关原始文件的信息&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;cf) 硬链接&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;具有新 inode 的文件，而不是具有新 inode 的文件，只是逐字复制了 inode&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与真正拷贝的区别在于没有写入额外的数据，与复制不同&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;块设备和字符设备&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;根据数据传输方法的不同对设备进行分类&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;块：以块或扇区等量化单位传输数据，IO 传输速度快&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;字符：以字节为单位传输数据，IO 传输速度可能稍慢，但通过应用阶段的缓冲控制，性能会有差异。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;###原始设备&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;未设置文件系统的设备&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;操作系统内核没有缓冲，数据直接从设备传输，如果设备有自己的缓存系统，则使用此方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;磁盘 IO 性能好，CPU 开销低。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;避免操作系统文件系统开销，并可减少操作系统缓冲区大小。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;作为原始设备使用，因为在系统中配置为共享磁盘时，无法进行并发访问。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;IO 调度器&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;系统中负责排序、合并和确定请求处理顺序的部分，以提高磁盘 I/O 效率。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对硬盘等设备特别有用，因为在这些设备上，寻道时间很昂贵，合并同一位置的请求很有效；在固态硬盘上，效率减半。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;类型&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;noop：无操作，用于高性能磁盘&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cfq （完全公平队列）：给每个进程一个 IO 队列，并尽可能均匀地调度，用于大量进程产生细粒度 IO 的情况&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;deadline：优先处理更接近阈值的进程，优化延迟，平衡所有 I/O，适用于少数进程产生大量 I/O 的环境。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;预期性：预测未来 I/O 请求的位置，并优先处理最近的 I/O 请求；传统硬盘采用的结构是输入和输出汇总，可能会增加延迟。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[日本银行 9519，中国人民银行]昏昏欲睡</title><link>https://www.traceoflight.dev/zh/blog/boj9519/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj9519/</guid><description>BOJ 9519，&quot;瞌睡 &quot;问题的 C++ 解决方案</description><pubDate>Mon, 04 Sep 2023 14:32:38 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp3@@&quot;&gt;boj 9519&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;实现, 字符串, 模拟&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;这个问题最初是通过全面探索解决的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;首先测量字符串的长度&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分配一个与字符串长度相等的数字向量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;根据问题条件重复并翻转&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果翻转了一定次数，则使用相应的哈希值将它们按相反顺序排列&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;你将看到原始图像！&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里最重要的一点是，你可以根据问题的条件反复翻转，而循环返回的结果将始终与初始数组相同。&lt;/p&gt;
&lt;p&gt;找到上述规则后，你可以使用&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;先测量字符串的长度&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;0 ~ 指定一个与字符串长度相等的数字向量&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;检查从 1 到（字符串长度 - 1）的循环次数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重复翻转总次数除以循环次数，得出哈希值&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果翻转了一定次数，则使用该散列值按相反顺序排列&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;你可以看到原始图像！&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;看起来像这样&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++)
    {
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; target_length / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;; j++)
        {
            temp = result.&lt;span class=&quot;hljs-built_in&quot;&gt;back&lt;/span&gt;();
            result.&lt;span class=&quot;hljs-built_in&quot;&gt;pop_back&lt;/span&gt;();
            result.&lt;span class=&quot;hljs-built_in&quot;&gt;insert&lt;/span&gt;(result.&lt;span class=&quot;hljs-built_in&quot;&gt;begin&lt;/span&gt;() + &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * j + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, temp);
        }

		&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (start_vector == result)
		{
			cycle = i;
			&lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; ;
		}
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;起初，我们如上图所示直接移动数组，但这造成了一些开销，因为插入后的数组也要移动，所以花费的时间稍长。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++)
    {
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt;();
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;resize&lt;/span&gt;(target_length);
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; target_length; j++)
        {
			&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!(j % &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))
				temp_vector[j] = result[j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;];
			&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
				temp_vector[j] = result[target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - (j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)];
        }

		&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (start_vector == temp_vector)
		{
			cycle = i;
			&lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; ;
		}
		&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
			result = temp_vector;
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此，我们使用上述方法提前创建数组，然后逐个插入数值，这样时间只用在数组的最大长度上。&lt;/p&gt;
&lt;h4&gt;求解代码&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 졸려&lt;/span&gt;

&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;namespace&lt;/span&gt; std;

&lt;span class=&quot;hljs-function&quot;&gt;vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;flicker_action&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; target_length, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; count)&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;
&lt;/span&gt;{
    ios_base::&lt;span class=&quot;hljs-built_in&quot;&gt;sync_with_stdio&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;);
    cin.&lt;span class=&quot;hljs-built_in&quot;&gt;tie&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;NULL&lt;/span&gt;);
    cout.&lt;span class=&quot;hljs-built_in&quot;&gt;tie&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;NULL&lt;/span&gt;);

    &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; flicker_number;
    string result_string, init_string;
    vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;char&lt;/span&gt;&amp;gt; string_vector;
    vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt; idx_vector;

    cin &amp;gt;&amp;gt; flicker_number;
    cin.&lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;();
    &lt;span class=&quot;hljs-built_in&quot;&gt;getline&lt;/span&gt;(cin, result_string);

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) result_string.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;(); i++)
        string_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;push_back&lt;/span&gt;(result_string[i]);
    

    idx_vector = &lt;span class=&quot;hljs-built_in&quot;&gt;flicker_action&lt;/span&gt;(result_string.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;(), flicker_number);
    init_string.&lt;span class=&quot;hljs-built_in&quot;&gt;resize&lt;/span&gt;(result_string.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;());

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) result_string.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;(); i++)
        init_string[idx_vector[i]] = result_string[i];

    cout &amp;lt;&amp;lt; init_string &amp;lt;&amp;lt; endl;
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;);
}

&lt;span class=&quot;hljs-function&quot;&gt;vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;flicker_action&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; target_length, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; count)&lt;/span&gt;
&lt;/span&gt;{
    vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt; result, temp_vector, start_vector;
	&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; cycle;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; target_length; i++)
        result.&lt;span class=&quot;hljs-built_in&quot;&gt;push_back&lt;/span&gt;(i);

	start_vector = result;
	cycle = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++)
    {
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt;();
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;resize&lt;/span&gt;(target_length);
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; target_length; j++)
        {
			&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!(j % &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))
				temp_vector[j] = result[j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;];
			&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
				temp_vector[j] = result[target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - (j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)];
        }

		&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (start_vector == temp_vector)
		{
			cycle = i;
			&lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; ;
		}
		&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
			result = temp_vector;
    }

	result = start_vector;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; (count % cycle); i++)
    {
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt;();
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;resize&lt;/span&gt;(target_length);
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; target_length; j++)
        {
			&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!(j % &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))
				temp_vector[j] = result[j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;];
			&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
				temp_vector[j] = result[target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - (j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)];
        }

		result = temp_vector;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; (result);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 4821，CPP] Page counting</title><link>https://www.traceoflight.dev/zh/blog/boj4821/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj4821/</guid><description>BOJ 4821 &quot;页数计算 &quot;问题的 C++ 解决方案</description><pubDate>Sat, 26 Aug 2023 15:04:16 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp1@@&quot;&gt;boj 4821&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;实现, 字符串, 解析&lt;/p&gt;
&lt;h3&gt;包括&lt;/h3&gt;
&lt;p&gt;我最近加入了一家新公司，工作相当繁忙。作为一名新员工，刚进公司就感觉压力很大......不过，我一直在写下各种故事，相信迟早会讲出来的。&lt;/p&gt;
&lt;p&gt;最近，我有一个学习 C 语言的好机会，每当学习 Python 或 Java 遇到时间墙时，我总是很失望，所以我想借此机会用 C++ 解决问题。&lt;/p&gt;
&lt;p&gt;从我使用 C++ 的短暂经历来看，我有一种很好的感觉，那就是它的很多实现都相当繁琐，但速度却能弥补这一点。一旦我掌握了它的诀窍，是否就能利用它的速度优势......？我很期待。&lt;/p&gt;
&lt;h4&gt;说明。&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;向量：动态数组结构，类似于数组，但最大的优点是大小可以灵活改变，内存分配是自动的！&lt;/p&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;npos：无位置，当位置无效时检查索引值。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;stringstream: 将字符串视为流的设备，允许将其视为输入和输出，常用于解析&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;基本逻辑是创建一个可以覆盖整个页面限制范围的 bool 数组，然后检查所有输入的页面范围，最后输出计数值。&lt;/p&gt;
&lt;p&gt;不过，值得注意的是，问题中给出的数值范围可能超出 int 值，因此需要设置一个变量来控制，而且如果给出的范围顺序相反，也有不检查的例外情况。&lt;/p&gt;
&lt;p&gt;这在 Python 中相当容易实现，但当我尝试用 C++ 实现时，代码变得非常长...&lt;/p&gt;
&lt;h3&gt;解决方案代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 페이지 세기&lt;/span&gt;

&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;sstream&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;namespace&lt;/span&gt; std;

&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;
&lt;/span&gt;{
	ios_base::&lt;span class=&quot;hljs-built_in&quot;&gt;sync_with_stdio&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;);
	cin.&lt;span class=&quot;hljs-built_in&quot;&gt;tie&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;NULL&lt;/span&gt;);
	cout.&lt;span class=&quot;hljs-built_in&quot;&gt;tie&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;NULL&lt;/span&gt;);

	&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;				total_page, seperator, start, end, result;
	string			temp, each_range;
	vector&amp;lt;string&amp;gt;	line_info;
	vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt;&amp;gt;	print_info;
	vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt;		result_vector;

	&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;)
	{
		cin &amp;gt;&amp;gt; total_page;

		&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!total_page)
			&lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; ;
		&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
		{
			print_info.&lt;span class=&quot;hljs-built_in&quot;&gt;assign&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1001&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;);
			cin.&lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;();
			&lt;span class=&quot;hljs-built_in&quot;&gt;getline&lt;/span&gt;(cin, temp);
			&lt;span class=&quot;hljs-function&quot;&gt;stringstream &lt;span class=&quot;hljs-title&quot;&gt;range_stream&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(temp)&lt;/span&gt;&lt;/span&gt;;

			&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;getline&lt;/span&gt;(range_stream, each_range, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;,&amp;#x27;&lt;/span&gt;))
			{
				&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-&amp;#x27;&lt;/span&gt;) == string::npos)
				{
					&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;() &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range) &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;)
						print_info[&lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range)] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
				}
				&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
				{
					seperator = each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-&amp;#x27;&lt;/span&gt;);
					&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, seperator).&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;() &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;
						&amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, seperator)) &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;)
						start = &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, seperator));
					&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
						start = &lt;span class=&quot;hljs-number&quot;&gt;1001&lt;/span&gt;;
					&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(seperator + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;size&lt;/span&gt;()).&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;() &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; 
						&amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(seperator + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;size&lt;/span&gt;())) &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;)
						end = &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(seperator + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;size&lt;/span&gt;()));
					&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
						end = &lt;span class=&quot;hljs-number&quot;&gt;1001&lt;/span&gt;;
					&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (start &amp;lt;= end)
					{
						&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = start; i &amp;lt;= end; i++)
						{
							&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i &amp;lt;= total_page)
								print_info[i] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
						}
					}
				}
			}

			result = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
			&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= total_page; i++)
			{
				&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (print_info[i])
					result++;
			}
			result_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;push_back&lt;/span&gt;(result);
		}
	}

	&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) result_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;size&lt;/span&gt;(); i++)
		cout &amp;lt;&amp;lt; result_vector[i] &amp;lt;&amp;lt; endl;

	&lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>零散的Shell记录 (3)</title><link>https://www.traceoflight.dev/zh/blog/shell-3/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/shell-3/</guid><description>学习Shell的旅程，第三篇</description><pubDate>Tue, 25 Jul 2023 18:05:52 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;23-07-26 修正错误内容&lt;/p&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;23-07-27 添加命令&lt;/p&gt;
&lt;h3&gt;BC&lt;/h3&gt;
&lt;p&gt;Basic Calculator的缩写，是根据POSIX标准提供的、可在Unix系统上使用的计算器。&lt;/p&gt;
&lt;p&gt;其特点包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;采用栈式结构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持逆波兰表示法 (Reverse Polish notation)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;2 + 3&amp;#x27;&lt;/span&gt; | dc
dc &amp;lt;&amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;2 3 + p&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;TR&lt;/h3&gt;
&lt;p&gt;用于字符转换、删除、压缩等的命令。通常通过管道与其他处理步骤结合使用&lt;/p&gt;
&lt;p&gt;*&lt;code&gt;tr [문자열1] [문자열2]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;：使用两个长度相同的字符串，通常将字符串1中对应位置的字符替换为字符串2中相同索引位置的字符。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;：使用两个长度相同的字符串，通常将字符串1中对应位置的字符替换为字符串2中相同索引位置的字符。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-c：用第二个字符串的最后一个字符替换所有不在该字符串中的字符&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-s：移除所有重复出现的序列，并替换为指定的字符&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-d：删除指定字符&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-t：在执行命令前，将两个字符串截断至相同长度&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SED（&lt;/h3&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;，流式编辑器）&lt;/p&gt;
&lt;p&gt;支持多种编辑功能的命令，基本基于缓冲区运行，因此在修改前不会影响原始文件。&lt;/p&gt;
&lt;h4&gt;命令选项&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;以 /[模式]/ 的形式表示模式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加 g 时，对所有匹配的模式进行操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过逗号 (,) 调整范围。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;p：输出所有行，若匹配模式则额外输出一次&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;添加 -n 选项：排除默认输出，仅输出匹配模式的行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;d：删除匹配的模式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;s：替换匹配的模式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;e：多行编辑&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;code&gt;n;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;：下一行&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;y：转换&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;i：插入&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;c：更改&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a: 追加&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 약간의 응용&lt;/span&gt;

sed -n &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;n; p&amp;#x27;&lt;/span&gt;: 짝수 줄 출력
sed -n &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;p; n&amp;#x27;&lt;/span&gt;: 홀수 줄 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;WC&lt;/h3&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;词数统计&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;-l: 查看文件的行数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-c: 查看文件的字节数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-m: 查看文件中的字符数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-w: 查看文件中的单词数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>贝壳历史杂项 (2)</title><link>https://www.traceoflight.dev/zh/blog/shell-2/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/shell-2/</guid><description>学习贝壳的旅程，第二部分</description><pubDate>Thu, 20 Jul 2023 16:49:40 GMT</pubDate><content:encoded>&lt;h3&gt;列表&lt;/h3&gt;
&lt;p&gt;通常与 &lt;code&gt;ls&lt;/code&gt; 一起使用的命令。 您可以使用这些命令查看目录的内容。附加命令非常有用，因为它们允许您出于适当目的调出列表。&lt;/p&gt;
&lt;p&gt;我们将留下最常用的命令和用于特定目的的命令，如果您需要更多命令，可以使用 &lt;code&gt;man&lt;/code&gt; 获取手册或参考下面链接的文档。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-l&lt;/strong&gt;: 长默认格式。
&lt;code&gt;working john 2008-07-25 11:56 csrc 1 alias.c-4.5 27&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-al&lt;/strong&gt;: 显示全文。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-t&lt;/strong&gt;: 按修改时间排序。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-m&lt;/strong&gt;：输出用逗号和空格（, ）分隔的每个元素
&lt;code&gt;this, is, example&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-r&lt;/strong&gt;：以与当前顺序相反的方式输出&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-R&lt;/strong&gt;：递归打印子目录的内容&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-h&lt;/strong&gt;：单位的人可读输出（使用 m、k、g 等单位）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man1/ls.1.html&quot;&gt;列表手册&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;查找&lt;/h3&gt;
&lt;p&gt;该命令用于搜索文件，搜索指定位置的所有子目录并打印结果。它提供的功能远不止输出这么简单，如果你真的想充分利用它，就应该学习一下正则表达式。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-name&lt;/strong&gt;: 这是一条添加搜索名称信息的命令，可以使用正则表达式对搜索名称进行限制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-o&lt;/strong&gt;：该命令的作用类似于 or 运算符，因此如果你想在条件 A 的情况下执行操作 a，在条件 B 的情况下执行操作 b，请使用该命令。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-exec&lt;/strong&gt;：允许应用附加命令的命令。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-delete&lt;/strong&gt;：删除找到的文件。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-print&lt;/strong&gt;: 打印找到的文件的命令&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;同样，你也可以在这里搜索其他命令。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man1/find.1.html&quot;&gt;查找手册&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Echo &amp;amp; Printf&lt;/h3&gt;
&lt;p&gt;我在 shell 中经常使用 echo，但除了 echo 之外，你还可以使用 printf。老实说，除了换行符的默认值，我对它们了解不多，所以我向 ChatGPT 求助！&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-2f0cb8656eb567ac-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;令人惊讶的是，printf 比我经常使用的 echo 更复杂一些。我不认为我在少量使用时会注意到有什么不同，所以我暂时就使用这些信息了......&lt;/p&gt;
</content:encoded></item><item><title>贝壳历史杂项 (1)</title><link>https://www.traceoflight.dev/zh/blog/shell-1/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/shell-1/</guid><description>学习壳牌的旅程</description><pubDate>Mon, 17 Jul 2023 17:25:08 GMT</pubDate><content:encoded>&lt;h3&gt;文件创建相关&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;touch&lt;/code&gt;：创建文件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;mkdir&lt;/code&gt;：创建文件夹&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;chmod&lt;/code&gt;：设置文件权限&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;chown&lt;/code&gt;：设置文件所有者&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;mv&lt;/code&gt;：移动和重命名文件&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;检查文件信息&lt;/h4&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-f343d0b04676158d-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-rwxr-xr-x&lt;/code&gt;部分：检查文件权限&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一个数字表示文件类型（-、d、l）； 2.
2. 读写执行权限以三位数的形式表示用户、组和其他、
&lt;code&gt;rwx&lt;/code&gt; 的值可以改为 7，&lt;code&gt;-xr&lt;/code&gt; 的值可以改为 4，因为在二进制数形式中，r 是 4，w 是 2，x 是 1。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; 744 Slack.lnk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这类命令可用于设置权限。
3.链接数（其中写入 1）
4.关于所有者（空）和所有者组（197609）的信息
5.文件大小
6.最后修改时间信息
7.文件名&lt;/p&gt;
&lt;h3&gt;ssh-keygen&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在许多情况下用于通过安全壳公钥进行 Git 验证&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;包含在 Window 和 Linux 软件包中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;生成密钥时，会生成一个密钥和 &lt;code&gt;.pub&lt;/code&gt; 文件，通过向服务器提供 .pub 文件的内容将其用作密钥锁&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;如何在 shell 中调整文件的容量&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfile -n 10k test.sh
fallocate -l 10k test.sh
&lt;span class=&quot;hljs-built_in&quot;&gt;truncate&lt;/span&gt; -s 10k test.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用该命令可以调整现有文件的大小或创建新文件。&lt;/p&gt;
&lt;h3&gt;更改文件修改历史记录&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;touch&lt;/span&gt; -t 2301011234 timefile.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以下命令可更改文件的修改历史，使其显示最后修改时间为 1 月 23 日 12:34，作为触摸应用。&lt;/p&gt;
&lt;h3&gt;硬链接和符号链接&lt;/h3&gt;
&lt;h4&gt;符号链接（软链接）&lt;/h4&gt;
&lt;p&gt;使原始文件在特定文件夹中可用的链接，如 Windows 中的快捷方式，如果原始文件被删除，链接将失效。&lt;/p&gt;
&lt;h4&gt;硬链接&lt;/h4&gt;
&lt;p&gt;与符号链接不同，区别在于它复制了原始文件并创建了一个副本；当原始文件被删除时，符号链接将无法使用，但硬链接仍可使用，因为它毕竟是同一个文件；链接涉及的链接数。&lt;/p&gt;
&lt;h4&gt;代码&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ln&lt;/span&gt; [대상 폴더] [만들 링크 파일명] &lt;span class=&quot;hljs-comment&quot;&gt;# Hard Link&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;ln&lt;/span&gt; -s [대상 폴더] [만들 링크 파일명] &lt;span class=&quot;hljs-comment&quot;&gt;# Symbolic Link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;rm&lt;/code&gt; 可以解除擦除命令，就像擦除文件一样&lt;/p&gt;
&lt;h3&gt;Diff &amp;amp; Patch&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;diff a b &amp;gt; difference.patch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;diff&lt;/code&gt; 命令逐行比较两个文件，而 &lt;code&gt;patch&lt;/code&gt; 命令允许你根据 diff 的比较结果修改文件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;patch -p{패치 경로의 depth} [원본] [patch 파일] &lt;span class=&quot;hljs-comment&quot;&gt;# 패치 파일 적용&lt;/span&gt;
patch -p{패치 경로의 depth} -R [원본] [patch 파일] &lt;span class=&quot;hljs-comment&quot;&gt;# 적용된 패치 파일을 되돌림&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;与上述形式相同，你可以从现有文件中应用或删除由 diff 确定的内容。&lt;/p&gt;
</content:encoded></item><item><title>2023 年韩亚 IDT 暑期招聘回顾</title><link>https://www.traceoflight.dev/zh/blog/2023-idt/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/2023-idt/</guid><description>我如何加入韩亚 IDT 的招聘流程</description><pubDate>Sat, 15 Jul 2023 09:23:14 GMT</pubDate><content:encoded>&lt;h4&gt;在&lt;/h4&gt;
&lt;p&gt;由于经济原因，招聘轮次和招聘人数都比去年少了很多。 最后，谁能在时机成熟时得到工作，谁就是赢家，所以我认为我需要更加坚持不懈。&lt;/p&gt;
&lt;p&gt;###文件筛选和能力测试&lt;/p&gt;
&lt;p&gt;与其他公司一样，文件方面没有什么特别之处，但与财务招聘类似的能力测试却不同寻常。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-de67b160b1aa0129-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我以为我的回答都很正常，但我很担心，因为出现了（注意），但摄像头和麦克风都没有问题，所以我就照原样提交了、&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-bfb139a0580b844d-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我顺利通过了考试。如果时间充裕，我会再检查一次能力测试。&lt;/p&gt;
&lt;h3&gt;编码测试&lt;/h3&gt;
&lt;p&gt;难度和题型让我想起了金融专业的编码测试。总的来说，难度一般，与 SQL 类似。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-04f741f5ffa434c7-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我通过了考试，并获得了在韩亚 IDT 面试的机会！&lt;/p&gt;
&lt;h3&gt;最终面试&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-3d3262bf0a5592a0-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我在大楼入口处领取了面试官的访客通行证，然后去参加面试。 面试内容与我在准备过程中读到的其他评论类似，都是讨论和性格面试。&lt;/p&gt;
&lt;p&gt;我没想到自己会在讨论面试中扮演重要角色，但我认为这是一个筛选出有沟通问题的人的过程。&lt;/p&gt;
&lt;p&gt;在性格面试中，我被问到的问题是基于文件、编码测试结果等的综合。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;我认为应聘这样一份工作的人并不多，但我认为对公司研究不够的人可能会在问题上遇到困难。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过询问面试者的意见，我感觉公司在思考公司的发展方向。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;最终结果。&lt;/h4&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-1e2142ef3cf56fc9-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我认为我在面试中的回答比平时要好，尽管竞争激烈，我还是成功获得了这份工作！&lt;/p&gt;
&lt;p&gt;###感想&lt;/p&gt;
&lt;p&gt;在进入 IT 行业时，很多人都会因为听到的各种故事而对 SI/SM 产生一种模糊的恐惧感，而我正是如此。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-94c515233c0d9259-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;
~~超级现实主义&lt;/p&gt;
&lt;p&gt;但我认为，国内IT行业的大部分人都在关注SI/SM，而不是IT服务，如果忽略了这一点，就可能做出非理性的选择。&lt;/p&gt;
&lt;p&gt;由于现在的就业市场已经今非昔比，所以现在应该有一种意识，考虑现在最好的选择是什么，而不是去追求过于狭隘的目标，只要牢记这一点，就一定会取得好的结果！&lt;/p&gt;
</content:encoded></item><item><title>[面试问题] 什么是面向对象编程？</title><link>https://www.traceoflight.dev/zh/blog/object-oriented-programming/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/object-oriented-programming/</guid><description>整理有关面向对象编程的面试问题</description><pubDate>Wed, 12 Jul 2023 07:28:03 GMT</pubDate><content:encoded>&lt;h4&gt;在&lt;/h4&gt;
&lt;p&gt;昨天，我去一家大公司面试，遇到了一个情况，我必须回答一个关于面向对象编程的问题，我以为我很清楚，但当我试图回答时，却磕磕绊绊。&lt;/p&gt;
&lt;p&gt;多亏了这件事，我想我已经找到了自己的弱点，决定花时间重新整理一下！&lt;/p&gt;
&lt;p&gt;什么是 ### 对象？&lt;/p&gt;
&lt;p&gt;让我们从一般定义开始&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一般理论：实际存在的东西
计算机科学：根据类的定义在内存中创建的东西。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;面向对象的语言定义如下&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Java：类的实例或数组
Python：具有属性值或行为的数据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Java 中的类不是实例，但 Python 中的类是实例。&lt;/p&gt;
&lt;h4&gt;面向对象编程&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;通过定义对象的角色和关系来构建交互式程序。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们可以这样定义&lt;/p&gt;
&lt;h4&gt;面向对象语言的特点&lt;/h4&gt;
&lt;h4&gt;抽象&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可以在对象之间推导出共同特征&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;定义类的部分是&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;多态性&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可以对行为略有不同的函数进行相同的调用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为同一命令向链接对象传递解释&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;覆盖（覆盖内部源）、重载（根据参数调用另一个同名函数）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;封装&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;允许你隐藏部分实现而不向外界暴露&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果需要与外界通信，则通过方法发送和接收信息&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从 #### 继承&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;从一个类继承另一个类的功能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;除已创建的类外，还允许创建新类&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[BOJ 11689, Python] GCD(n, k) = 1</title><link>https://www.traceoflight.dev/zh/blog/boj11689/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj11689/</guid><description>BOJ 11689，&quot;GCD(n, k) = 1 &quot;问题的 Python 解法</description><pubDate>Fri, 07 Jul 2023 06:49:25 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp8@@&quot;&gt;boj 11689&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;数学, 数论, 欧拉函数&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;最近，我一直在练习解决不分类的 Backzun 问题，以提高我的实际能力。然而，当我遇到像这样的问题时，就变得相当头疼。&lt;/p&gt;
&lt;p&gt;就这个问题而言，我起初认为至少应该尝试将其求解到 O(N) 以下，因为我需要在 1 秒钟内检查 10&lt;sup&gt;12&lt;/sup&gt; 以下的数字。我使用了下面的代码，因为我认为如果是质因数分解，而且没有重叠的数字，就不会有问题。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;factorize&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_number: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;:

    result = []
    prime_list = find_prime(target_number)

    now_number = target_number
    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; now_number &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_prime &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; prime_list:
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; each_prime &amp;gt; now_number:
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; now_number % each_prime:
                &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; now_number % each_prime:
                    now_number //= each_prime
                result.append(each_prime)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然而，根据这段代码计算出的时间复杂度并不令人满意，于是我决定检查一下标签，结果发现了一个新朋友 &lt;code&gt;오일러 피 함수&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;原来，问题本身是一个使用&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;φ(n) = {n 是小于或等于 n 的自然数的个数}。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我是这样实现的&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;euler_phi&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;number: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    오일러 피 함수를 활용한 자연수 n과 서로소인 수의 갯수를 구하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    checker = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;
    result = number

    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(checker, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) &amp;lt;= number:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; number % checker:
            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; number % checker:
                number //= checker

            result -= result // checker

        checker += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; number &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        result -= result // number

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;从 2 开始，一直除下去。&lt;/li&gt;
&lt;li&gt;如果这个数能被整除，就尽可能多地整除它。(质因数分解）&lt;/li&gt;
&lt;li&gt;从得到的数中减去，因为这个数的倍数不能是质数。&lt;/li&gt;
&lt;li&gt;如果最后还剩下一个数，就从结果数中减去它，因为它是一个质数，而这个质数的倍数不能是质数。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这就是有点棘手的地方。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;结果 -= 结果 // 校验&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我曾想过为什么我们要从结果中移除除数，而不是移除 &lt;code&gt;number // checker&lt;/code&gt;，但这是有道理的。如果我们去掉 &lt;code&gt;n&lt;/code&gt; 的倍数，然后再去掉相同数目的 &lt;code&gt;m&lt;/code&gt; 的倍数，最后就会得到两个 &lt;code&gt;n * m&lt;/code&gt; 的倍数！&lt;/p&gt;
&lt;p&gt;为了处理这些重复的数字，我们要从已经删除过一次的数字中减去该数字的倍数。&lt;/p&gt;
&lt;p&gt;总之，一旦你明白了解决方法，这个问题就变得非常简单了。数论问题似乎都是这样，这对学习很有帮助，但有点令人沮丧，因为第一种方法总是很难&lt;/p&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# GCD(n, k) = 1&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;euler_phi&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_number: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;):
    result = target_number
    check_number = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(check_number, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) &amp;lt;= target_number:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; target_number % check_number:
            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; target_number % check_number:
                target_number //= check_number
            result -= result // check_number
        check_number += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; target_number &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        result -= result // target_number

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result

target = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(euler_phi(target))
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[面试问题] 依赖注入</title><link>https://www.traceoflight.dev/zh/blog/dependency-injection/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/dependency-injection/</guid><description>汇编有关 DI 的面试问题</description><pubDate>Thu, 06 Jul 2023 11:46:58 GMT</pubDate><content:encoded>&lt;h3&gt;依赖注入&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;依赖关系：一个对象使用另一个对象的关系。
→ 依赖注入：建立关系的东西&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;为什么需要依赖注入？&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Product&lt;/span&gt; {

	&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Apple apple;
    
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; {
    	&lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.apple = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Apple&lt;/span&gt;();
	}

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在本示例中，如果一个名为 Product 的类使用了 Apple 构造函数，那么我们就是在使用它，而没有注入它。
当使用 Product 时，可以将其理解为 Apple 附带的依赖关系。在这种情况下，它不是对象之间的连接，而是类之间的关系。&lt;/p&gt;
&lt;p&gt;另外，如果我想使用一个名为 &lt;code&gt;Orange&lt;/code&gt; 的额外类，我就必须修改 Product 类的构造函数，而这是不灵活的。&lt;/p&gt;
&lt;p&gt;最后，总结一下依赖注入的必要性&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;类之间的强耦合 + 代码不灵活&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们可以说，依赖注入解决了这些问题，所以它是必要的！&lt;/p&gt;
&lt;h3&gt;解决方案的应用&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Fruit&lt;/span&gt; {

}

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Apple&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Fruit&lt;/span&gt; {

}

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Product&lt;/span&gt; {

	&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Fruit fruit;
    
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Fruit fruit)&lt;/span&gt; {
    	&lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.fruit = fruit;
    }
    
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看出，每个类都保证是独立的。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;添加一个新的 &amp;quot;水果 &amp;quot;不会改变 &amp;quot;产品&amp;quot;； 2.&lt;/li&gt;
&lt;li&gt;对象之间形成关系，而不是类之间的关系&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>[面试问题] Java 堆栈和堆的结构</title><link>https://www.traceoflight.dev/zh/blog/java-stack-heap/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/java-stack-heap/</guid><description>关于 Java 堆栈和堆的面试问题简述</description><pubDate>Sun, 02 Jul 2023 17:19:40 GMT</pubDate><content:encoded>&lt;h4&gt;Java 内存结构&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;/blog/jvm&quot;&gt;参见 JVM 结构和原理&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们为运行应用程序而构建的 Java 运行时数据区位于内存中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;所有线程共享 PC 寄存器、本地方法堆栈和方法区。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;只有堆栈和堆区域是线程专用的&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;堆的结构&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;伊甸园 → 幸存者 → 旧的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对象按上述格式移动，这基本上是创建的顺序。&lt;/p&gt;
&lt;h3&gt;垃圾回收器的作用&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;伊甸园（Eden）：Java 对象创建后立即存放的地方。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Survivor &amp;amp; Old：根据引用程度移动对象的空间&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;标记和扫描&lt;/strong&gt;：使用标记和扫描算法。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;小型垃圾收集器&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;负责根据对象引用移动 Eden 和 Survivor 区域（年轻一代），如果它们的内存超过允许的数量。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;主要垃圾收集器&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;当旧区域（长期一代）的内存超过允许上限时，它将删除所有未引用的对象并回收内存。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;在删除过程中，停止除运行垃圾回收器的线程以外的所有线程（&amp;quot;Stop-The-World&amp;quot;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;堆栈结构&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;基本类型 + 局部变量 + 参数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在参数的情况下，它用作对堆区对象的引用，并带有对象的地址值。&lt;/p&gt;
&lt;p&gt;→ 如果参数指向不同的对象，地址值也会不同，存储在堆中的对象也不会立即消失！（保持到主要 GC 执行为止）&lt;/p&gt;
&lt;h3&gt;另请参见。&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://coding-factory.tistory.com/828&quot;&gt;编码工厂的文章&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[日本央行 27231，蟒蛇] 我为何期待 2023 年</title><link>https://www.traceoflight.dev/zh/blog/boj27231/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj27231/</guid><description>解决《日本经济新闻》第 27231 期 &quot;为什么我期待 2023 年 &quot;问题的 Python 解决方案</description><pubDate>Fri, 30 Jun 2023 10:32:49 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp4@@&quot;&gt;boj 27231&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;暴力算法, 逆向追踪&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-11d42ef72dcdad8a-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;很高兴看到我能够解决以前无法解决的问题，所以我觉得我进步了。&lt;/p&gt;
&lt;p&gt;就拿这道题来说，最后一次尝试是在五个月前提交给比赛的，但在此期间我已经把解题思路写了好几遍。&lt;/p&gt;
&lt;p&gt;之所以会有多次尝试，是因为只缺少一个条件，但我还是不清楚为什么缺少这个条件会超时。整理博客是最棒的！&lt;/p&gt;
&lt;p&gt;让我来介绍一下解决问题的方法&lt;/p&gt;
&lt;p&gt;对 *+ 符号之间的坐标进行位屏蔽，检查是否为整数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在不允许重复的列表中设置或排序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;计数直到最初输入的数字（因为无论如何切分，都不会大于该数字），方格尺寸不断增大&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里我们遇到了一个问题。&lt;/p&gt;
&lt;p&gt;对于一个由 0 和 1 组成的数字，我们应该输出 &lt;code&gt;Hello, BOJ 2023!&lt;/code&gt;，因为如果我们把它分割成一个数字，那么无论平方多少次，数值都不会改变，但我只是排除了 1 的情况。&lt;/p&gt;
&lt;p&gt;为了检查这一部分，我通过检查是否有大于 2 的单个数字来处理边缘情况，如果没有大于 2 的项，则打印 &lt;code&gt;Hello, BOJ 2023!&lt;/code&gt;，这就是正确答案。&lt;/p&gt;
&lt;h4&gt;求解代码&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 2023년이 기대되는 이유&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;pow_target&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_num: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, exponent: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:

    result = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    now_number = target_num

    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; now_number:
        result += &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;((now_number % &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;), exponent)
        now_number //= &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result

testcase = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
result_dict = &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt;()
output = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(testcase):

    target_number = &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().rstrip(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\n&amp;#x27;&lt;/span&gt;)

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; result_dict.get(target_number) &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
        output.append(result_dict[target_number])

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        is_under_limit = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_element &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(target_number):
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(each_element) &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
                is_under_limit = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; is_under_limit:
            result_dict[target_number] = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Hello, BOJ 2023!&amp;#x27;&lt;/span&gt;
            output.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Hello, BOJ 2023!&amp;#x27;&lt;/span&gt;)
            &lt;span class=&quot;hljs-keyword&quot;&gt;continue&lt;/span&gt;

        length = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(target_number)

        check_list = []
        check_list.append(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(target_number))

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &amp;lt;&amp;lt; length):

            calc_result = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

            now_start = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
            now_end = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; j &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(length):

                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; i &amp;amp; (&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &amp;lt;&amp;lt; j):
                    now_end = j
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_end:
                        calc_result += &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(target_number[now_start : now_end])
                    now_start = now_end
                    
            calc_result += &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(target_number[now_start : length + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; calc_result &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; check_list:
                check_list.append(calc_result)

        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
            result = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

            check_amount = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(check_list)
            check_list.sort()

            max_value = check_list[-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]
            pointer = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
            counter = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; pointer &amp;lt; check_amount:
                now_result = pow_target(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(target_number), counter)

                &lt;span class=&quot;hljs-comment&quot;&gt;# 종료 조건 1&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_result &amp;gt; max_value:
                    &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

                &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; pointer &amp;lt; check_amount &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; now_result &amp;gt; check_list[pointer]:
                    pointer += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

                &lt;span class=&quot;hljs-comment&quot;&gt;# 종료 조건 2&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; pointer &amp;gt;= check_amount:
                    &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_result == check_list[pointer]:
                    result += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

                counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

            result_dict[target_number] = result
            output.append(result)

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; output:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 13325, Python] 二进制树</title><link>https://www.traceoflight.dev/zh/blog/boj13325/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj13325/</guid><description>BOJ 13325 &quot;二叉树 &quot;问题的 Python 解决方案</description><pubDate>Wed, 28 Jun 2023 12:58:52 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp4@@&quot;&gt;boj 13325&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;动态程序设计, 树, 树中的动态程序设计&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;如果你和我一样，是那种即使不能马上解决问题，也会长期坚持的人！&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-4b0aee5765d752b7-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;于是，那些我尝试了却无法解决的问题，那些我努力了却无法解决的问题，就这样和竞赛题一起堆积起来......&lt;/p&gt;
&lt;p&gt;为了摆脱它们，我有时会通读试题，细细咀嚼，真庆幸今天终于在这篇文章中找到了解决办法！&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-5ef200830a30afc7-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;距离我第一次尝试已经过去 8 个月了，上次尝试后我又修补了几次，但似乎都没有效果。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;pre_order_detail&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;graph_dict: &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt;, target_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;:

    result = [target_node]

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(graph_dict[target_node]) &amp;gt;= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_element &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; pre_order_detail(graph_dict, graph_dict[target_node][&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]):
            result.append(each_element)
        result.append(target_node)

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(graph_dict[target_node]) &amp;gt;= &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_element &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; pre_order_detail(graph_dict, graph_dict[target_node][&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]):
            result.append(each_element)
        result.append(target_node)

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我最初的想法是使用类似上述递归函数形式的潜在遍历的变体，拍摄访问节点的图片，将其放入类似堆栈的数据结构中，然后遍历每个主干。&lt;/p&gt;
&lt;p&gt;不过，经过思考，我意识到如果将比较对象限定为来自同一父节点的树干，那么只需将两个值中较大的一个加到父树干上，这样会更简洁！&lt;/p&gt;
&lt;p&gt;后来，我解决了这类问题，并将其归类为树形 DP。我认为它与 DP 非常相似。&lt;/p&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 이진 트리&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

tree_height = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
node_number = &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, tree_height + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

edges = [&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))
edge_sum = &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;(edges)

now_start = node_number // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
now_end = node_number - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; now_end:

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;((now_end - now_start) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;):

        child_edge = now_start + (&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * i)
        next_node = child_edge // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        edges[next_node] += &lt;span class=&quot;hljs-built_in&quot;&gt;max&lt;/span&gt;(edges[child_edge], edges[child_edge + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])
        edge_sum += &lt;span class=&quot;hljs-built_in&quot;&gt;abs&lt;/span&gt;(edges[child_edge] - edges[child_edge + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])

    now_end = now_start
    now_start = now_start // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(edge_sum)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代码长度和时间复杂度比我们最初想象的要简单。现在我们把代码编排成这样，肯定是自下而上的。&lt;/p&gt;
</content:encoded></item><item><title>[存档]什么是 IaaS、PaaS 和 SaaS？</title><link>https://www.traceoflight.dev/zh/blog/iaas-paas-saas/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/iaas-paas-saas/</guid><description>您经常听到但尚未深入探讨的词语</description><pubDate>Mon, 26 Jun 2023 05:21:36 GMT</pubDate><content:encoded>&lt;h3&gt;普通话中的 &amp;quot;aaS &amp;quot;是什么意思？&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;服务 &amp;quot;的缩写&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由第三方提供的云计算服务！&lt;/p&gt;
&lt;h4&gt;有什么区别？&lt;/h4&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;以服务形式提供不同的基础设施、平台和软件。
→ 不同的管理级别&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-7a2b2e1c34c6a3d0-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;1. IaaS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;从内部基础设施演变而来&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;向云提供基础设施服务&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供商负责管理和访问网络、服务器、虚拟化和存储&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;例如 AWS、Azure、GCP 等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. PaaS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;责任范围比 IaaS 更广&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;允许用户开发、运行和管理自己的应用程序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供构建和部署环境&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. SaaS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;所有应用程序均由提供商管理&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供商管理所有软件维护、升级和安全工作&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;注意&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.redhat.com/ko/topics/cloud-computing/iaas-vs-paas-vs-saas&quot;&gt;IaaS vs. PaaS vs. SaaS&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[面试问题]什么是连接池？</title><link>https://www.traceoflight.dev/zh/blog/connection-pool/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/connection-pool/</guid><description>回顾有关 DB 连接池的面试问题</description><pubDate>Sun, 25 Jun 2023 17:05:44 GMT</pubDate><content:encoded>&lt;h3&gt;什么是 DB 连接池？&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;在池中存储已连接到数据库的对象。
客户请求时借用连接
处理后，返回连接并将其保存回池中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我想你可以理解为，这就像一个事先连接好的连接对象，需要时再取出来。&lt;/p&gt;
&lt;h4&gt;为什么要使用它？&lt;/h4&gt;
&lt;p&gt;对于 Java Spring 来说、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果你使用直接连接到数据库的方式进行处理，你可以使用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每次都需要加载 JDBC 驱动程序并获取连接对象&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每次请求都要重复加载驱动程序、创建对象和连接&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;→ 这样做效率很低，因此我们使用连接池来解决这些问题。&lt;/p&gt;
&lt;p&gt;+ 其他框架也使用它。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-bec4f7ed8c564abe-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;功能&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;WAS 运行时在连接对象池中预先创建&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;根据 HTTP 请求获取、写入和返回对象&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每个连接请求不消耗连接和创建时间
→ 减少连接负载&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;当并发连接数多于池中对象数时？
→ 如果没有足够的预创建连接对象，则按顺序等待，直至返回&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;较大的池会消耗更多内存并减少延迟。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[碎片] 关于主要功能的位置</title><link>https://www.traceoflight.dev/zh/blog/main/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/main/</guid><description>让我们把主函数移到顶部</description><pubDate>Sun, 18 Jun 2023 11:50:50 GMT</pubDate><content:encoded>&lt;h4&gt;在&lt;/h4&gt;
&lt;p&gt;我决定将 &lt;code&gt;자투리&lt;/code&gt; 类别用于简短的经验教训！&lt;/p&gt;
&lt;h3&gt;将主要功能的位置移到顶部&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/live/ywg7cW0Txs4?feature=share&quot;&gt;CS50&lt;/a&gt;我在听讲座，这就是我组织代码的方式。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;example&lt;/span&gt;():
	&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hello&amp;#x27;&lt;/span&gt;)
    
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;():
	example()
    
main()

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如，我会先列出我需要的所有函数的详细定义，然后再列出主函数。&lt;/p&gt;
&lt;p&gt;不过，我觉得主函数应该放在开头，这样别人在阅读代码时会更清楚。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;():
	example()
    this_function()

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;example&lt;/span&gt;():
	&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hello&amp;#x27;&lt;/span&gt;)
    
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;this_function&lt;/span&gt;():
	&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;function&amp;#x27;&lt;/span&gt;)
    
main()

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们应该把显示代码整体实现的主函数移到页面顶部，把详细定义放在它后面，这样代码的作用就更清楚了。&lt;/p&gt;
</content:encoded></item><item><title>SSAFY 第 8 年回顾，无特别之处</title><link>https://www.traceoflight.dev/zh/blog/ssafy-8/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/ssafy-8/</guid><description>三星青年 SW 学院总结</description><pubDate>Fri, 16 Jun 2023 17:28:37 GMT</pubDate><content:encoded>&lt;h4&gt;在&lt;/h4&gt;
&lt;p&gt;历时一年的第八期三星青年 SW 学院（SSAFY）终于结束了。 虽然付出了很多，但这是一段令人惊叹的旅程，所以我想现在就写下来。如果你看一下 SSAFY 的评论，就会发现他们中的大多数人都以优秀或更高的成绩完成了课程，甚至还获得了一两张证书......&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-aee8ee7c7a4b8132-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我想，大家可以把这篇评论看作是某位SSAFY学员的故事，而不是某位获得了很多奖项的SSAFY式的优秀人物的故事。 我也希望这篇评论能对今后参加SSAFY课程的学员有所帮助。&lt;/p&gt;
&lt;h3&gt;입과&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-442ceb7c6829c573-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-219d272c02689759-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我莫名其妙地闯过了 SSAFY 这一关，众所周知，SSAFY 对于非专业学生来说是很高的。我通过了自我介绍，但没有通过面试......不过，我还是收到了非专业录取通知，进入了首尔校区。因为我是最后才被录取的，所以可以不用参加开学训练营，但听说只有参加过开学训练营的人才知道。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-fa0b9011434db360-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;当你被SSAFY录取时，你会得到一个名牌，但就连名牌上也把我的名字贴在了其他先期录取者的名字上面......事后我不得不用胶带把它粘起来，因为它老是掉下来。&lt;/p&gt;
&lt;p&gt;现在回想起来，我觉得名牌实际上让我更加努力地工作。我认为它让我充满动力，并不断提醒我，我所获得的机会是无价的！&lt;/p&gt;
&lt;p&gt;###第 1 学期，Python 方向&lt;/p&gt;
&lt;p&gt;虽然我知道自己想学 Java，但我还是选择了 Python 方向。我在第一学期学到了很多东西...&lt;/p&gt;
&lt;p&gt;在第二学期，我认为我真正学到并用得好的东西只有算法、Git 和 Python。即便如此，Python 和 Algorithm 在编码测试中的使用率远远高于在项目中的使用率...&lt;/p&gt;
&lt;p&gt;(我在学习前端，但我主要是在重新学习 React，所以它并不存在）&lt;/p&gt;
&lt;p&gt;尽管如此，如果你加入这个赛道，就会发现几乎每个人都对学习充满热情，就像 SSAFY 一样。我觉得我在班上花了很多时间，一起做研究，一起在咖啡馆学习。&lt;/p&gt;
&lt;p&gt;对于我来说，编程几乎是零基础，因为我所知道的编程知识都是在大学里学的，我觉得自己不可能样样精通，所以我觉得需要有所选择，有所侧重，所以我觉得应该先看看招募流程，一步步尝试突破。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;文档筛选 → 编码测试 → 性格面试 → 技术面试 → 录用&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我发现大多数公司都在这个范围内。因此，我想，&lt;strong&gt;“如果你不能通过编码测试，那你就没有前途。”&lt;/strong&gt; 这就是算法技术树的开端。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-cfc4f764b173e0d0-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;为了提高算法技能，我投入了大量时间学习，但最终，在取得白金 5 后，我几乎耗尽了自己的精力。从那时起，为了通过三星软件能力评估 B 类，我还在中间学习了 Java 语言，但遗憾的是，我最终没有通过。复习资料在&lt;a href=&quot;/blog/b&quot;&gt;这里&lt;/a&gt;，如果你拿到了B类，你将优先获得SSAFY提供的各种福利、经验和人脉，所以如果你能拿到，就去做吧！&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-b2e44c75355b7edc-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;(不过，我认为即使是低级问题也要坚持解决，这样才不会失去方向感）&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-8836547a6ac0689c-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;在几乎每周都艰难地通过理论和实践测试后，我进入了最终项目。这是一个为期 7 周的项目，事后看来，它要求我们用&lt;strong&gt;压倒性地更少的人和更少的时间&lt;/strong&gt;完成第二学期的挑战！我确信我在某个地方看到过一些很酷的代码，但最终，奖项归属于完成了其他人无法完成的任务（例如部署）的团队。&lt;/p&gt;
&lt;h4&gt;第二学期，项目一个接一个。&lt;/h4&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-00a981c35d4a739d-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;在第二学期，你一直在做项目，我认为这是 SSAFY 最重要的部分。&lt;/p&gt;
&lt;p&gt;在第一学期，即使你想应聘一家公司，如果对方问你 &amp;quot;你做过什么？&amp;quot;，你也没有什么可以回答的，所以你在自我介绍或面试时可以诉说的部分很有限，但随着第二学期的逐步推进，无论结果如何，只要你忠实地参与了项目，你就可以说 &amp;quot;我做了这样那样的事情，我在这样那样的事情上遇到了困难，但我在这样那样的事情上得到了改进 &amp;quot;这样的话！&lt;/p&gt;
&lt;p&gt;项目的主题似乎是一成不变的，但如果不是专门的项目，我就可以按照团队的要求开展工作，而不会被某个主题所束缚。就我而言，我参与了两个应用程序开发项目和一个具有移动规格的网络开发项目。至于岗位，不同的人在第二学期可能有不同的想做的事情，但我想在所有岗位上都获得经验，所以我选择了一个后台、一个前台和一个应用程序的经验。&lt;/p&gt;
&lt;p&gt;如果你是 Python 方向的学生，你大部分时间都在用 Java 构建一堵墙，而由于第二学期 99% 的项目都使用 Spring Boot，你不可避免地会在前端工作，这也是你获得职位固定的地方。 因此，如果你是 Python 方向的学生，如果你知道自己想在后端工作，最好单独选修 Java。就我而言，我单独选修了 Java 课程，以便为后端职位留出选择余地，结果，我获得了一个后端职位。&lt;/p&gt;
&lt;p&gt;###求职和各种面试&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-3bc909615076161a-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;当我幻想着从第一学期到第二学期都能有所表现时，一小群有准备的人却荣幸地一直尝试着与公司取得联系，结果，在这中间得到了SSAFY的逃脱。看到他们时，我的第一个想法是：&apos;我还没准备好...&apos;但结果是，在两个学期后，你自然而然地开始通过观察各种逃脱的领导者来做准备。&lt;/p&gt;
&lt;p&gt;看到自己接受并完成了第二学期的证书，而别人却拿到了员工证书，你可能会很失望，所以你应该继续努力。我申请了很多地方，最后还是接受了第二学期的证书，但我觉得我很庆幸自己这么做了。&lt;/p&gt;
&lt;p&gt;一旦你通过了编码测试和文件筛选，了解了 SSAFY 的各种好处和你所掌握的技能，还有面试。你往往要通过性格面试和技术面试才能知道自己的不足之处，所以我觉得如果能在培训期间体验一下就非常好了。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-09b59b4e7d50faf7-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;面试绝对是越做越好的事情。我认为，如果你不身临其境，不紧张，你就无法体验如何应对面试官，所以如果你有能力，就继续参加比你实际想要的级别低的公司的面试，这样你就可以在你实际想要的公司取得更好的成绩！&lt;/p&gt;
&lt;h3&gt;完成后...&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-0a384db17a2502a8-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;那么在 SSAFY 之后我们要做什么呢？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我花了很多时间思考这个问题，现在仍在努力寻找答案。基本上，我想花时间静下心来反思一下我所参与的项目，但我也想总结一下我所学到的东西，而且我还想尽快找到一份工作......&lt;/p&gt;
&lt;p&gt;最后，我想我会继续一切。我相信，最好的办法是自下而上，因为我目前所学到的东西不会丢失。我在 SSAFY 的第 8 年旅程即将结束，但我的开发人员生涯不会就此结束！我相信更好的日子在等着我，我会继续努力。&lt;/p&gt;
</content:encoded></item><item><title>2023 年 LG CNS H1 招聘回顾</title><link>https://www.traceoflight.dev/zh/blog/2023-lg-cns/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/2023-lg-cns/</guid><description>Boom！</description><pubDate>Fri, 16 Jun 2023 08:27:19 GMT</pubDate><content:encoded>&lt;h4&gt;在&lt;/h4&gt;
&lt;p&gt;今年上半年，我参加了 LG CNS 的初级招聘，并进入了最后的面试。最后，很遗憾，我没有取得好成绩。不过，与其掩盖自己的失败，不如写下自己的不足，下次做得更好。希望对今后参加招聘的人有所帮助。&lt;/p&gt;
&lt;h3&gt;文件筛选&lt;/h3&gt;
&lt;p&gt;我不认为筛选过程有什么不正常的地方。 唯一不正常的地方是自我介绍的篇幅比其他公司要少。 不过，也有被拒之门外的情况，所以我认为有意想不到的歧视因素。如果通过了，就可以进入编码测试。&lt;/p&gt;
&lt;h3&gt;编码测试&lt;/h3&gt;
&lt;p&gt;总的来说，我认为难度并不高。如果你能随机解决 Silver~ Gold 5 级的问题，我想你就能做得很好。 如果非要给一个方向的话，我认为练习能够应对该领域的任何问题而不是要求创造性的算法会很有帮助。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-0050c757a54e8dd4-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;当你把问题解决到一定程度后，就可以进入面试了，我顺利通过了面试。&lt;/p&gt;
&lt;p&gt;###第一次面试&lt;/p&gt;
&lt;p&gt;通过编码测试后，我收到了第一轮面试的信息。基本上是视频面试，我想他们问了我求职信中的问题和一般的面试问题。 我不记得面试官说了什么，但他说他们对新员工的期望不高，也不评估能力。 他之后还说了一些话，但我当时很紧张，就从记忆中删除了。我想，如果我们少看能力，就会把重点放在个性、自我介绍验证、诚信和文化契合度等方面！&lt;/p&gt;
&lt;p&gt;话说回来，如果你在编码测试中表现出色，你可能会得到面试官对测试的小小赞美。 我感觉很好，因为我注意了可能遇到的反例和边缘情况，感觉就像得到了结果的确认。&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-95c1802564fc051e-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;因为对面试不熟悉，所以我的动作很僵硬、很笨拙，我以为我失败了......但我还是得到了第二次面试的机会。毕竟，卖面也是一门学问。&lt;/p&gt;
&lt;h3&gt;第二次面试&lt;/h3&gt;
&lt;p&gt;与其他公司的筛选类似，如果你真的被录用了，有权决定你在哪个部门工作的人也会亲自来面试你。一开始，他们做了自我介绍，但我太紧张了，根本记不住。我想他们是想让我感觉舒服一些，但我只记得当我觉得和第一次面试差不多时，他们开始问我技术问题，我就开始胡言乱语。最后，我问他如果带着雄心壮志加入公司，会有什么样的态度，我记得他笑着说了一些好话。 还有...&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-306ab2ca84c94e03-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;说实话，当我得到这个答案时，我真的很伤心。不过，面试结束后仔细想想，这个结果也不是没有道理的，因为让我失望的地方有很多，我觉得有些方面我回答得太差了，比如面试官问我的技术问题和对应聘公司的认知程度，所以我没有任何让面试官觉得我想打动并录用的长处。&lt;/p&gt;
&lt;h3&gt;最后的想法&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-ca72109624ea74bc-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;很遗憾，因为我是上半年招聘过程中最接近被录取的。不过，我相信现在收到的成绩单给了我前进的方向，我会继续努力，改进自己不足的地方。&lt;/p&gt;
&lt;p&gt;我希望以这次经历为跳板，成为更好的自己。我会更加努力，在下一次 CNS 招聘中成为&lt;strong&gt;选择组织的人&lt;/strong&gt;，而不是&lt;strong&gt;可以选择组织的人&lt;/strong&gt;。&lt;/p&gt;
</content:encoded></item><item><title>[面试问题] JVM 的结构和原理</title><link>https://www.traceoflight.dev/zh/blog/jvm/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/jvm/</guid><description>编译有关 JVM 的面试问题</description><pubDate>Thu, 15 Jun 2023 16:30:41 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;23-06-27 填充未完成的内容
23-07-01 完成并填写内容&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Java 概述&lt;/h3&gt;
&lt;h4&gt;1. Java 的开发理念&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;一次编写，随处运行&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;以平台无关的语言为目标&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;开发的重点是能够在任何操作系统上运行用相同语言编写的代码（跨平台）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. JDK&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Java 开发工具包
它是 Java 开发工具，包括 JRE 和 JVM。与默认情况下只需运行用 Java 编写的程序的用户不同，开发人员需要安装 JDK。JDK 包括一个编译器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java 运行时环境
Java 运行时环境包括 Java 类库、Java 类加载器和 JVM。使用类加载器和类库编写的 Java 代码可与类库结合在 JVM 上运行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java 虚拟机&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;什么是 JVM？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Java Virtual Machine，Java 虚拟机。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为运行 Java 程序提供环境的软件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Java 代码 → 编译器 → 机器语言&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;通过为应用程序的执行分配内存来构建 Java 运行时数据区。&lt;/p&gt;
&lt;h3&gt;运行时数据区&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;堆区&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;方法区域&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上两个区域由所有线程共享&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;PC 寄存器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;本地方法堆栈&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;堆栈区域&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上述三个区域在每个线程启动时创建，并在终止时销毁。&lt;/p&gt;
&lt;h3&gt;每个区域的详细信息&lt;/h3&gt;
&lt;h4&gt;1. 堆&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;存储类实例和数组的空间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;垃圾回收 * 动态内存管理系统 &amp;quot;垃圾回收&lt;/p&gt;
&lt;h4&gt;2. 方法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;存储类、接口结构的空间&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 堆栈&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;类似于 C 语言的堆栈结构，存储局部变量和函数执行结果&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;它负责调用和返回函数，并有一个堆栈框架。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;什么是堆栈框架？&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;每个函数的分隔空间，包含函数的调用信息。
以后进先出的方式处理堆栈框架
如果在没有空闲空间时添加了一个框架，就会发生堆栈溢出。
指针法使用序幕和尾声检查堆栈返回位置&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;4. 本地方法堆栈&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用 C、CPP 编写的方法的执行堆栈&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行代码时分配本地方法栈&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可能导致堆栈溢出错误或内存不足错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可动态调整堆栈大小&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;5. PC 寄存器&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每个线程都有一个 PC 寄存器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;记录线程执行当前指定指令时的指令地址&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从一条指令到另一条指令，该值会稳步波动，以确保所指向的值被执行&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;注释&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.1&quot;&gt;JVM文档&lt;/a&gt;
&lt;a href=&quot;https://m.blog.naver.com/goreng2/221770110714&quot;&gt;고랭이님의블로그&lt;/a&gt;
&lt;a href=&quot;https://velog.io/@sgwon1996/JAVA%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC%EC%99%80-JVM-%EA%B5%AC%EC%A1%B0&quot;&gt;sgwon1996的velog&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[面试问题] 什么是 DB 索引？</title><link>https://www.traceoflight.dev/zh/blog/db-index/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/db-index/</guid><description>整理数据库索引面试问题</description><pubDate>Tue, 13 Jun 2023 15:20:25 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;加快数据库表搜索速度的数据结构&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;使用索引的优势&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;由于加快了表的查找速度，因此提高了性能&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可减少系统负荷&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;使用索引的缺点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;数据库索引需要额外的存储空间&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据库管理的额外工作和开销&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;索引管理&lt;/h3&gt;
&lt;p&gt;索引需要保持更新和排序，这样才能快速浏览到所需的值，因此在数据经常被修改的属性上挂起索引可能会因开销而导致性能下降。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;INSERT：在插入数据时添加索引。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DELETE：应禁用已删除数据上的索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更新：禁用现有索引 + 为更新数据添加索引&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;使用的数据结构&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;B+ 树&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;B 树增强规范&lt;/p&gt;
&lt;p&gt;只在叶节点中存储数据&lt;/p&gt;
&lt;p&gt;叶节点之间有一个链接列表&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;哈希表&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;以键-值对形式存储数据
可以快速浏览数据
不常用，因为它不适合不等式操作（排序 X）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;索引的分类&lt;/h3&gt;
&lt;h4&gt;1. 按键分类&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;主索引：包含主键（键的顺序 = 记录的顺序）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;二级索引：不含主键（键的顺序 != 记录的顺序）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 根据文件组织分类&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;重点索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;非重点索引&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 按数据范围分类&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;密集索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;稀疏索引&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;注意&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://brunch.co.kr/@skeks463/25&quot;&gt;内森的早午餐故事&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[1天-1CS] 处理各层的设备</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-e4320ddf/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-e4320ddf/</guid><description>每天 1CS，处理各层设备的简要说明</description><pubDate>Mon, 05 Jun 2023 15:08:16 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;2023-06-18 合并以前帖子的内容，使内容保持一致&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;###处理应用层的设备&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;L7 交换机：也称为负载平衡器，是一种平衡服务器负载的设备&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;交换机：连接多个设备并调解数据通信的电信网络设备，仅向与之相连的端口发送电信号以传输数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;旨在增加系统可处理的流量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;根据 URL、服务器、缓存、cookie 等分配流量。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;具有过滤功能，可过滤掉不必要的外部数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;允许流量监控&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;= 健康检查将失败的服务器排除在流量分配之外&lt;/p&gt;
&lt;h3&gt;L4 和 L7 交换机之间的区别&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;L4 交换机是处理传输层的设备，不能用于流媒体相关服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基于消息的不可知性、基于 IP 和端口的流量分配&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在云服务中，L7 交换机的负载平衡是通过 ALB（应用负载平衡器）组件完成的，而 L4 交换机的负载平衡是通过 NLB（网络负载平衡器）组件完成的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;健康检查&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;通过设置传输周期和重传次数等，反复向服务器发送请求。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;适当，以避免服务器超载&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以不同方式发送请求，并确定它们是否得到正确处理。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;使用负载平衡器实现服务器冗余&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;基于 2 个或更多服务器提供虚拟 IP，并以此为基础提供稳定的服务&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;服务器冗余是必要的，因为即使特定服务器发生错误，服务也必须继续。&lt;/p&gt;
&lt;h3&gt;处理互联网层的设备&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;路由器：连接、划分和分离多个网络。
L3 交换机：L2 交换机 + 路由器&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;处理数据链路层的设备&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;L2 交换机：管理设备的 Mac 地址并传输数据包
网桥：允许两个局域网互连的电信网络连接设备。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;处理物理层的设备&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;网络接口卡（NIC）：局域网卡，唯一标识的 Mac 地址就在这里。
中继器：放大输入信号并将其传递到另一端。
接入点：复制数据包的设备；连接有线局域网和无线网络。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[面试问题] 框架和库 (Feat. ChatGPT)</title><link>https://www.traceoflight.dev/zh/blog/framework-library/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/framework-library/</guid><description>关于框架和库的面试问题</description><pubDate>Sat, 03 Jun 2023 13:45:20 GMT</pubDate><content:encoded>&lt;h4&gt;简介&lt;/h4&gt;
&lt;p&gt;在一次面试中，我第一次被问到这个问题，虽然我很诚实地认为自己知道答案，但却无法清楚地回答，最后给出了一个校友的答案......所以我写了这篇文章，以确保我下次能更好地了解这个问题！&lt;/p&gt;
&lt;h3&gt;图书馆&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;将开发中常用的功能模块化，旨在执行特定功能的程序。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;框架&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;具有多种功能的类和库的组合，以实现特定的结果。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;ChatGPT 的回答&lt;/h3&gt;
&lt;p&gt;上述定义是我阅读各种文章后得出的，个人认为这些定义已经接近正确答案。不过，我觉得有些地方不够完整，想得到更详细的答案，所以决定试试 ChatGPT！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;图书馆的定义
&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-63d37d80c7d7a66e-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;框架的定义
&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-f8277c02067f5cf0-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;那么有什么区别呢？&lt;/h3&gt;
&lt;p&gt;如果我们回到上面的答案，看看框架和库，就会发现&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;库&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;可重用代码和资源的集合
由函数、类、方法、数据类型等组成。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;框架&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;开发软件的结构化框架或平台。
由预定义代码和库组成&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就提出了几个问题。如果框架可以包含库，为什么库不能包含框架？&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-27fca29bce6050ea-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;不出所料，事实证明框架可以包含库，反之亦然。 这篇文章还强调了框架和库之间的一个重要区别。&lt;/p&gt;
&lt;p&gt;这就是&lt;strong&gt;代码流的控制&lt;/strong&gt;。在库的情况下，&lt;strong&gt;开发人员调用库的函数并使用它们&lt;/strong&gt;，但在框架的情况下，&lt;strong&gt;开发人员的方法被框架调用&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;框架中出现的这种形式被称为 IoC（控制反转）。由于它与依赖注入（Dependency Injection）有关，我就不多写了，因为我觉得还会有其他内容要写。&lt;/p&gt;
&lt;h3&gt;结语&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;库是可重用代码和资源的集合，而框架则是结构框架或开发平台。就功能而言，它们的工作原理大致相同，区别在于如何使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;框架可以包含库，但库不能包含框架。代码流的控制权掌握在框架和开发人员手中，因此开发人员一般不可能对框架进行修改，而库则可以由开发人员根据需要进行定制。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;另请参见。&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://curryyou.tistory.com/363&quot;&gt;Kareyu 的博客&lt;/a&gt;
ChatGPT 3.5&lt;/p&gt;
</content:encoded></item><item><title>[面试问题] Fork 和 Exec 有什么区别？</title><link>https://www.traceoflight.dev/zh/blog/fork-exec/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/fork-exec/</guid><description>整理有关流程中叉子和执行器的面试问题</description><pubDate>Wed, 31 May 2023 07:48:53 GMT</pubDate><content:encoded>&lt;h3&gt;fork() 和 exec() 有什么共同点？&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;一个进程用来执行另一个进程&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;fork()&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;为新进程分配内存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进程被添加（我们有一个不同 PID 的进程）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;exec()&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不会为新进程分配额外内存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过覆盖现有进程（相同 PID）来加载新进程&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;→ 新进程将在调用后运行，因此在现有程序执行点之后的程序将无法运行&lt;/p&gt;
&lt;h4&gt;注意&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://woochan-autobiography.tistory.com/207#2.%20fork(),%20exec()%EC%9D%98%20%EC%B0%A8%EC%9D%B4%EC%A0%90&quot;&gt;U-chan Seon&apos;s Blog&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[BOJ 2887，蟒蛇]行星隧道</title><link>https://www.traceoflight.dev/zh/blog/boj2887/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj2887/</guid><description>Python 解决 BOJ 2887 &quot;行星隧道 &quot;问题</description><pubDate>Tue, 30 May 2023 15:33:18 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp2@@&quot;&gt;boj 2887&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;图论, 排序, 最小生成树&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-edb2ff1f13cf5892-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我很惊讶这个问题距离我第一次遇到这个问题已经过去半年多了，但我认为这个问题值得记录下来，因为它得到了令人满意的解决，这与我最近对白金问题的忽视相比是一个很好的改变。&lt;/p&gt;
&lt;p&gt;要正式解决这个问题，可以使用联合查找 + 克鲁斯卡尔算法的组合，即从最多 100,000 个坐标中挑选两个坐标，将它们的值从小到大列出，然后将最小的主干线包括在内。&lt;/p&gt;
&lt;p&gt;但是，这将导致求解时间为 10&lt;sup&gt;5&lt;/sup&gt; * 10&lt;sup&gt;5&lt;/sup&gt;，即大约 100 亿例，这将需要大约 100 秒的求解时间，因此这是一种不可行的求解方法。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;提示：如果考虑每 1 亿次操作耗时 1 秒，则很容易计算！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此，这个问题的关键在于如何将案例数从 O(N&lt;sup&gt;2&lt;/sup&gt;) 减少到 O(N)。&lt;/p&gt;
&lt;p&gt;总之，在当前问题中，为任意点构建生成树时，我们不需要考虑相邻点以外的其他点。&lt;/p&gt;
&lt;p&gt;假设我们有任意点 A、B，需要将它们连接到一个点 C。&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;如果 x 值之差（|X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;B&lt;/sub&gt;|）是小于 y 的最小值，则 z
→ 假设点 C 的 x 值位于 A 和 B 的 x 值之间。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果 |X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;C&lt;/sub&gt;| + |X&lt;sub&gt;B&lt;/sub&gt; - X&lt;sub&gt;C&lt;/sub&gt;|，则差不存在。
任何任意的 |X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;B&lt;/sub&gt;| 保留 |X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;C&lt;/sub&gt;| 或 |X&lt;sub&gt;B&lt;/sub&gt; - X&lt;sub&gt;C&lt;/sub&gt;| 进一步连接 C 的 |X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;B&lt;/sub&gt;| &lt;strong&gt;必须大于现有生成树&lt;/strong&gt; → &lt;strong&gt;不能作为反例存在&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因此，如果在当前问题的最小生成树中包含一条连接两个任意点的干线，则证明这两个点一定是邻居！&lt;/p&gt;
&lt;p&gt;解决这个证明是关键，我认为问题的其余部分与典型的联合查找问题并无太大区别。&lt;/p&gt;
&lt;p&gt;***]&lt;/p&gt;
&lt;p&gt;补充）在使用 PriorityQueue 而不是 heapq 时，我遇到了超时问题，我找到了这个问题的答案。&lt;/p&gt;
&lt;p&gt;[在 python 中，heapq 和 PriorityQueue 有什么区别？&lt;/p&gt;
&lt;p&gt;答案是 PriorityQueue 更慢，因为它保证了线程安全。&lt;/p&gt;
&lt;h3&gt;解决方案代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 행성 터널&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; heapq &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; heappush, heappop

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;check_union&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;union_info: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, now_target: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
    해당 노드의 현재 유니온을 조회하는 함수
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; union_info[now_target] == -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        union_info[now_target] = now_target

    &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; union_info[now_target] != now_target:
        union_info[now_target] = check_union(union_info, union_info[now_target])

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; union_info[now_target]

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;make_union&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;union_info: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, target_1: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_2: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
    두 점이 같은 유니온인지 확인하고 아니라면 합쳐주는 함수
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    union_1 = check_union(union_info, target_1)
    union_2 = check_union(union_info, target_2)

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; union_1 == union_2:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; union_1 &amp;gt; union_2:
            union_info[union_1] = union_2
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
            union_info[union_2] = union_1

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;

planet_number = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
coord_list = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(planet_number):
    coord_list.append([i] + &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())))

cost_queue = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;):
    coord_list.sort(key=&lt;span class=&quot;hljs-keyword&quot;&gt;lambda&lt;/span&gt; x: x[i])
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; j &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(planet_number - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):
        heappush(
            cost_queue,
            (
                coord_list[j + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;][i] - coord_list[j][i],
                (coord_list[j][&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], coord_list[j + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]),
            ),
        )

union_info = [-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(planet_number)]

total_length = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
line_number = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; cost_queue:
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; line_number == planet_number - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

    now_length, nodes = heappop(cost_queue)
    node_a, node_b = nodes

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; make_union(union_info, node_a, node_b):
        total_length += now_length
        line_number += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(total_length)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[面试问题] 进程与线程、多线程之间的区别</title><link>https://www.traceoflight.dev/zh/blog/process-thread/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/process-thread/</guid><description>关于流程和线程之间区别的面试问题</description><pubDate>Mon, 29 May 2023 17:44:03 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;~~ 我还在写这篇文章！~~ &amp;gt;~23.
&lt;s&gt;23. 05. 30. 写作完成&lt;/s&gt; → 23. 06. 09. 添加内容&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;计划&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;为计算机执行特定任务而编写的一组可执行指令。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它有许多不同的定义，但我在阅读时是这样理解的！我之所以先检查程序的定义，是因为进程的定义是一个范围较窄的程序。&lt;/p&gt;
&lt;h3&gt;流程&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&apos;运行中&apos;&lt;strong&gt;的程序的&lt;/strong&gt;&apos;实例&apos;&lt;/strong&gt; （几乎可与任务互换使用）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在内存中运行的基于操作系统的工作单元&lt;/p&gt;
&lt;p&gt;耗费大量时间和资源来创建（高开销）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我认为有特点的部分是，可以同时拥有一个程序的多个实例，而不是程序本身。&lt;/p&gt;
&lt;h4&gt;线程&lt;/h4&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;在进程中执行工作的基于 CPU 的执行单元。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有处理器都至少有一个线程&lt;/p&gt;
&lt;p&gt;线程有自己的寄存器和堆栈&lt;/p&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;堆内存空间是共享的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;那么两者之间有什么区别呢？&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;进程可被视为一个更大的分类单元&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不过，我想如果我就这么简单地回答，那就太全面了，所以我参考了一些条理清晰的文章，补充说明了一些问题！&lt;/p&gt;
&lt;h3&gt;工作原理&lt;/h3&gt;
&lt;h4&gt;1. 对于流程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;进程运行时，操作系统会为其分配一个单独的内存区域。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内存区域的格式如下：代码/数据/堆栈/Heap&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不能访问其他进程的内存区域&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 对于线程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;进程的堆栈区域被分割并拥有自己的区域&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代码区、数据区和堆区的其余部分是共享的&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;一个进程的错误不会扩散到其他进程的区域&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;但如果一个线程失败，所有线程都会终止&lt;/strong&gt;。
→ 因为它们共享内存区域&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4&gt;摘要&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;进程（Process）和线程（Thread）有什么区别？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;进程是动态使用的程序，线程是任务的执行单位，但概念不同。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个进程至少包含一个线程&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进程通常不共享内存空间，但线程可以&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进程在每次出错时都会单独宕机，而线程则会在同一进程内全部宕机&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;***]&lt;/p&gt;
&lt;h3&gt;+ 关于多线程&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;在一个进程中同时运行多个线程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;上下文切换（上下文切换）&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;默认情况下，可同时处理的最大任务数为内核数。
如果运行的线程数多于内核数，则每个内核会交替执行多个任务。
线程切换时，会保存并读取任务的当前状态或下一个任务所需的数据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;多线程和进程的优缺点&lt;/h4&gt;
&lt;h5&gt;1) 多线程的优点&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;创建进程和分配资源的系统调用处于休眠状态，可有效管理资源。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;线程之间发送和接收数据的处理成本较低，因为除堆栈外，它们在一个进程内共享内存空间。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于线程之间的通信方法不那么复杂，程序响应时间缩短。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;2) 多线程的缺点&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;增加调试难度和设计难度&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;其他进程线程的不可控性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内存共享（同时访问相同资源）导致的同步问题&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个线程的问题会影响整个进程&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;3) 多进程的优势&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;如果一个进程出现问题，其影响不会扩散到该进程之外&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;4) 多进程的缺点&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;上下文交换开销大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进程间通信比线程间通信更加困难和复杂&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;注意&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/&quot;&gt;维基百科关于进程和线程的词条&lt;/a&gt;
&lt;a href=&quot;https://velog.io/@raejoonee/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4&quot;&gt;进程与线程的区别&lt;/a&gt;
&lt;a href=&quot;https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html&quot;&gt;进程与线程的区别 by heejeong Kwon&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[CI/CD] 从实例到 DooD 部署的流程（特点：Nginx、Jenkins）</title><link>https://www.traceoflight.dev/zh/blog/ci-cd-dood-feat-nginx-jenkins/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/ci-cd-dood-feat-nginx-jenkins/</guid><description>使用 Docker 和 Nginx 巩固部署基础</description><pubDate>Sat, 27 May 2023 14:55:17 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;23-06-16 修改路径，使音量安装更清晰
23-07-05 调整设置，方便开发&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;简介&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;/blog/cicd-docker-jenkins-git-webhook&quot;&gt;[CI/CD]使用 Docker + Jenkins + Git Webhook 组织 FastAPI 服务器的自动部署&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;之所以写这篇文章，是因为上面的最后一篇文章包含了我当初努力学习的内容，但我想把需要修正的部分修正一下，把需要打磨的部分打磨一下，完成成一篇整齐的文章。&lt;/p&gt;
&lt;p&gt;从上次开始，我已经掌握了一定的诀窍，并将部署任务条理化，也帮助了身边的人进行部署，所以我希望可以将其记录下来，作为下次部署的统一流程！如果你按照本帖的顺序进行部署，我想你不会觉得有什么困难。&lt;/p&gt;
&lt;p&gt;###第 1 部分后我学到的其他东西&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么要在 Docker 之外而不是 Docker 之中实施？&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;默认情况下，Docker 不鼓励在 Docker 容器上执行命令。&lt;/p&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Docker 中的 Docker 赋予安装了 Docker 的容器强大的权限，这可能是一个安全风险&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Docker 外的 Docker 允许你通过与容器外的 Docker 共享套接字来运行 Docker 命令。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;使用 Docker API 如何？&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;实际上，我就是用它来解决第 1 部分中的问题的，而且成功了。
但我认为，如果你已经成功地从 Docker 中构建了系统，那么在 CI/CD 程序中就不需要它了......&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;关于应用程序接口的一些内容，我觉得太含糊，无法单独写出来，所以就写下来了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Docker 使用 REST API 在引擎和客户端之间进行通信，该 API 大部分未被使用，但可用。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;  docker --tlsverify --tlscacert=/.docker/ca.pem \
  --tlscert=/.docker/cert.pem --tlskey=/.docker/key.pem \
  -H={server_ip}:{port_number} &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; nginx \
  sed -i &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;4s/.*$/ server {container}:8000;/&amp;#x27;&lt;/span&gt; /etc/nginx/sites-available/default.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码通过带有 TLS 证书的 Docker 客户端修改位于任意服务器上的 Nginx 配置文件的内容。
它通过 -H 命令，通过服务器上的端口与守护进程（Docker 引擎）通信，代码的其余部分是通过证书确保访问安全的程序。&lt;/p&gt;
&lt;p&gt;如果不使用证书而开放端口，就会有人通过该端口撞毁你的容器！&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-fb3d711504538106-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;容器干扰的真实体验。我在没有安全认证的情况下打开了一个 Docker 常用的端口...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;通过证书确保安全是必须的，如果因为某些不可避免的原因而无法确保安全，就必须限制通过该端口运行的命令。&lt;/p&gt;
&lt;p&gt;详情请参见 [Docker应用程序接口文档] (&lt;a href=&quot;https://docs.docker.com/engine/api/v1.43/&quot;&gt;https://docs.docker.com/engine/api/v1.43/&lt;/a&gt;)！&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;构建 All in One 部署基础的步骤&lt;/h4&gt;
&lt;h4&gt;1. 访问和更新实例&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh -i {secure shell key 경로} {사용자 이름}@{IP 주소}

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get update
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get upgrade
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果设置的是 ubuntu，用户名通常是 ubuntu。&lt;/p&gt;
&lt;h4&gt;2. 防火墙设置&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw allow ssh    &lt;span class=&quot;hljs-comment&quot;&gt;# ssh를 22로 대체할 수 있다.&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw allow http   &lt;span class=&quot;hljs-comment&quot;&gt;# http를 80으로 대체할 수 있다.&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw allow https  &lt;span class=&quot;hljs-comment&quot;&gt;# https를 443으로 대체할 수 있다.&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw &lt;span class=&quot;hljs-built_in&quot;&gt;enable&lt;/span&gt; 	  &lt;span class=&quot;hljs-comment&quot;&gt;# 방화벽 가동&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw status 	  &lt;span class=&quot;hljs-comment&quot;&gt;# 방화벽 상태 확인&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你使用的是云，云默认有自己的端口安全设置，所以需要在设置中单独打开。
UFW 是 Ubuntu 的防火墙，如果第一次设置时关闭了，则需要允许端口后再打开。
通过上述设置，你可以打开防火墙，并默认打开 HTTP(80)、HTTPS(443) 和 SSH(22) 端口。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;建议先打开端口允许设置。如果在 SSH 端口 22 关闭的情况下打开防火墙，将无法连接到防火墙。&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;3. 安装 Docker 和 Docker Compose&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Docker 설치&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get update
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get install ca-certificates curl gnupg

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | &lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; gpg --dearmor -o /etc/apt/keyrings/docker.gpg
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; a+r /etc/apt/keyrings/docker.gpg

&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;deb [arch=&lt;span class=&quot;hljs-subst&quot;&gt;$(dpkg --print-architecture)&lt;/span&gt; signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
&lt;span class=&quot;hljs-subst&quot;&gt;$(. /etc/os-release &amp;amp;&amp;amp; echo &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$VERSION_CODENAME&lt;/span&gt;&amp;quot;&lt;/span&gt;)&lt;/span&gt; stable&amp;quot;&lt;/span&gt; | \
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get update
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

&lt;span class=&quot;hljs-comment&quot;&gt;# Docker Compose 설치&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt install docker-compose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/ubuntu/&quot;&gt;Ubuntu Docker 安装文件&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;截至 2023 年 5 月，我只从文档中摘录了我需要的内容。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; usermod -aG docker &lt;span class=&quot;hljs-variable&quot;&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该命令允许你在没有 sudo 的情况下使用 docker 命令。
如果不包含它，你会得到 &lt;code&gt;/var/run/docker.sock: connect: permission denied&lt;/code&gt;。&lt;/p&gt;
&lt;h4&gt;4. 编写 docker-compose.yml&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3.8&amp;#x27;&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
  {&lt;span class=&quot;hljs-string&quot;&gt;원하는&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}&lt;span class=&quot;hljs-string&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;driver:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bridge&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;services:&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;# Jenkins Container 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;jenkins:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins/jenkins:lts&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{원하는 포트 번호}:8080&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/jenkins:/var/jenkins_home&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;user:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;원하는&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;部署管道工具的编写方式就像利用 Jenkins 一样。&lt;/p&gt;
&lt;p&gt;如果没有需要添加的网络，可以完全省略网络部分，直接从 Docker 中为要使用的套接字进行卷绑定。你可以根据需要设置时区或其他卷绑定。&lt;/p&gt;
&lt;h4&gt;5. 为要使用的域设置 DNS&lt;/h4&gt;
&lt;p&gt;不同的域名提供商使用不同的方法。您需要查看域名提供商的注册说明，注册您要使用的服务器的 IP，并将其与您的域名关联起来。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.whatsmydns.net/&quot;&gt;我的 DNS 是什么&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;您不能注册后立即开始使用，DNS 服务器会有一个反映时间差。我在上面附上了一个网站，您可以轻松查看它的受欢迎程度。&lt;/p&gt;
&lt;h4&gt;6. 使用 Let&apos;s Encrypt 签发证书&lt;/h4&gt;
&lt;h5&gt;1) docker-compose.yml&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Nginx 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;nginx:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt; 			&lt;span class=&quot;hljs-comment&quot;&gt;# Nginx 설정을 위한 바인딩&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx/sites-available:/etc/nginx/sites-available&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;				&lt;span class=&quot;hljs-comment&quot;&gt;# 인증서 공유를 위한 바인딩&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:80&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:443&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;원하는&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}

  &lt;span class=&quot;hljs-comment&quot;&gt;# Certbot 컨테이너 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;certbot:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将此添加到 docker-compose.yml，但不要处理它。&lt;/p&gt;
&lt;h5&gt;2) mount/sites-available/default.conf&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-nginx&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;server&lt;/span&gt; {
     &lt;span class=&quot;hljs-attribute&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;;
     &lt;span class=&quot;hljs-attribute&quot;&gt;listen&lt;/span&gt; [::]:&lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;;

     &lt;span class=&quot;hljs-attribute&quot;&gt;server_name&lt;/span&gt; my_domain.org; 

     &lt;span class=&quot;hljs-section&quot;&gt;location&lt;/span&gt; /.well-known/acme-challenge/ {
             &lt;span class=&quot;hljs-attribute&quot;&gt;allow&lt;/span&gt; all;
             &lt;span class=&quot;hljs-attribute&quot;&gt;root&lt;/span&gt; /var/www/certbot;
     }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;文件，并在其中加入 &lt;code&gt;server_name&lt;/code&gt; 后跟上您的域名。&lt;/p&gt;
&lt;h5&gt;3) mount/nginx.conf&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-nginx&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;user&lt;/span&gt; nginx;
&lt;span class=&quot;hljs-attribute&quot;&gt;worker_processes&lt;/span&gt; auto;
&lt;span class=&quot;hljs-attribute&quot;&gt;worker_priority&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

&lt;span class=&quot;hljs-attribute&quot;&gt;pid&lt;/span&gt; /run/nginx.pid;
&lt;span class=&quot;hljs-attribute&quot;&gt;include&lt;/span&gt; /etc/nginx/modules-enabled/&lt;span class=&quot;hljs-regexp&quot;&gt;*.conf&lt;/span&gt;;

&lt;span class=&quot;hljs-section&quot;&gt;events&lt;/span&gt; {
        &lt;span class=&quot;hljs-attribute&quot;&gt;worker_connections&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;multi_accept&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;off&lt;/span&gt;;
}

&lt;span class=&quot;hljs-section&quot;&gt;http&lt;/span&gt; {

        &lt;span class=&quot;hljs-attribute&quot;&gt;sendfile&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;tcp_nopush&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;tcp_nodelay&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;keepalive_timeout&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;65&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;types_hash_max_size&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2048&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;server_tokens&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;off&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;include&lt;/span&gt; /etc/nginx/mime.types;
        &lt;span class=&quot;hljs-attribute&quot;&gt;default_type&lt;/span&gt; application/octet-stream;
        &lt;span class=&quot;hljs-attribute&quot;&gt;log_format&lt;/span&gt;  main  &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&lt;span class=&quot;hljs-variable&quot;&gt;$remote_addr&lt;/span&gt; - &lt;span class=&quot;hljs-variable&quot;&gt;$remote_user&lt;/span&gt; [&lt;span class=&quot;hljs-variable&quot;&gt;$time_local&lt;/span&gt;] &amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$request&lt;/span&gt;&amp;quot; &amp;#x27;&lt;/span&gt;
                          &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&lt;span class=&quot;hljs-variable&quot;&gt;$status&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$body_bytes_sent&lt;/span&gt; &amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$http_referer&lt;/span&gt;&amp;quot; &amp;#x27;&lt;/span&gt;
                          &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$http_user_agent&lt;/span&gt;&amp;quot; &amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$http_x_forwarded_for&lt;/span&gt;&amp;quot;&amp;#x27;&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;ssl_protocols&lt;/span&gt; TLSv1 TLSv1.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; TLSv1.&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; TLSv1.&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;; &lt;span class=&quot;hljs-comment&quot;&gt;# Dropping SSLv3, ref: POODLE&lt;/span&gt;
        &lt;span class=&quot;hljs-attribute&quot;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;access_log&lt;/span&gt; /var/log/nginx/access.log main;
        &lt;span class=&quot;hljs-attribute&quot;&gt;error_log&lt;/span&gt; /var/log/nginx/&lt;span class=&quot;hljs-literal&quot;&gt;error&lt;/span&gt;.log &lt;span class=&quot;hljs-literal&quot;&gt;debug&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;include&lt;/span&gt; /etc/nginx/sites-available/*;

}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是一个相当基本的配置，基于首次安装nginx时所包含的内容。&lt;/p&gt;
&lt;h5&gt;4) 通过 Let&apos;s Encrypt 签发证书，这是一个过程&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh -o init-letsencrypt.sh
&lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; +x init-letsencrypt.sh
vi init-letsencrypt.sh			&lt;span class=&quot;hljs-comment&quot;&gt;# 여기서 도메인과 메일 주소를 입력해야 함&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ./init-letsencrypt.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从外部获取帮助你完成证书签发过程的文件，并设置权限。然后，你可以在文件中输入你的域名和电子邮件地址，并运行文件来签发证书。如果签发失败，你可以查看日志找出失败原因，修复后再试一次。&lt;/p&gt;
&lt;h4&gt;7. 为证书更新设置 Nginx&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Nginx 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;nginx:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/sites-available:/etc/nginx/sites-available&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:80&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:443&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;연결을&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;원하는&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}
    &lt;span class=&quot;hljs-attr&quot;&gt;command:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/bin/sh -c &amp;#x27;while :; do sleep 6h &amp;amp; wait $${!}; nginx -s reload; done &amp;amp; nginx -g \&amp;quot;daemon off;\&amp;quot;&amp;#x27;&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;# Certbot 컨테이너 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;certbot:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;entrypoint:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/bin/sh -c &amp;#x27;trap exit TERM; while :; do certbot renew; sleep 12h &amp;amp; wait $${!}; done;&amp;#x27;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s Encrypt 签发的证书有效期有限，当证书即将过期时可以重新签发。你可以在 certbot 和 nginx 容器中添加与补发相关的命令，以自动处理证书更新。这样，nginx 就不会因为证书已签发而在构建容器时出错。&lt;/p&gt;
&lt;h4&gt;8.在 Jenkins 容器内安装 Docker&lt;/h4&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;已添加）我原本直接列出了命令，但我意识到这并不直观，所以我修正了它！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# /jenkins-docker-install.sh&lt;/span&gt;

apt-get update
apt-get install ca-certificates curl gnupg

install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
&lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; a+r /etc/apt/keyrings/docker.gpg

&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;deb [arch=&lt;span class=&quot;hljs-subst&quot;&gt;$(dpkg --print-architecture)&lt;/span&gt; signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/debian \
&lt;span class=&quot;hljs-subst&quot;&gt;$(. /etc/os-release &amp;amp;&amp;amp; echo &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$VERSION_CODENAME&lt;/span&gt;&amp;quot;&lt;/span&gt;)&lt;/span&gt; stable&amp;quot;&lt;/span&gt; | \
&lt;span class=&quot;hljs-built_in&quot;&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null

apt-get update
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我创建了一个 sh 文件，可以从现有的 docker 安装方法中移除 sudo 命令。你可以通过挂载把这个文件放进去，然后运行它，就能实现干净利落的单间安装了！&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;9. 处理 Docker Compose&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3.8&amp;#x27;&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
  {&lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}&lt;span class=&quot;hljs-string&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;driver:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bridge&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;services:&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;# Jenkins Container 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;jenkins:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins/jenkins:lts&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{포트 번호}:8080&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/jenkins:/var/jenkins_home&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/jenkins-html:/var/lib/jenkins&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./jenkins-docker-install.sh:/jenkins-docker-install.sh&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;user:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}

&lt;span class=&quot;hljs-comment&quot;&gt;# Nginx 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;nginx:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx/sites-available:/etc/nginx/sites-available&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:80&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:443&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}
    &lt;span class=&quot;hljs-attr&quot;&gt;depends_on:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;선행&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;컨테이너&lt;/span&gt;}
    &lt;span class=&quot;hljs-attr&quot;&gt;command:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/bin/sh -c &amp;#x27;while :; do sleep 6h &amp;amp; wait $${!}; nginx -s reload; done &amp;amp; nginx -g \&amp;quot;daemon off;\&amp;quot;&amp;#x27;&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;# Certbot 컨테이너 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;certbot:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;entrypoint:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/bin/sh -c &amp;#x27;trap exit TERM; while :; do certbot renew; sleep 12h &amp;amp; wait $${!}; done;&amp;#x27;&amp;quot;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;添加这些 Jenkins 配置后，运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;language-xml&quot;&gt;docker-compose -f &lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{yml 파일 위치 및 파일명}&lt;/span&gt;&lt;span class=&quot;language-xml&quot;&gt; up -d
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;命令调出所有容器。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; -it jenkins bin/bash
sh /jenkins-docker-install.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过在 Jenkins 容器内安装 Docker，我们可以通过 Jenkins 内部 Shell 命令控制 Docker 引擎。
我们遵循了现有的 Docker 文档，但不同之处在于我们没有使用 sudo，而且我们安装的是 Debian 版 Docker。&lt;/p&gt;
&lt;h3&gt;可选&lt;/h3&gt;
&lt;h4&gt;1. 设置交换内存&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# swap memory 설정&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; fallocate -l {설정 용량} /swapfile   &lt;span class=&quot;hljs-comment&quot;&gt;# 설정 용량은 대체로 G 단위로 설정한다.&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; 600 /swapfile
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; mkswap /swapfile
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; swapon /swapfile

&lt;span class=&quot;hljs-comment&quot;&gt;# 재부팅 시에도 지속 사용을 원할 경우&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; vi /etc/fstab 			&lt;span class=&quot;hljs-comment&quot;&gt;# &amp;#x27;/swapfile swap swap defaults 0 0&amp;#x27; 내용을 해당 파일에 삽입&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# swap 비활성화&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; vi /etc/fstab 			&lt;span class=&quot;hljs-comment&quot;&gt;# &amp;#x27;/swapfile swap swap defaults 0 0&amp;#x27; 내용을 제거&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; swapoff -v /swapfile
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; /swapfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;根据实例性能和需求，您可能需要设置交换内存，以防止实例弹出。&lt;/p&gt;
&lt;h4&gt;2. 如果 Jenkins 插件安装错误，应尝试哪些方法&lt;/h4&gt;
&lt;p&gt;&amp;lt;解决方案 1
转到 Jenkins 管理 &amp;gt; 插件管理器 &amp;gt; 高级设置 &amp;gt; 更新站点部分
将 &lt;code&gt;https://updates.jenkins.io/update-center.json&lt;/code&gt; 更改为 &lt;code&gt;http://updates.jenkins.io/update-center.json&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;解决方案 2
安装名为 &lt;code&gt;skip-certificate-check&lt;/code&gt; 的插件&lt;/p&gt;
&lt;p&gt;这不是一个完美的解决方案，但我看到所有这些解决方案都取得了一些成功。&lt;/p&gt;
&lt;h4&gt;结论&lt;/h4&gt;
&lt;p&gt;关于 Docker，我就写到这里吧，除了稍后的一些框架部署。如果有机会，我以后会写更多关于部署的内容，因为在真实网络上看到自己的工作是一种很棒的感觉。&lt;/p&gt;
</content:encoded></item><item><title>[面试问题] 什么是 RESTful API？</title><link>https://www.traceoflight.dev/zh/blog/restful-api/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/restful-api/</guid><description>关于 RESTful API 的面试问题</description><pubDate>Sun, 21 May 2023 17:27:57 GMT</pubDate><content:encoded>&lt;h3&gt;RESTful API&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;指 RESTful API。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-3a8f738579ac35de-image.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;不言自明，但听起来就是那么回事！
让我们来看看每个单词的意思，你就会明白 RESTful API 是怎么回事了。&lt;/p&gt;
&lt;p&gt;###应用程序接口&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;应用程序编程接口的简称。
允许两个软件组件使用一套定义和协议相互通信的机制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我是这样定义的。我对它的理解是，不同的软件组件有不同的方法来处理对象等，为了处理这种差异，需要建立一种约定，使它们能够相互通信和交互。&lt;/p&gt;
&lt;h3&gt;REST&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;表征状态转移。
分布式超媒体系统（如万维网）的软件架构之一。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;REST 最初是作为在互联网等复杂网络中管理通信的指南而创建的，据说它对于大规模通信是可靠的，而且易于实施和修改。&lt;/p&gt;
&lt;h4&gt;REST 架构的原则&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;统一接口（Uniform Interface）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;服务器以标准格式发送信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;标准格式可能与服务器上资源的内部表示不同&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对同一资源的所有应用程序接口请求都是一样的，与具体语言、平台等无关。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;无状态&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每个请求都独立于所有其他请求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务器无需额外信息就能完全理解并满足请求&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分层系统&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不同的应用程序协同工作，以满足客户的要求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多层服务器，在服务器和客户端之间可能存在不同的授权中间人&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;额外的中介机构，如代理和网关、加密、负载平衡层等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;客户端不可见&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可缓存（Cacheable）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;支持缓存，以存储某些响应，从而缩短服务器响应时间&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在客户端或服务器端实施缓存&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按需代码（On Demand Code）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;交付通常是静态的资源&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在按需响应中包含可执行代码，允许您临时扩展或定制客户端功能&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;使用 RESTful API 的好处&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可扩展性&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可扩展性，因为它优化了客户端与服务器之间的交互&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;灵活性&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;支持客户端与服务器完全分离&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;简化和分离服务器组件，使每个部分都能独立发展&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;独立性&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;独立于所使用的技术&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能够使用各种编程语言和变更技术编写客户端和服务器应用程序，而无需考虑应用程序接口的设计&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;摘要&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;什么是 RESTful API？
它是指使用 REST 架构的应用程序编程接口，是一种组织遵守 REST 架构原则的程序之间交互的约定。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;那么有什么好处呢？
使用这些 API 的好处是可扩展性、灵活性和独立性！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;另请参见。&lt;/h4&gt;
&lt;p&gt;[什么是 RESTful API？&amp;quot;(&lt;a href=&quot;https://aws.amazon.com/ko/what-is/restful-api/&quot;&gt;https://aws.amazon.com/ko/what-is/restful-api/&lt;/a&gt;)&lt;/p&gt;
</content:encoded></item><item><title>[1天-1CS] 网络设备覆盖范围</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-2e8effb4/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-2e8effb4/</guid><description>1CS 1 天内，快速了解网络设备的覆盖范围以及哪些设备负责处理应用层</description><pubDate>Fri, 19 May 2023 17:06:42 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;2023-06-18 编辑内容范围&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;分级处理范围&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;应用层：L7 交换机&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;互联网层：L3 交换机、路由器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据链路层：L2 交换机、网桥&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;物理层：网卡、中继器、接入点&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>开始整理您的面试问题！（问题历史记录）</title><link>https://www.traceoflight.dev/zh/blog/velog-bdb80888/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/velog-bdb80888/</guid><description>面试问题练习以及为什么要问这些问题</description><pubDate>Tue, 16 May 2023 22:32:46 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-2d4a54a2ae94fc97-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;仪器&lt;/h3&gt;
&lt;p&gt;我不知道从我开始认真地向公司投简历到现在有多久了......我想大概有三个月了吧，但我并没有通过所有的编码测试，但我通过了其中的不少测试，而且我最近还得到了几个面试机会！&lt;/p&gt;
&lt;p&gt;但是，即使我去面试，即使我学过 CS，面试中出现的问题和我学过的 CS 知识还是有区别的......所以，我想在博客上写写面试中出现的问题和我在 Pinpoint 学习的内容。&lt;/p&gt;
&lt;h3&gt;问题列表&lt;/h3&gt;
&lt;h4&gt;总体&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;什么是 RESTful API？](/blog/restful-api)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进程和线程的区别](/blog/process-thread)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/fork-exec&quot;&gt;Fork和Exec的区别&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;框架与库](/blog/framework-library)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;什么是事务？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关于 OSI 第 7 层&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子网、网关和专用 IP&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;后台&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;什么是 DB 索引](/blog/db-index)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;什么是连接池](/blog/connection-pool)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/jvm&quot;&gt;jvm의 구조와 원리&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/java-stack-heap&quot;&gt;Java Heap &amp;amp; Stack의 구조&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;依赖注入](/blog/dependency-injection)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Spring IoC 容器如何管理 Bean
+ 代理模式、Spring Beans 如何成为代理以及如何实现多线程行为。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;单例模式和Spring依赖注入&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;前端&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;在地址栏中输入访问 URL 时会发生什么情况&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1 天-1CS] 跨层数据传输与接收课程和 PDU</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-pdu/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-pdu/</guid><description>快速复习 1CS、跨层数据传输和 TDU</description><pubDate>Sun, 07 May 2023 17:02:23 GMT</pubDate><content:encoded>&lt;h3&gt;封装和解封过程&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;封装：将上层的报头和数据嵌入下层的数据部分，并插入该层的报头。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;应用 → 传输 → 互联网 → 传递到链路层&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分段或数据编排 + 添加 TCP（第 4 层）报头，因为它传递到传输层&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;转发到互联网层，添加 IP（第 3 层）报头 = 数据包&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;转发到链路层，添加帧头 + 帧拖尾 = 帧&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;解封装：从低层到高层时删除各层报头部分的过程&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;解封装反向进行&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;帧 → 数据包 → 网段、数据报 → 信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最后在应用程序中作为传输数据单元（TDU）报文传送&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;协议数据单元&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;数据在层与层之间传递时的大块单位&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不同层有不同的名称，如消息、段、数据报、数据包、帧、位等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以比特为单位传输速度最快，效率最高&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应用层基于字符串的发送和接收（因为易于扩展）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1天-1CS] 半双工通信（2）、无线通信和以太网帧</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-70a48fb3/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-70a48fb3/</guid><description>1 天 快速复习 1CS、半双工通信、无线通信和以太网帧</description><pubDate>Thu, 04 May 2023 14:01:28 GMT</pubDate><content:encoded>&lt;h4&gt;半双工通信的类型&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CSMA/CD: 发送数据，如果数据发送后发生碰撞，则在一段时间后重发&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CSMA/CA：在发送数据前主动检测载波，尽可能避免碰撞。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;发送数据前检查无线介质&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;确定线路是否空闲（载波检测）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果忙，则根据随机值（IFS）以增加的间隔检查可用性&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;无线通信&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Wifi：允许电子设备连接到无线局域网信号的技术；需要无线接入设备。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BSS（基本服务集）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;代表基本服务集&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过路由器进行简单访问 + 接入点和同一 BSS 内的设备可相互通信&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;扩展服务集（ESS）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一组或多组已连接的 BSS&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供远距离无线通信&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与 BSS 相比，具有更高的可用性和移动性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;允许您从一个地点移动到另一个地点，并不间断地与网络保持连接&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;以太网帧&lt;/h3&gt;
&lt;p&gt;数据链路层使用的传输机制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;序言：宣布以太网帧开始&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SFD（起始帧分隔符）：表示 MAC 地址字段从下一个字节开始。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DMAC、SMAC：发送和接收 MAC 地址&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以太类型：定义 IP 协议&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有效载荷：接收到的数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CRC： 错误检查位&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[BOJ 2473，Python] 三种解决方案</title><link>https://www.traceoflight.dev/zh/blog/boj2473/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj2473/</guid><description>Python 解决 BOJ 2473 &quot;三个解决方案 &quot;问题的办法</description><pubDate>Thu, 04 May 2023 13:15:05 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp1@@&quot;&gt;boj 2473&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;分段、排序、两个指针&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;这是经典的双指针问题的稍高级版本。&lt;/p&gt;
&lt;p&gt;当我第一次解这道题时，我认为一定有不同的解法，因为我必须把三种解法结合起来，所以我出乎意料地没有使用精确法，导致实际解题速度减慢。&lt;/p&gt;
&lt;p&gt;这个问题最重要的一点是，解的总数必须在 5000 个以内。如果没有这个条件，这个问题就永远无法及时解决......可惜我一开始没有注意到这个条件，导致我一直在寻找其他解法。&lt;/p&gt;
&lt;p&gt;因此，这个问题的解决方案可以表述如下。&lt;/p&gt;
&lt;p&gt;排序→固定一个解→对其余解使用双指针算法，与该解求和，得到最接近 0 的解→当所有解都遍历或到达 0 时停止&lt;/p&gt;
&lt;h3&gt;求解代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 세 용액&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

solution_number = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
solution_list = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))

solution_list.sort()
characteristic_value = &lt;span class=&quot;hljs-number&quot;&gt;3000000000&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(solution_number):

    pointer_1 = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
    pointer_2 = solution_number - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; pointer_1 &amp;lt; pointer_2:

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; pointer_1 == idx:
            pointer_1 += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; pointer_2 == idx:
            pointer_2 -= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; pointer_1 &amp;gt;= pointer_2:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        now_value = &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;([solution_list[idx], solution_list[pointer_1], solution_list[pointer_2]])

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;abs&lt;/span&gt;(now_value) &amp;lt; characteristic_value:
            characteristic_value = &lt;span class=&quot;hljs-built_in&quot;&gt;abs&lt;/span&gt;(now_value)
            result = [solution_list[idx], solution_list[pointer_1], solution_list[pointer_2]]

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; characteristic_value:
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_value &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;:
            pointer_1 += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; now_value &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;:
            pointer_2 -= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; characteristic_value:
        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

result.sort()

&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(*result)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[1 天 1CS] 全双工和半双工通信 (1)</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-1/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-1/</guid><description>1 天 1CS，快速回顾全双工和半双工通信介绍</description><pubDate>Mon, 01 May 2023 16:24:13 GMT</pubDate><content:encoded>&lt;h3&gt;全双工通信&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;两台设备可同时发送和接收信号的方法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;发送和接收数据的发送路径和接收路径分开&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;现代快速以太网使用这种方法&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;半双工通信&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;两个设备可以相互通信，但不能同时通信
基于一条路径，一次只能进行一个方向的通信&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果发送数据后发生碰撞，则会在一段时间后重新传输。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有线局域网&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;双绞线：电缆绞在一起以减少噪音（串扰）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;光纤电缆：利用芯线和电缆的折射率差异传输光的电缆。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;无线局域网&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;半双工通信，使用同一信道进行传输和接收。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1天-1CS] 互联网层和链路层</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-e167b4e7/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-e167b4e7/</guid><description>1 天 1CS，快速复习互联网层和链路层</description><pubDate>Thu, 27 Apr 2023 03:32:49 GMT</pubDate><content:encoded>&lt;h3&gt;互联网层&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;用于将从设备接收到的网络数据包传输到其 IP 地址指定的目的地的层。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;链路层&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;建立设备间数据和信号实际传递规则的层，也称为网络接入层。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;物理层：在局域网上发送由 0 和 1 组成的数据的层。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据链路层：负责通过以太网帧进行错误检查、流量和访问控制。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1天-1CS] 传输层</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-f7e9e56d/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-f7e9e56d/</guid><description>1CS 1 天内，快速回顾传输层</description><pubDate>Tue, 25 Apr 2023 17:14:48 GMT</pubDate><content:encoded>&lt;h4&gt;传输层&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;提供连接发送方和接收方的通信服务。
提供面向连接的数据流支持、可靠性和流量控制
充当应用层和互联网层之间的数据传输中介&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;TCP：保证顺序，使用面向连接的协议，并确认收到（虚拟线路数据包交换）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UDP：排序 X、确认 X、简单数据传输（数据报数据包交换）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;虚拟线路数据包交换方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每个数据包包含一个虚拟线路标识符&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;虚拟线路在所有数据包发送完毕后释放，数据包按发送顺序到达&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;数据报数据包的交换方式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;数据包独立移动，选择最佳路径&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可按不同路径和顺序发送&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TCP 如何建立和中断连接&lt;/h3&gt;
&lt;p&gt;连接到 ####：三方握手&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;客户端发送带有 ISN 的连接请求标志； 2.
服务器发送服务器的 ISN 和客户端的 ISN + 1 以及授权号； 3.&lt;/li&gt;
&lt;li&gt;客户端回复服务器的 ISN + 1 和授权号&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;断开连接：4 路握手&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;客户端发送 FIN 设置段并进入 FIN\WAIT
接收数据的服务器向客户端发送 ACK 确认段并进入 CLOSE_WAIT&lt;/li&gt;
&lt;li&gt;在发送 ACK 一段时间后发送 FIN 段
客户端收到 ACK，进入 TIME/WAIT（等待），并将 ACK 重新发送回服务器； 5.
接收服务器发送 CLOSE&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;使用 TIME_WAIT 的原因：可能出现延迟包，确认断开连接&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[BOJ 7490，Python] 创建 0</title><link>https://www.traceoflight.dev/zh/blog/boj7490/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj7490/</guid><description>用 Python 解决 BOJ 7490 &quot;归零 &quot;问题</description><pubDate>Mon, 24 Apr 2023 16:15:36 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp1@@&quot;&gt;boj 7490&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;回溯, 强制算法, 实现, 字符串&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;我认为这是一个典型的反向追踪问题。不过，我发现处理过程有点深奥，ASCII 排序有点不寻常。&lt;/p&gt;
&lt;p&gt;我看到可以用 Python 的 Eval 函数轻松解决这个问题，但我没有用它，而是用了一种困难的方法。&lt;/p&gt;
&lt;p&gt;基本上，我取了一个数字和两个之前未处理的数字之和，然后进行回溯，以为它会检查 &amp;quot;加法&amp;quot;、&amp;quot;减法 &amp;quot;和 &amp;quot;无操作 &amp;quot;这三种情况，结果我得到了正确答案。&lt;/p&gt;
&lt;h4&gt;已解决代码。&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 0 만들기&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;make_sum_zero&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;
    result_arr: &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;,
    target_arr: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;,
    last_index: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;,
    now_index: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
    sum_now: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
    now_calc: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
    log=[],
&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
    백트래킹을 활용하여 숫자들의 합이 0이 되도록 만드는 함수
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; last_index == now_index:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; sum_now + now_calc:
            result_arr.add(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;.join(log))

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; now_index:
            make_sum_zero(
                result_arr,
                target_arr,
                last_index,
                now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
                target_arr[now_index],
                [&lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(target_arr[now_index])],
            )

        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
            new_number = target_arr[now_index]

            make_sum_zero(
                result_arr,
                target_arr,
                last_index,
                now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                sum_now + now_calc,
                new_number,
                log + [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;+&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(new_number)],
            )
            make_sum_zero(
                result_arr,
                target_arr,
                last_index,
                now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                sum_now + now_calc,
                -new_number,
                log + [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;-&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(new_number)],
            )

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_calc &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;:
                make_sum_zero(
                    result_arr,
                    target_arr,
                    last_index,
                    now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                    sum_now,
                    &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; * now_calc - new_number,
                    log + [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(new_number)],
                )
            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
                make_sum_zero(
                    result_arr,
                    target_arr,
                    last_index,
                    now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                    sum_now,
                    &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; * now_calc + new_number,
                    log + [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(new_number)],
                )

testcase = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
output = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(testcase):
    arr_length = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
    result = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;()

    &lt;span class=&quot;hljs-comment&quot;&gt;# 함수를 통해 결과 확인&lt;/span&gt;
    target_arr = [i &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, arr_length + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]
    make_sum_zero(result, target_arr, arr_length)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 혹여라도 겹치는 결과가 있다면 Set을 통해 배제, ASCII 순으로 정렬&lt;/span&gt;
    sort_result = &lt;span class=&quot;hljs-built_in&quot;&gt;sorted&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(result), key=&lt;span class=&quot;hljs-keyword&quot;&gt;lambda&lt;/span&gt; x: &lt;span class=&quot;hljs-built_in&quot;&gt;ascii&lt;/span&gt;(x))
    output.append(sort_result)

&lt;span class=&quot;hljs-comment&quot;&gt;# 문제 조건에 맞춰 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(testcase):
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; element_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(output[idx])):
        &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(output[idx][element_idx])

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; idx != testcase - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[1Day-1CS] TCP/IP 四层模型与应用层</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-tcp-ip-4/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-tcp-ip-4/</guid><description>每日一CS：关于TCP/IP四层模型及应用层的简要总结</description><pubDate>Mon, 24 Apr 2023 15:18:37 GMT</pubDate><content:encoded>&lt;h3&gt;互联网协议套件 (Internet Protocol Suite)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;互联网中计算机之间用于交换信息的协议集合&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;可用TCP/IP四层模型或OSI七层模型进行说明&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TCP/IP四层&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;根据网络范围，由四个抽象层组成&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;应用层&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输层&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;互联网层&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;链路层&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OSI模型的特点是将应用层和链路层进一步细分&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;应用层&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;应用FTP、HTTP、SSH、SMTP、DNS等应用程序的协议层&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;FTP：设备间的文件传输&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SSH：安全外壳协议（Secure Shell Protocol），一种加密网络协议&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HTTP：通过万维网（World Wide Web）访问网站所使用的协议&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SMTP：用于电子邮件传输的互联网标准通信协议&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DNS：负责将域名与IP地址进行映射的服务器&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实际上是向用户提供服务的层&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[BOJ 25542, Python] 约会地点</title><link>https://www.traceoflight.dev/zh/blog/boj25542/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj25542/</guid><description>BOJ 25542，“约会地点”问题的 Python 解法</description><pubDate>Sun, 23 Apr 2023 18:10:04 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;[BOJ 25542](&lt;a href=&quot;https://www.acmicpc.net/problem/25542&quot;&gt;https://www.acmicpc.net/problem/25542&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;)&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;暴力搜索算法、实现、字符串&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;最初在比赛中遇到这道题时，我以为思路本身并不难。但这道题的实现比想象中要费工夫，而且7个月前的我连写Python代码都觉得非常吃力，因此没能解出这道题。&lt;/p&gt;
&lt;p&gt;3个月前的我也曾试图解决这道题，但最终得出结论：构思的思路还需要额外的剪枝，结果再次受挫，只能暂时搁置这道题。&lt;/p&gt;
&lt;p&gt;最近有了些空闲，加上想重新挑战之前没解出的题目，于是再次尝试，终于解出来了！不过，我仍然对这道题被归类为银牌题感到疑惑……&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-90c53486a9b70423-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;起初，我尝试仅使用已有的字符串来输出结果，但这显然存在反例，因此以失败告终。&lt;/p&gt;
&lt;p&gt;之后尝试的代码虽然在实现上稍作改进，但依然只使用了已知的字符串，因此无法解决使用其他字符串的反例。附上代码如下。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; itertools &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; product

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;is_similar&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;checker: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;, target: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;:
	&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    두 문자열이 비슷한지 확인하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;
    
    length = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(checker)
    counter = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(length):

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; checker[idx] != target[idx]:
            counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; counter &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;
    
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 입력&lt;/span&gt;
store_number, name_length = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

&lt;span class=&quot;hljs-comment&quot;&gt;# 각 문자열의 동일 인덱스를 집합화&lt;/span&gt;
name_list = []
store_chr_arr = [&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;() &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(name_length)]

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(store_number):
    each_name = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
    name_list.append(each_name)

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(name_length):
        store_chr_arr[idx].add(each_name[idx])

result = &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 겹치지 않는 문자열의 Product를 비교&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_name_combination &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; product(*store_chr_arr):
    target_name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.join(each_name_combination)
    
    is_answer = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; check_name &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; name_list:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; is_similar(target_name, check_name):
            is_answer = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; is_answer:
        result = target_name
        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;CALL FRIEND&amp;#x27;&lt;/span&gt;)

&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;虽然起初曾尝试使用未使用的字符，但因实现能力不足未能付诸实践，但通过该方法最终获得了“正解”判定。&lt;/p&gt;
&lt;h3&gt;解法代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 약속 장소&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;is_similar&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;checker: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;, target: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    두 문자열이 비슷한지 확인하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    length = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(checker)
    counter = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(length):

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; checker[idx] != target[idx]:
            counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; counter &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 정보 입력&lt;/span&gt;
store_number, name_length = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

name_list = []
first_checker = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 첫 문자열만 따로 분류하고 나머지는 이름 리스트에 기록&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(store_number):
    each_name = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().rstrip(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\n&amp;#x27;&lt;/span&gt;))

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; first_checker:
        target_name = each_name
        first_checker = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        name_list.append(each_name)

&lt;span class=&quot;hljs-comment&quot;&gt;# 첫 문자열을 통해 문자열 변형된 후보를 양산&lt;/span&gt;
result_set = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;()

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(name_length):
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; alpha &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;65&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;91&lt;/span&gt;):
        temp = target_name[:]
        temp[idx] = &lt;span class=&quot;hljs-built_in&quot;&gt;chr&lt;/span&gt;(alpha)
        result_set.add(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.join(temp))

&lt;span class=&quot;hljs-comment&quot;&gt;# 확인하면서 후보를 소거&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; result_set &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; name_list:

    now_check_name = name_list.pop()
    remove_target = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;()

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_result &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; result_set:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; is_similar(now_check_name, each_result):
            remove_target.add(each_result)

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_target &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; remove_target:
        result_set.remove(each_target)

&lt;span class=&quot;hljs-comment&quot;&gt;# 후보가 안 남았다면 문구를 출력, 후보가 남았다면 후보 중 하나를 출력한다.&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; result_set:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;CALL FRIEND&amp;#x27;&lt;/span&gt;)

&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result_set.pop())
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[1 天-1CS]瓶颈、分类和网络分析</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-26405cdf/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-26405cdf/</guid><description>1 天 1CS，快速回顾瓶颈和网络的分类与分析</description><pubDate>Sun, 23 Apr 2023 13:06:14 GMT</pubDate><content:encoded>&lt;h3&gt;瓶颈&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;整个系统的性能或容量受到一个组件的限制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在服务器上打开事件时，由于流量大且管理不善而造成&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;需要有关网络拓扑结构的信息，以正确排除瓶颈故障。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;瓶颈的主要原因&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;网络带宽&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络拓扑结构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务器 CPU、内存使用情况&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络配置效率低下&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;网络分类&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;网络根据规模分类&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;局域网&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;局域网&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输速度快且不受干扰&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;城域网&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;城域网&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输速度一般，比局域网更拥挤&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;广域网（WAN）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;广域网&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输速度较慢，比城域网更拥挤&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;网络性能分析命令&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ping&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向要检查其状态的目标节点发送一定大小的数据包&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;netstat&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;显示连接服务的网络状态&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;netstat * 显示网络连接、路由表、网络协议等列表。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nslookup&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用于查找 DNS 相关内容&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nslookup * 用于查看哪些 IP 映射到特定域&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tracert （跟踪路由）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用于验证到目标节点的网络路由&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可用于查看响应时间变慢的位置等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;还有许多其他命令，可使用 wireshark、netmon 等程序。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1天-1CS] 网络拓扑结构</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-21436c11/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-21436c11/</guid><description>1 天 1CS，快速复习网络拓扑模式</description><pubDate>Thu, 20 Apr 2023 12:56:24 GMT</pubDate><content:encoded>&lt;h4&gt;网络拓扑结构&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;节点和链接的排列方式以及连接方式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;树状拓扑&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;分层拓扑结构，即以树形布局的网络组织。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;易于添加和删除节点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;流量集中在某个节点上会影响子节点&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;总线拓扑&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;将多个节点连接到一条中央通信线路上&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用于局域网&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装成本低，可靠性高，易于在中央通信线路上添加和删除节点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存在欺骗问题&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;欺骗：
在LAN上&lt;strong&gt;向未参与传输的另一台主机&lt;/strong&gt;。
&lt;strong&gt;瘫痪或欺骗交换机，使其无法将数据包发送到指定节点&lt;/strong&gt;。
&lt;strong&gt;将数据包当作来自特定节点的数据包&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;星形拓扑&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;每个人都连接到中心节点的网络配置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;易于添加节点或检测错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据包不易碰撞&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;中央节点故障时整个网络不可用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装成本高&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;环形拓扑&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;在节点之间移动数据，通过环形路径处理数据包&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;随着节点数量的增加，网络损耗很小&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不易崩溃，更容易发现节点故障&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;难以更改网络配置&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;故障会影响整个网络&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;网状拓扑&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;网状拓扑，一种网状连接结构&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;存在多条路径，因此即使一个终端出现故障，网络仍可使用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;流量可以分配&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;难以增加节点，建设和运营成本高昂&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 网络启动、吞吐量和延迟</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-4b2e3588/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-4b2e3588/</guid><description>每天 1CS，吞吐量和延迟的简要说明</description><pubDate>Mon, 17 Apr 2023 14:32:41 GMT</pubDate><content:encoded>&lt;h4&gt;简介&lt;/h4&gt;
&lt;p&gt;现在是自助书籍的季节，我觉得自己最近太忙了，但我认为继续学习是有帮助的，所以我要尽力而为！&lt;/p&gt;
&lt;h3&gt;网络&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;一组只相互连接或共享连接和资源的节点和链接。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;节点：服务器、路由器、交换机等设备。
链接： 无线或有线&lt;/p&gt;
&lt;h4&gt;吞吐量和延迟&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;吞吐量和延迟 &amp;gt; 吞吐量大、延迟低、故障少、安全性好的网络。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;吞吐量：链路中成功传递的数据量。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;流量：任何给定时间内链路中流动的数据量。
→ 更多流量 = 更多数据流。
→ 更多吞吐量 = 处理更多流量。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;吞吐量受流量、带宽、网络引起的错误和设备规格的影响&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;延迟：处理请求所需的时间，以往返次数衡量。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;延迟受介质类型、数据包大小和路由器数据包处理时间的影响。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[1Day-1CS]设计模式与范例简述</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-5e78c961/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-5e78c961/</guid><description>1 天 1 全面复习 CS、设计模式和编程范例</description><pubDate>Mon, 10 Apr 2023 16:56:14 GMT</pubDate><content:encoded>&lt;h4&gt;简介&lt;/h4&gt;
&lt;p&gt;我现在写的所有东西都是基于《CS 专业面试知识笔记》。其实，我觉得我应该在第一天 CS 的开头就提到它，但我现在还是要写。&lt;/p&gt;
&lt;h3&gt;设计模式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过对象之间的相互关系等来解决在设计程序时出现的问题的约定。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;单例模式：1 类 1 实例/依赖注入器，解决模块耦合问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;工厂模式：父类提供框架，子类通过继承来完善框架。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;策略模式：使用封装算法，并在上下文中进行交换&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;观察者模式：观察状态变化，并通过方法等传达变化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;代理模式：作为接口，在访问目标对象前拦截流程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;迭代器模式：使用迭代器访问集合中的元素，允许通过单个接口进行遍历。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ExposureModule 模式：创建一个访问控制器。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;MVC 模式：由模型、视图和控制器组成，允许以分隔的方式开发应用程序的各个组件。&lt;/p&gt;
&lt;p&gt;MVP 模式：用演示器取代控制器。&lt;/p&gt;
&lt;p&gt;MVVM 模式：仅用视图模型代替控制器&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;编程范式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;声明式与命令式
→ 什么是声明式，什么是命令式？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;声明式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;函数式编程：堆叠纯函数来实现逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;命令式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;面向对象编程：表达对象之间的交互，利用对象方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;面向过程的程序设计：包括连续计算，通过逐字执行代码来实现&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 过程式编程与范式的混合</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-fbf17eb9/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-fbf17eb9/</guid><description>“每日一CS”、过程式编程、关于编程范式选择的简要总结</description><pubDate>Sat, 08 Apr 2023 15:32:23 GMT</pubDate><content:encoded>&lt;h3&gt;过程式编程&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;由需要执行的连续计算过程构成&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代码按照流程顺序实现，因此可读性好且运行速度快&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存在难以模块化、可维护性较低的缺点&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;编程范式的选择&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;编程范式之间并不存在绝对的优劣之分&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应根据服务特性或业务逻辑选择合适的编程范式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;根据具体逻辑进行灵活选择也是可行的&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 面向对象编程的设计原则</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-oop/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-oop/</guid><description>每日一CS：关于面向对象编程设计原则的简要总结</description><pubDate>Thu, 06 Apr 2023 12:27:00 GMT</pubDate><content:encoded>&lt;h3&gt;单一职责原则&lt;/h3&gt;
&lt;p&gt;Single Responsibility Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;每个类都应只承担一项职责。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;开闭原则&lt;/h3&gt;
&lt;p&gt;Open Closed Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在维护时，应尽量减少对现有代码的修改，并确保代码易于扩展。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;里斯科夫替换原则&lt;/h3&gt;
&lt;p&gt;Liskov Substitution Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对象应能够被替换为其子类型的实例，且不破坏程序的正确性。这意味着继承机制必须能够正常运作，确保没有问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;接口隔离原则&lt;/h3&gt;
&lt;p&gt;Interface Segregation Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;应创建多个具体的接口，而非一个通用的接口&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;依赖倒置原则&lt;/h3&gt;
&lt;p&gt;Dependency Inversion Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;上层应独立于下层的变更，应使用上层类或抽象接口，以避免受到比自身更易变的事物的影响。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>三星软件能力评估 B 类审查</title><link>https://www.traceoflight.dev/zh/blog/samsung-software-competency-evaluation-type-b/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/samsung-software-competency-evaluation-type-b/</guid><description>参加三次三星软件能力评估，并写下你的失败经历。</description><pubDate>Thu, 06 Apr 2023 12:08:47 GMT</pubDate><content:encoded>&lt;h4&gt;简介&lt;/h4&gt;
&lt;p&gt;我先说结论：迄今为止，我错过了三次机会中的两次。因此，我想给大家留下一些关于如何在未来取得成功的建议。&lt;/p&gt;
&lt;h3&gt;资质&lt;/h3&gt;
&lt;p&gt;我参加了三星青年软件学院的模拟能力评估，获得了 A 级资格。&lt;/p&gt;
&lt;h3&gt;回顾&lt;/h3&gt;
&lt;p&gt;过去，我觉得自己不仅在实现方面花了太多时间，在优化方面也有所欠缺。我还有一次考试机会，我想我应该多学习优化方面的知识。&lt;/p&gt;
&lt;h4&gt;1. 对象使用不佳&lt;/h4&gt;
&lt;p&gt;也许是因为我来自 Python 的缘故，我不习惯用对象来编码，我也尝试着掌握了很多，但还是觉得自己不够好。特别是，我发现很难覆盖和使用 Comparator 等部分...&lt;/p&gt;
&lt;h4&gt;2. 熟悉数据结构&lt;/h4&gt;
&lt;p&gt;如果你听 B 类通过者的故事，他们非常强调材料结构，但如果你问我是否已经掌握了足够的材料结构，我认为在最终测试之前我仍然需要有足够的时间来复习。&lt;/p&gt;
&lt;h3&gt;+ 更多&lt;/h3&gt;
&lt;p&gt;四月底标志着我为期三个月的 B 型旅程的结束。结果，我没有拿到 B 类资格证书，我很失望，因为我离最后一题很近，却没能迈出最后一步。&lt;/p&gt;
&lt;p&gt;但我努力了，所以我尝试了，我很高兴我做到了，而且我能够取得一些进展。&lt;/p&gt;
&lt;p&gt;在参加企业工作的编码测试时，这绝对是一个优势。&lt;/p&gt;
&lt;p&gt;我现在取得的资格可能是临时 A 级，所以 SSAFY 之后我就没有机会再考 B 级了，但能再考一次也不错！&lt;/p&gt;
</content:encoded></item><item><title>[1天-1CS]执行程序设计与面向对象程序设计</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-cdddda5a/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-cdddda5a/</guid><description>第 1 天 1CS，快速回顾命令式编程和面向对象编程</description><pubDate>Fri, 31 Mar 2023 11:39:05 GMT</pubDate><content:encoded>&lt;h4&gt;命令式编程的类型&lt;/h4&gt;
&lt;h4&gt;面向对象编程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;将程序的交互作用表示为对象集合，并在对象内部声明方法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设计需要大量时间，比其他编程范式慢。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;面向对象编程的特点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;抽象：从复杂系统中提炼出关键概念、特征和功能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;封装：将对象的属性和方法捆绑在一起，并对外界隐藏其中的一些属性和方法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;继承：允许子类继承父类的特征，使其可以重复使用、添加和扩展。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多态性：一个方法或类可以有多种不同的行为方式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重载：拥有多个同名方法；在 &amp;quot;编译 &amp;quot;过程中出现的 &amp;quot;静态 &amp;quot;多态性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重载：重载：子类重载从父类继承的方法，&amp;quot;动态 &amp;quot;多态性发生在 &amp;quot;运行时&amp;quot;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1天-1CS]声明式编程</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-dbfa4ad8/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-dbfa4ad8/</guid><description>1 天 1CS，快速复习声明式编程</description><pubDate>Fri, 31 Mar 2023 11:36:56 GMT</pubDate><content:encoded>&lt;h3&gt;编程范式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;让程序员获得编程视角的开发方法论&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;声明式 vs 命令式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;声明式: 关注解决什么的范式 (What)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;命令式: 关注如何解决的范式 (How)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;例)
声明式: 家的地址 (准确指定位置)
命令式: 到家的路线 (提示如何到达位置的方法)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;声明式编程的种类&lt;/h3&gt;
&lt;h4&gt;函数式编程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;把小的纯函数像积木一样叠起来构建逻辑、通过实现高阶函数提升复用性的编程范式&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;纯函数: 输出仅依赖于输入的函数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;高阶函数: 把函数作为值通过参数接收并构建逻辑的函数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果语言支持一级对象 (First Class Object) 就可以使用高阶函数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一级对象的特征&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可以把函数赋值给变量或方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以把函数作为参数嵌入到函数中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;函数可以返回函数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[1天-1CS] MVC 模式和类似模式</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-mvc/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-mvc/</guid><description>1CS 在 1 天内，快速回顾 MVC 模式</description><pubDate>Thu, 30 Mar 2023 16:36:43 GMT</pubDate><content:encoded>&lt;h3&gt;MVC 模式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;由模型、视图、控制器组成的设计模式&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;将应用程序的组件分为三部分，使您可以专注于每个组件并分别进行开发&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;促进可重用性和确定性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缺点是随着应用程序复杂性的增加，模型和视图之间的关系也会变得更加复杂&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;模型&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;应用程序中的数据，指数据库、常量、变量等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;视图&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;指用户界面元素，即用户根据模型可以看到的屏幕。&lt;/p&gt;
&lt;p&gt;不存储模型的任何信息，只存储屏幕显示信息&lt;/p&gt;
&lt;p&gt;发生变化时，将变化传递给控制器。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;控制器&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;充当模型和视图之间的桥梁&lt;/p&gt;
&lt;p&gt;负责事件等主要逻辑，并管理生命周期&lt;/p&gt;
&lt;p&gt;当模型或视图发生变化时，它会向所需组件发送相应的内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;类似模式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;MVP 模式：用演示器代替控制器，由于视图和演示器之间的关系是 1:1，因此耦合度更高&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MVVM 模式：用视图模型取代控制器，具有命令和数据绑定功能，实现了用户界面的可重用性，并简化了单元测试&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 代理模式、迭代器模式和暴露模块模式</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-c6863ddc/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-c6863ddc/</guid><description>简要回顾 1CS、代理模式、迭代器模式和曝光模块模式</description><pubDate>Tue, 28 Mar 2023 23:30:10 GMT</pubDate><content:encoded>&lt;h4&gt;代理模式&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一种设计模式，在访问目标对象之前，通过拦截目标对象的流程，在目标对象前充当接口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用于安全、数据验证、缓存、日志记录，以及作为服务器而非对象使用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;代理服务器&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在服务器和客户端之间工作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;允许客户通过它间接访问其他网络服务的系统或程序。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;例如 Apache、Nginx、CloudFlare 等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;代理服务器使用示例&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;通过代理，可以隐藏实际使用的端口&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以通过 Nginx 压缩静态资源，或登录到主服务器的前端&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CloudFlare 可轻松部署 HTTPS 并抵御 DDOS 攻击&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;前端代理服务器可用于防止跨源资源共享（CORS）错误&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;迭代器模式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;通过迭代器访问集合元素的设计模式&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;无论数据类型的结构如何，都可以通过一个接口：迭代器来遍历它们。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通常情况下，可迭代对象可以通过迭代器协议进行遍历&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;公开模块模式&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;通过立即执行函数创建访问控制器（如 private 和 public）的模式&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;在 JS 的情况下，没有单独的访问控制器，因此也可以通过执行来建立访问控制器&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 工厂模式 &amp;amp; 策略模式 &amp;amp; 观察者模式</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs-f886ff08/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs-f886ff08/</guid><description>每日一CS：工厂模式、策略模式、观察者模式的简要总结</description><pubDate>Mon, 27 Mar 2023 22:36:03 GMT</pubDate><content:encoded>&lt;h3&gt;工厂模式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一种将对象创建部分从使用对象的代码中抽象出来的模式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;父类决定重要的框架结构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子类决定对象创建的具体细节&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;工厂模式的特点与优点&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;通过类分离实现松耦合
确保父类的灵活性并提高可维护性&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;策略模式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;若不想改变对象的行为，则不直接修改&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过在上下文中更换作为策略的&lt;strong&gt;封装算法&lt;/strong&gt;，使其设计为可替换&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;上下文&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;指开发人员完成某项工作所需的相关信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存在为使某种行为发生而必不可少的必要上下文，以及为有效执行该行为而存在的可选上下文。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;观察者模式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;主体观察特定对象的状态变化&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;状态发生变化时，通过方法等方式向观察者提供变化信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有时不将主体与对象分离，而是基于可变对象进行构建&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;该模式也应用于 MVC 模式中&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1天-1CS] 单件模式</title><link>https://www.traceoflight.dev/zh/blog/1day-1cs/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/1day-1cs/</guid><description>1CS 单例模式一天快速回顾</description><pubDate>Mon, 27 Mar 2023 15:29:32 GMT</pubDate><content:encoded>&lt;h3&gt;什么是设计模式？&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;设计程序时遇到问题&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;→ 利用对象之间的相互关系等创建一个约定来解决它。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;h3&gt;单例模式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一个类 = 一个实例&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;我们可以为每个类创建多个独立的实例，但我们不会这样做，我们只使用一个实例&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通常用于 DB 模块&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;生产力 ↑，依赖性 ↓&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;单例模式的缺点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在 TDD（测试驱动开发）过程中进行单元测试时可能出现问题&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;由于单例模式的高度依赖性，很难为每个测试创建一个独立实例&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;依赖注入&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;解决单例模式模块间耦合性强的缺点的一种方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;主模块不直接向其他子模块提供依赖关系，而是通过&lt;strong&gt;依赖关系注入器&lt;/strong&gt;（解耦）间接注入依赖关系。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;优点&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;更容易替换模块、更容易测试和迁移、依赖关系方向一致、更容易推理应用程序、关系清晰等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;缺点&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;模块的解耦程度更高 → 由于类的数量增加，运行时的惩罚增加了复杂性&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;依赖注入原则&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;父模块不从子模块导入任何内容&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;两者都必须依赖抽象 + 抽象不依赖细节&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[CI/CD] 基于 Docker + Jenkins + Git Webhook 的 FastAPI 服务器自动部署总结</title><link>https://www.traceoflight.dev/zh/blog/cicd-docker-jenkins-git-webhook/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/cicd-docker-jenkins-git-webhook/</guid><description>实现实战中的压缩与自动部署</description><pubDate>Fri, 24 Mar 2023 02:08:12 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;内容整理中 &amp;gt; 截至 2023 年 5 月、第 1 次更新完成
&lt;a href=&quot;/blog/ci-cd-dood-feat-nginx-jenkins&quot;&gt;关于部署的内容，建议参考整理得更好的第 2 篇。&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;序言&lt;/h3&gt;
&lt;p&gt;在当前进行的项目中，我正在构建一个利用 AI 模型提供输出的服务。&lt;/p&gt;
&lt;p&gt;我原本想用 Firebase Cloud Function 来构建这一功能，但加载模型时由于使用 nodeJS + tensorflow.js 不得不转换模型，且其本身就比较重，导致不断超时等，被各种方式卡住，于是决定构建一个简单的服务器来返回 AI 模型的结果。&lt;/p&gt;
&lt;p&gt;因此服务器的构建与部署便落到我身上，第一阶段目标是实现自动部署，之后的追加目标是用自己的手实现零停机部署。&lt;/p&gt;
&lt;p&gt;本文仅涉及基于 AWS 等实例构建系统并实现自动部署为止的内容。&lt;/p&gt;
&lt;h3&gt;前置概念学习&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;CI: Continuous Integration (持续集成)&lt;/p&gt;
&lt;p&gt;这是面向开发者的自动化流程，代码变更经过构建和测试后定期合并到共享仓库的过程，把这个过程自动化能够减少开发过程中的风险，因此被广泛采用&lt;/p&gt;
&lt;p&gt;由 CI Server, Source Control Management, Build Tool, Test Tool 等组成&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;CD: Continuous Delivery / Deployment (持续交付 / 持续部署)&lt;/p&gt;
&lt;p&gt;指部署自动化流程，通过对管线后续阶段的自动化，变更可以无须人工干预自动部署到 product。需要持续集成的支撑，构建可信赖的环境后甚至每天都能进行多次发布&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由此可见，通过这种 CI/CD 过程，可以缩短产品上市的时间、提升人力效率，且都是渐进而持续的过程，因此能够降低出现重大问题的概率。&lt;/p&gt;
&lt;h3&gt;Docker 环境配置&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;实例信息&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;没有使用 EC2 免费层，而是选择条件相对更好的 Oracle Cloud 免费层
分配并使用基于 arm64 的 Ampere A1 Compute 2 核与 12GB RAM&lt;/p&gt;
&lt;p&gt;此外它也免费提供一定程度的备份等选项，可以参考！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Linux 配置
&lt;a href=&quot;https://bgpark.tistory.com/85&quot;&gt;使用 password 连接 EC2 的方法&lt;/a&gt; - 介绍 ssh 配置以提升登录便利性的文章
&lt;a href=&quot;https://docs.docker.com/engine/install/ubuntu/&quot;&gt;Docker 安装&lt;/a&gt; - 基于 Ubuntu 的 Docker 安装官方 DOCS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我整理了自己参考过的资料，关于 Docker 安装过程和实例配置的文章很多，可以一边查阅一边配置 Docker。&lt;/p&gt;
&lt;h3&gt;Docker in Docker 配置 (失败 &amp;gt; 改用通过 API 的 Docker out of Docker 进行)&lt;/h3&gt;
&lt;h4&gt;使用理由&lt;/h4&gt;
&lt;p&gt;在 Docker 之上再操作 Docker 的理由是为了通过容器来控制容器，从而让该容器拥有非常强的权限，虽然会带来安全风险，但本身仍然很有吸引力。&lt;/p&gt;
&lt;h4&gt;曾尝试的配置方法&lt;/h4&gt;
&lt;h5&gt;1. 在 Docker 上构建 Jenkins 容器&lt;/h5&gt;
&lt;p&gt;首先在 Docker 中构建 Jenkins 容器。
使用 Docker Compose 可以更轻松地构建，可以参考。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker pull jenkins/jenkins:lts

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首先拉取 Jenkins LTS 版本的容器。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;vim docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过此命令创建或打开 yml 文件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2.5.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 输入 compose 版本&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;services:&lt;/span&gt;

  &lt;span class=&quot;hljs-attr&quot;&gt;jenkins:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins/jenkins:lts&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 使用 Jenkins LTS 版本&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 自动重启选项&lt;/span&gt;

    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;8181:8080&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 把 host 的 8181 端口映射到 Jenkins 的 8080 端口&lt;/span&gt;

    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 通过此选项可以共享 host 的 volume&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/home/opendocs/jenkins:/var/jenkins_home&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;

    &lt;span class=&quot;hljs-attr&quot;&gt;user:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;privileged:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 实现 Docker In Docker 的关键选项&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按示例代码所示在 yml 文件中写入所需内容。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker-compose -f {文件名} up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过此命令可以基于 docker-compose.yml 进行配置；若沿用 docker-compose.yml 作为文件名，则无需 -f 选项。具体内容请参考 Docker Compose Docs！&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose Documents&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;+ 不使用 sudo 操作 docker 的方法 → 把当前用户加入 Docker 组&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 通过此命令把当前用户加入 Docker 组&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; usermod -aG docker &lt;span class=&quot;hljs-variable&quot;&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2. Jenkins Container 配置&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;通过浏览器访问已配置 IP 上 Docker 分配的 Port Number&lt;/li&gt;
&lt;li&gt;把 Jenkins 安装日志中的 key 输入到页面中&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 通过此命令可以查看容器日志&lt;/span&gt;
docker logs jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;安装推荐插件&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可能会出现问题，但先把安装收尾，再处理后续问题。
不收尾的话，未安装插件造成的依赖错误会持续出现…&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wingsh.tistory.com/261&quot;&gt;插件安装 Time Out 解决方法&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;安装 GitHub API Plugin&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这是协助 Webhook 触发器工作的插件。安装吧。安装后把 Git ID/PW 注册为 Secret。&lt;/p&gt;
&lt;h5&gt;3. Github 配置&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在 Settings 的 Developer Settings 中创建 Token。截至撰写本文，使用 Classic token，权限只需 repo, admin:repo_hook 即可。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在自动部署 Repo 的设置中向 Webhooks 添加 Webhook。大致设置为 http://{jenkins_url}/github-webhook/ 即可。去掉最后的 / 可能会有问题，老实地保留它吧。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;4. Jenkins 项目配置&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;添加项目。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;构建配置 - 在源代码管理选 Git 并选择已经注册的 Secret，就可以接收 webhook 信号。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必须选择 GitHub hook trigger for GITScm polling 选项，触发器才会工作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;视情况进行分支选定后完成配置并进行测试。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>[BOJ 4803, Java] 树</title><link>https://www.traceoflight.dev/zh/blog/boj4803/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj4803/</guid><description>BOJ 4803，“树”题的 Java 解法</description><pubDate>Tue, 28 Feb 2023 00:26:49 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;[BOJ 4803](&lt;a href=&quot;https://www.acmicpc.net/problem/4803&quot;&gt;https://www.acmicpc.net/problem/4803&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;)&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;数据结构(data_structures)、深度优先搜索(dfs)、不相交集合(disjoint_set)、图论(graphs)、图遍历(graph_traversal)、树(trees)&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;这是一道利用树的性质来统计树的数量的问题。本题可以通过排除由连接元素构成的结构中的环来解决。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检查所有节点是否已被访问&lt;/li&gt;
&lt;li&gt;对于未访问的节点，将其纳入树中并进行深度遍历&lt;/li&gt;
&lt;li&gt;若形成环，则将构成该环的所有节点标记为已访问&lt;/li&gt;
&lt;li&gt;若未形成环，则该集合为树，计数为1&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过上述逻辑进行了实现，在思考如何在深度遍历过程中进行计数处理后，最终编写了如下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;dfs&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nowNode, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; parent, &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt;[] visitLog, HashMap&amp;lt;Integer, ArrayList&amp;lt;Integer&amp;gt;&amp;gt; graph)&lt;/span&gt; {

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nextNode : graph.get(nowNode)) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextNode != parent &amp;amp;&amp;amp; !visitLog[nextNode]) {

                visitLog[nextNode] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;

                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; dfs(nextNode, nowNode, visitLog, graph);
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (result == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
                }

            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextNode != parent &amp;amp;&amp;amp; visitLog[nextNode]) {
                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
            }

        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

    }

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该代码从起始点开始以递归形式进行访问和检查，当出现环时，默认遍历所有节点后返回0。&lt;/p&gt;
&lt;p&gt;如果未出现环路，则正常结束遍历并返回1，通过持续累加该函数的返回值，即可得知树的数量！&lt;/p&gt;
&lt;h3&gt;解法代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;dfs&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nowNode, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; parent, &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt;[] visitLog, HashMap&amp;lt;Integer, ArrayList&amp;lt;Integer&amp;gt;&amp;gt; graph)&lt;/span&gt; {

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nextNode : graph.get(nowNode)) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextNode != parent &amp;amp;&amp;amp; !visitLog[nextNode]) {

                visitLog[nextNode] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;

                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; dfs(nextNode, nowNode, visitLog, graph);
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (result == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
                }

            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextNode != parent &amp;amp;&amp;amp; visitLog[nextNode]) {
                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
            }

        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;testCase&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

        ArrayList&amp;lt;String&amp;gt; outputArr = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ArrayList&lt;/span&gt;&amp;lt;&amp;gt;();

        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;) {

            &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;treeInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nodeNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(treeInfo.nextToken());
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;edgeNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(treeInfo.nextToken());

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nodeNumber == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; edgeNumber == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
            }

            testCase += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;treeCount&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
            &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt;[] isVisited = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;boolean&lt;/span&gt;[nodeNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;];

            &lt;span class=&quot;hljs-type&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;stringBuilder&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringBuilder&lt;/span&gt;();
            stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Case &amp;quot;&lt;/span&gt;);
            stringBuilder.append(testCase);
            stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;);

            HashMap&amp;lt;Integer, ArrayList&amp;lt;Integer&amp;gt;&amp;gt; treeGraph = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashMap&lt;/span&gt;&amp;lt;&amp;gt;();
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt; nodeNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++) {
                treeGraph.put(i, &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ArrayList&lt;/span&gt;&amp;lt;&amp;gt;());
            }

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; edgeNumber; i++) {

                &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;edgeInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;startNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(edgeInfo.nextToken());
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;endNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(edgeInfo.nextToken());

                treeGraph.get(startNode).add(endNode);
                treeGraph.get(endNode).add(startNode);

            }

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt; nodeNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++) {

                isVisited[i] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
                treeCount += dfs(i, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, isVisited, treeGraph);
            }

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (treeCount == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;No trees.&amp;quot;&lt;/span&gt;);
            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (treeCount == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;There is one tree.&amp;quot;&lt;/span&gt;);
            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (treeCount &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A forest of &amp;quot;&lt;/span&gt;);
                stringBuilder.append(treeCount);
                stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; trees.&amp;quot;&lt;/span&gt;);
            }

            outputArr.add(stringBuilder.toString());

        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; testCase; i++) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i != testCase - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                output.write(outputArr.get(i) + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;);
            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
                output.write(outputArr.get(i));
            }

        }

        output.flush();
        output.close();

    }

}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 1485, Python] 正方形</title><link>https://www.traceoflight.dev/zh/blog/boj1485/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj1485/</guid><description>BOJ 1485，“正方形”问题的 Python 解法</description><pubDate>Sat, 25 Feb 2023 03:05:13 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1485&quot;&gt;BOJ 1485&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;几何(geometry), 排序(sorting)&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;通过该流程即可判断是否为正方形。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检查连接4个点的6条边的长度&lt;/li&gt;
&lt;li&gt;排序&lt;/li&gt;
&lt;li&gt;检查前4条边的长度是否相同&lt;/li&gt;
&lt;li&gt;检查后2条边是否符合正方形的对角线长度&lt;/li&gt;
&lt;li&gt;仅当所有条件均满足时，才判定为可绘制正方形&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;解法代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 정사각형&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; math &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sqrt, isclose
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; itertools &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; combinations

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;distance&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;coord_1: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, coord_2: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; sqrt(&lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(coord_1[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] - coord_2[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) + &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(coord_1[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] - coord_2[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))

testcase = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())

output = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(testcase):

    is_square = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

    coord_info = []

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;):
        coord_info.append(&lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())))

    edge_info = []

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; edge_distance &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; combinations(coord_info, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;):
        edge_info.append(distance(edge_distance[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], edge_distance[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]))

    edge_info.sort()

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;):
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; isclose(edge_info[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], edge_info[idx]):
            is_square = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; is_square:
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;):
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; isclose(&lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(edge_info[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) * &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(edge_info[idx], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)):
                is_square = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; is_square:
        output.append(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        output.append(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; output:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 12850, Java]漫步主校园 2</title><link>https://www.traceoflight.dev/zh/blog/boj12850/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj12850/</guid><description>BOJ 12850，&quot;在大学周围散步 2 &quot;问题的 Java 解决方案</description><pubDate>Wed, 22 Feb 2023 14:05:40 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp1@@&quot;&gt;boj 12850&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;exponentiation_by_squaring, graph theory, maths, divide-and-conquer&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;h4&gt;除法与征服（Devide and Conquer）&lt;/h4&gt;
&lt;p&gt;一种通过将难以解决的问题分解成更小问题来解决的算法。&lt;/p&gt;
&lt;p&gt;这个问题可以通过绘制邻域矩阵来解决，并知道到达目的地的次数就是对邻域矩阵进行 n 次平方运算的次数。&lt;/p&gt;
&lt;p&gt;这确实需要学习一些分而治之和矩阵运算的知识，但我认为这是一个结合了几个较低层次问题的合理难度。&lt;/p&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; HashMap&amp;lt;Integer, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][]&amp;gt; matrixRecord = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashMap&lt;/span&gt;&amp;lt;&amp;gt;();

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] matrixCalculation(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] matrix1, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] matrix2) {
        &lt;span class=&quot;hljs-comment&quot;&gt;/* 행렬 연산 함수 */&lt;/span&gt;

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] resultArr = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;];

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;; i++) {
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;; j++) {

                &lt;span class=&quot;hljs-type&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; k &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;; k++) {
                    sum += ((&lt;span class=&quot;hljs-type&quot;&gt;long&lt;/span&gt;) matrix1[i][k] * (&lt;span class=&quot;hljs-type&quot;&gt;long&lt;/span&gt;) matrix2[k][j]) % &lt;span class=&quot;hljs-number&quot;&gt;1000000007&lt;/span&gt;;
                }

                resultArr[i][j] = (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) (sum % &lt;span class=&quot;hljs-number&quot;&gt;1000000007&lt;/span&gt;);

            }
        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; resultArr;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] matrixDivision(HashMap&amp;lt;Integer, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][]&amp;gt; matrixInfo, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; calculationCount) {
        &lt;span class=&quot;hljs-comment&quot;&gt;/* 분할 정복을 통한 행렬 연산 함수 */&lt;/span&gt;

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;halfCount&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; calculationCount / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;;

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] halfMatrix;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] otherHalfMatrix;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 기존 값이 존재할 경우 불러오기&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (matrixInfo.containsKey(halfCount)) {
            halfMatrix = matrixInfo.get(halfCount);
        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
            halfMatrix = matrixDivision(matrixInfo, halfCount);
        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (matrixInfo.containsKey(calculationCount - halfCount)) {
            otherHalfMatrix = matrixInfo.get(calculationCount - halfCount);
        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
            otherHalfMatrix = matrixDivision(matrixInfo, calculationCount - halfCount);
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 연산 후 행렬 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] calculationResult = matrixCalculation(halfMatrix, otherHalfMatrix);
        matrixInfo.putIfAbsent(calculationCount, calculationResult);

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; calculationResult;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;walkTime&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(input.readLine());

        &lt;span class=&quot;hljs-comment&quot;&gt;// 기본 행렬 및 본대 인접 행렬 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] baseMatrix = {
                {&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
        };

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] graph = {
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
        };

        &lt;span class=&quot;hljs-comment&quot;&gt;// 해시맵에 초기값들 등록&lt;/span&gt;
        matrixRecord.put(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, baseMatrix);
        matrixRecord.put(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, graph);

        &lt;span class=&quot;hljs-comment&quot;&gt;// 함수를 통해 분할정복 연산 실행&lt;/span&gt;
        matrixDivision(matrixRecord, walkTime);

        &lt;span class=&quot;hljs-comment&quot;&gt;// 결과 출력&lt;/span&gt;
        output.write(Integer.toString(matrixRecord.get(walkTime)[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]));

        output.flush();
        output.close();

    }

}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>重构 1 - 1.类型&quot;... &quot;不能分配给类型&quot;...&quot;</title><link>https://www.traceoflight.dev/zh/blog/refactoring-1-1/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/refactoring-1-1/</guid><description>类型&apos;string&apos;不可分配给类型&apos;&quot;text&quot; | &quot;outlined&quot; | &quot;contained&quot; | undefined&apos;&quot;。解决错误</description><pubDate>Tue, 21 Feb 2023 16:40:07 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-title class_&quot;&gt;Button&lt;/span&gt;
onClick={handleLogin}
variant=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;contained&amp;quot;&lt;/span&gt;
  &amp;gt;
    &lt;span class=&quot;hljs-variable constant_&quot;&gt;LOGIN&lt;/span&gt;
&amp;lt;/&lt;span class=&quot;hljs-title class_&quot;&gt;Button&lt;/span&gt;&amp;gt;
&lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;onClick&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{handleGoogleLogin}&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;img&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{logoSrc}&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;alt&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;alternative image&amp;quot;&lt;/span&gt;
/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;Social Login&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;Button&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;问题&lt;/h4&gt;
&lt;p&gt;在 TypeScript 中使用 map 重建此代码时，发生了错误。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Type &apos;string&apos; is not assignable to type &apos;&amp;quot;text&amp;quot; | &amp;quot;outlined&amp;quot; | &amp;quot;contained&amp;quot; | undefined&apos;&amp;quot;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我使用的是 MUI，它在 MUI 按钮的变体属性值中出现了错误。为了解决这个问题，我挣扎了一段时间，在通过 StackOverFlow 和 ChatGPT 进行大量搜索后，我终于找到了答案。&lt;/p&gt;
&lt;h4&gt;解决方案。&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Variant&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;outlined&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;contained&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-literal&quot;&gt;undefined&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;SubmitButtonProps&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ButtonProps&lt;/span&gt; {
  &lt;span class=&quot;hljs-attr&quot;&gt;variant&lt;/span&gt;?: &lt;span class=&quot;hljs-title class_&quot;&gt;Variant&lt;/span&gt;;
  &lt;span class=&quot;hljs-attr&quot;&gt;onClick&lt;/span&gt;?: &lt;span class=&quot;hljs-function&quot;&gt;() =&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Promise&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;void&lt;/span&gt;&amp;gt;;
  &lt;span class=&quot;hljs-attr&quot;&gt;contains&lt;/span&gt;?: &lt;span class=&quot;hljs-title class_&quot;&gt;React&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;ReactNode&lt;/span&gt;;
}

{loginButtonSettings.&lt;span class=&quot;hljs-title function_&quot;&gt;map&lt;/span&gt;(
  &lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;{ onClick, contains, variant }: &lt;span class=&quot;hljs-title class_&quot;&gt;SubmitButtonProps&lt;/span&gt;, &lt;span class=&quot;hljs-attr&quot;&gt;index&lt;/span&gt;: &lt;span class=&quot;hljs-built_in&quot;&gt;number&lt;/span&gt;&lt;/span&gt;) =&amp;gt;&lt;/span&gt; (
    &lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;SubmitButton&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;key&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{index}&lt;/span&gt;
  	&lt;span class=&quot;hljs-attr&quot;&gt;onClick&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{onClick}&lt;/span&gt;
	&lt;span class=&quot;hljs-attr&quot;&gt;contains&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{contains}&lt;/span&gt;
	&lt;span class=&quot;hljs-attr&quot;&gt;variant&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{variant}&lt;/span&gt;
	/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  )
)}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如上所示，我们需要通过 type 值为变量预先定义属性值，还需要将其附加到接口上。事实上，这一部分比我们下面要写的内容更重要。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; loginButtonSettings = [
  {
    &lt;span class=&quot;hljs-attr&quot;&gt;onClick&lt;/span&gt;: loginHandler,
    &lt;span class=&quot;hljs-attr&quot;&gt;contains&lt;/span&gt;: &lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;Login&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;hljs-attr&quot;&gt;variant&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;contained&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Variant&lt;/span&gt;, &lt;span class=&quot;hljs-comment&quot;&gt;// 바로 여기!&lt;/span&gt;
  },
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正如你所看到的，&amp;quot;contained（包含）&amp;quot;一般被识别为字符串，因此我们需要确保它是变量属性值中包含的值！&lt;/p&gt;
</content:encoded></item><item><title>进入重构</title><link>https://www.traceoflight.dev/zh/blog/refactoring/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/refactoring/</guid><description>回顾以及为什么要在重构之前使用 Stack</description><pubDate>Tue, 21 Feb 2023 16:26:20 GMT</pubDate><content:encoded>&lt;h3&gt;记录原因&lt;/h3&gt;
&lt;p&gt;我已经为一个项目工作了大约 7 周，时间有长有短，我想我已经有一些时间来了解 React 了。但和我想的不一样，我想让这位朋友长得整整齐齐，但不知怎么的，就像看着胡须乱长一样......&lt;/p&gt;
&lt;p&gt;于是我想，&amp;quot;让我们来修正这段代码吧！&amp;quot;我打算写一个简短的项目历史，并借此机会尝试一下 TypeScript。&lt;/p&gt;
&lt;h4&gt;为什么选择 React？&lt;/h4&gt;
&lt;p&gt;在我之前的项目中，我有机会使用 VueJS，所以我有过基于 Vue 编写代码的经验，但我没有足够的经验来比较优缺点，而且我之前甚至没有使用过 React，所以我想，&amp;quot;它是现在最热门的框架，让我们试试吧！&amp;quot;。我认为这是一个体验 React 优点而不是 Vue 缺点的机会。&lt;/p&gt;
&lt;h4&gt;生态系统广泛&lt;/h4&gt;
&lt;p&gt;我认为这是一个众所周知的优势，无论是在数量上还是在其他方面，但我在 Vue 中使用的大多数库在 React 中也有，我觉得这才是最主要的，而 Vue 只是一个免费赠品。&lt;/p&gt;
&lt;h4&gt;直观&lt;/h4&gt;
&lt;p&gt;我不知道是不是因为我还没有用过很多 Hooks，但在如何处理 Props 和如何编写代码方面，我感觉更得心应手。&lt;/p&gt;
&lt;p&gt;在 UE 中，我感觉代码之间的区别感是通过编写模板、脚本以及头部、胸部和腹部等样式来实现的，但 React 基本上是以一种不区分 JavaScript 代码的方式来编写 Fuction Components 的，因此我感觉在访问变量等方面要方便得多。&lt;/p&gt;
&lt;p&gt;当然，如果像 Vue 那样将它们分开，可能会更容易阅读代码，但在编写标准方面还是有明显区别的，即使是现在，如果要问 &amp;quot;我应该使用什么？&amp;quot;我也会使用 React。&lt;/p&gt;
&lt;h4&gt;事件处理很方便&lt;/h4&gt;
&lt;p&gt;这与上文有点相似，但我记得编写 EventHandlers 比使用 Vue 时要直观得多。在 Vue 的情况下，我认为有很多部分都将函数和变量分开了，但 React 允许你当场声明和处理变量，就像使用一般的编程语言一样，所以这种感觉就像我以前每天吃的白癜风能治好吗一样，温暖而舒适。&lt;/p&gt;
&lt;h4&gt;为什么要使用 TypeScript？&lt;/h4&gt;
&lt;p&gt;虽然 React 的利弊可能与实际行业中的利弊不同，但我个人能够指出 React 的上述优点，在重构过程中还是选择了 React。&lt;/p&gt;
&lt;p&gt;同样，我认为在重构时写下我想使用 TS 而不是 JS 的原因也是不错的，所以就留在这里吧。&lt;/p&gt;
&lt;h4&gt;错误捕获&lt;/h4&gt;
&lt;p&gt;我认为 TS 的很多优点都是针对 JS 的缺点的。基本上，我认为 JS 是一种非常松散的语言，而事实也是如此，因此有时错误会发生在奇怪的地方，而且很难解决，我希望 TS 能很好地捕获这些错误。&lt;/p&gt;
&lt;h4&gt;熟悉性&lt;/h4&gt;
&lt;p&gt;作为一种编程语言，JS 有很多我个人不喜欢的地方，这是因为它不可避免的发展历史。然而，TS 显然是基于 JS 的，但它提供了一种非常严密的结构，解决了我对 JS 感到失望的问题！当然，我还可以做得更多，但熟悉稳定的结构所带来的舒适感是我使用 TS 的动力...&lt;/p&gt;
&lt;h3&gt;结论&lt;/h3&gt;
&lt;p&gt;我将继续写下我的心得，并在今后的文章中与我以前的代码进行比较。我不知道这需要多长时间，但我希望这是一个非常有意义的过程！&lt;/p&gt;
</content:encoded></item><item><title>[BOJ 1922, Java] 网络连接</title><link>https://www.traceoflight.dev/zh/blog/boj1922/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj1922/</guid><description>BOJ 1922，“网络连接”题的 Java 解法</description><pubDate>Mon, 20 Feb 2023 07:55:51 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1922&quot;&gt;BOJ 1922&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;图论，最小生成树&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;h4&gt;引言&lt;/h4&gt;
&lt;p&gt;最近只顾着做题，感觉对理论有些疏忽，因此想在记录解题过程的同时，哪怕只是简单地梳理一下理论。&lt;/p&gt;
&lt;h4&gt;MST（minimum spanning tree，最小生成树）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;什么是生成树？&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;指包含图中所有顶点的树。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;最小生成树&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;指在所有生成树中总边长最短的那棵&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;主要特征&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;包含 n 个顶点，且拥有 (n - 1) 条边
由于边长最小，因此可用于企业内部网络构建等场景&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;普雷姆算法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;选择 1 个初始顶点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从MST中包含的顶点所连接的边中，依次选择最短的边&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当所有顶点均被连接时结束&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;克鲁斯卡尔算法&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;按权重对所有边进行排序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在不形成环的情况下，依次添加边&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当所有顶点均被连接时结束&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-comment&quot;&gt;// 간선 정보 클래스 선언&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Comparable&lt;/span&gt;&amp;lt;Connection&amp;gt; {

        &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; cost;
        &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; start;
        &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; end;

        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; cost, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; start, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; end)&lt;/span&gt; {
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.cost = cost;
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.start = start;
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.end = end;
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 가중치를 통한 비교&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;compareTo&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Connection other)&lt;/span&gt; {
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.cost - other.cost;
        }

    }

    &lt;span class=&quot;hljs-comment&quot;&gt;// 정점의 집합을 확인하는 함수&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;checkUnion&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] unionInfo, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; targetVertex)&lt;/span&gt; {

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (unionInfo[targetVertex] != targetVertex) {
            unionInfo[targetVertex] = checkUnion(unionInfo, unionInfo[targetVertex]);
        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; unionInfo[targetVertex];
    }

    &lt;span class=&quot;hljs-comment&quot;&gt;// 정점 2개가 집합을 이루는지 확인하는 함수&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;isUnion&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] unionInfo, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; vertex1, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; vertex2)&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; checkUnion(unionInfo, vertex1) == checkUnion(unionInfo, vertex2);
    }

    &lt;span class=&quot;hljs-comment&quot;&gt;// 집합을 합쳐주는 함수&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;makeUnion&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] unionInfo, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; vertex1, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; vertex2)&lt;/span&gt; {

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;group1&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; checkUnion(unionInfo, vertex1);
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;group2&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; checkUnion(unionInfo, vertex2);

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (group2 &amp;gt; group1) {
            unionInfo[group2] = group1;
        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
            unionInfo[group1] = group2;
        }

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-comment&quot;&gt;// 정점 및 간선의 갯수 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;vertexNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(input.readLine());
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;edgeNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(input.readLine());

        &lt;span class=&quot;hljs-comment&quot;&gt;// 간선 정보를 담을 우선순위 큐 선언&lt;/span&gt;
        PriorityQueue&amp;lt;Connection&amp;gt; costPriorityQueue = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;PriorityQueue&lt;/span&gt;&amp;lt;&amp;gt;();

        &lt;span class=&quot;hljs-comment&quot;&gt;// 간선 정보 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; edgeNumber; i++) {
            &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;connectionInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;startNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(connectionInfo.nextToken());
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;endNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(connectionInfo.nextToken());
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(connectionInfo.nextToken());

            &lt;span class=&quot;hljs-type&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Connection&lt;/span&gt;(cost, startNode, endNode);
            costPriorityQueue.add(connection);

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 집합에 포함된 정점의 갯수와 최소 가중치 정보를 담을 변수 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;totalCost&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;totalEdge&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 집합 정보를 담을 배열 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] groupInfo = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[vertexNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;];
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; vertexNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++) {
            groupInfo[i] = i;
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// Kruskal&amp;#x27;s Algorithm&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (totalEdge &amp;lt; vertexNumber - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &amp;amp;&amp;amp; !costPriorityQueue.isEmpty()) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 가중치 순으로 확인&lt;/span&gt;
            &lt;span class=&quot;hljs-type&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowConnection&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; costPriorityQueue.poll();

            &lt;span class=&quot;hljs-comment&quot;&gt;// 집합 관계를 확인하여 아직 집합이 아닌 경우 집합에 추가하고 가중치 가산&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!isUnion(groupInfo, nowConnection.start, nowConnection.end)) {
                makeUnion(groupInfo, nowConnection.start, nowConnection.end);
                totalEdge += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
                totalCost += nowConnection.cost;
            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 최종 최소 가중치값 출력&lt;/span&gt;
        output.write(Integer.toString(totalCost));

        output.flush();
        output.close();

    }

}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 14503，Java] 机器人真空吸尘器</title><link>https://www.traceoflight.dev/zh/blog/boj14503/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj14503/</guid><description>BOJ 14503 &quot;机器人吸尘器 &quot;问题的 Java 解决方案</description><pubDate>Sat, 18 Feb 2023 12:31:09 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp1@@&quot;&gt;boj 14503&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Classification.&lt;/h3&gt;
&lt;p&gt;实施、模拟、仿真&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;这是一个典型的实施问题，但问题的描述有点难以理解。我尽量只评论这一部分。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;扫描当前单元&lt;/li&gt;
&lt;li&gt;检查当前槽的方向，&lt;strong&gt;从逆时针旋转 90 度开始&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;转一圈，检查开始时的位置，如果没有要清理的东西，就往回转。&lt;/li&gt;
&lt;li&gt;如果没有要清扫的内容，就停止。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果你忽略了先检查前方左侧的那部分问题，你就会对执行感到困惑。一定要注意这一点！&lt;/p&gt;
&lt;h3&gt;解决方案代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; height;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; width;

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;isNeedClean&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] table, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nowYIndex, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nowXIndex)&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; table[nowYIndex][nowXIndex] == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;mapSize&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

        &lt;span class=&quot;hljs-comment&quot;&gt;// 뒷 방향 등록 해시맵 선언&lt;/span&gt;
        HashMap&amp;lt;Integer, Integer&amp;gt; backward = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashMap&lt;/span&gt;&amp;lt;&amp;gt;();
        backward.put(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;);
        backward.put(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;);
        backward.put(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;);
        backward.put(&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;);

        height = Integer.parseInt(mapSize.nextToken());
        width = Integer.parseInt(mapSize.nextToken());

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] mapInfo = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[height][width];

        &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;startingPoint&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowY&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(startingPoint.nextToken());
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowX&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(startingPoint.nextToken());
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowDirection&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(startingPoint.nextToken());

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; height; i++) {
            &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;mapLine&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; width; j++) {
                mapInfo[i][j] = Integer.parseInt(mapLine.nextToken());
            }

        }

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;cleanCounter&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] directionY = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;};
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] directionX = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;};

        Loop:
        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 현재 칸이 청소가 필요하다면 청소 실시&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (isNeedClean(mapInfo, nowY, nowX)) {
                mapInfo[nowY][nowX] = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;;
                cleanCounter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
            }

            &lt;span class=&quot;hljs-comment&quot;&gt;// 주변 칸에 대해서 확인&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;; i++) {

                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetDirection&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (nowDirection + &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; - i) % &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;;
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetY&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowY + directionY[targetDirection];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetX&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowX + directionX[targetDirection];

                &lt;span class=&quot;hljs-comment&quot;&gt;// 청소할 칸이 있는 경우 이동 및 방향 전환&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (isNeedClean(mapInfo, targetY, targetX)) {
                    nowY = targetY;
                    nowX = targetX;
                    nowDirection = targetDirection;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
                }

                &lt;span class=&quot;hljs-comment&quot;&gt;// 청소할 칸이 없는 경우 뒷칸 확인&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;) {
                    targetY = nowY + directionY[backward.get(nowDirection)];
                    targetX = nowX + directionX[backward.get(nowDirection)];

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 뒤로 이동할 수 없는 경우 청소 종료&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (mapInfo[targetY][targetX] == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; Loop;

                        &lt;span class=&quot;hljs-comment&quot;&gt;// 이동할 수 있다면 뒤로 1칸 후진&lt;/span&gt;
                    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
                        nowY = targetY;
                        nowX = targetX;
                    }
                }

            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 이동 결과 출력&lt;/span&gt;
        output.write(Integer.toString(cleanCounter));

        output.flush();
        output.close();

    }

}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>首次采访回顾</title><link>https://www.traceoflight.dev/zh/blog/first-interview/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/first-interview/</guid><description>第一次访谈的简要回顾</description><pubDate>Tue, 07 Feb 2023 11:30:12 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;2023-07-06 缩略图编辑 (&lt;a href=&quot;https://kr.freepik.com/free-vector/interview-concept-illustration_7446777.htm#from_view=detail_alsolike&quot;&gt;作者故事集&lt;/a&gt;，来自 Freepik)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;简介&lt;/h4&gt;
&lt;p&gt;好久没写东西了。&lt;/p&gt;
&lt;p&gt;我目前正在完成第 8 期 SSAFY 课程，所以没有时间像我想象的那样写很多东西。&lt;/p&gt;
&lt;p&gt;不过，即使经历了面试等重要环节，我觉得如果不把这些事情整理好，对我的发展也没有什么帮助，所以就匆匆写了这篇文章。&lt;/p&gt;
&lt;h4&gt;面试过程&lt;/h4&gt;
&lt;p&gt;这是一次视频面试，我本以为会是一次性格面试，而不是技术面试，但它并不像我想象的那样是一次技术面试。&lt;/p&gt;
&lt;p&gt;我不知道我是应该为自己的预期和准备感到高兴，还是应该为失去获得经验的机会而感到失望......&lt;/p&gt;
&lt;p&gt;至于面试问题，我想说的是&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;每次 1 分钟的自我介绍&lt;/p&gt;
&lt;p&gt;你为什么选择目前的专业而不是主修专业？&lt;/p&gt;
&lt;p&gt;关于差距&lt;/p&gt;
&lt;p&gt;工作环境可能和你想象的不一样，可以吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我写得有点抽象，但我很高兴自己能用准备好的内容来回答。特别是对于非本专业的学生来说，总会有一些问题是针对他们与本专业学生相比缺乏 CS 知识的，因此在一定程度上做好准备是很有必要的！&lt;/p&gt;
&lt;p&gt;###个人感想&lt;/p&gt;
&lt;p&gt;不过，由于这不是一次技术面试，所以我觉得更令人失望的是，相关的问题并不多，因为我不知道下一次编码测试什么时候才能通过。&lt;/p&gt;
&lt;p&gt;我听说这是面试官重新评价公司的时候，就像公司在评价面试者一样，我想我在这次面试中也感受到了这一点。&lt;/p&gt;
&lt;p&gt;就我这次面试的公司而言，我认为我将从事的工作与我所想的工作大相径庭，所以我想即使我得到了这份工作，也会有很多麻烦.....！&lt;/p&gt;
</content:encoded></item><item><title>[BOJ 16934, Java] 游戏昵称</title><link>https://www.traceoflight.dev/zh/blog/boj16934/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj16934/</guid><description>BOJ 16934，“游戏昵称”题的 Java 解法</description><pubDate>Wed, 28 Dec 2022 00:35:18 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/16934&quot;&gt;BOJ 16934&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;数据结构(data_structures)、基于哈希的集合与映射(hash_set)、字符串(string)、树(trees)、Trie(trie)&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;我个人觉得自己在字符串题上比较薄弱，觉得应该再加把劲学习一下，而这道题正好是可以用Trie算法解决的。&lt;/p&gt;
&lt;p&gt;因为示例很多，反例检查并不难，但如果这种题连示例都不够清晰的话，恐怕会让人头疼得多……&lt;/p&gt;
&lt;p&gt;由于之前从未在Java中实现过树型结构，虽然花了一些时间，但能不借助外力独立实现，这一点还是值得肯定的！&lt;/p&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Node&lt;/span&gt; {

        &lt;span class=&quot;hljs-type&quot;&gt;char&lt;/span&gt; nowChar;
        String value;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
        &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;isUnique&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
        HashSet&amp;lt;Node&amp;gt; childSet;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 헤드에 사용하기 위한 정의 방식&lt;/span&gt;
        Node() {

            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.childSet = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashSet&lt;/span&gt;&amp;lt;&amp;gt;();
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.value = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.isUnique = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 일반적인 서브노드들을 위한 정의 방식&lt;/span&gt;
        Node(&lt;span class=&quot;hljs-type&quot;&gt;char&lt;/span&gt; target) {

            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.nowChar = target;
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.childSet = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashSet&lt;/span&gt;&amp;lt;&amp;gt;();
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.value = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;;

        }

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Trie&lt;/span&gt; {

        &lt;span class=&quot;hljs-comment&quot;&gt;// 헤드 노드 1개를 보유하고 시작&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Node&lt;/span&gt;();

        &lt;span class=&quot;hljs-comment&quot;&gt;/**
         * 문자열 1개를 트라이 클래스에 추가하는 메서드
         */&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;addString&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String target)&lt;/span&gt; {

            &lt;span class=&quot;hljs-type&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.head;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetLength&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; target.length();

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt;= targetLength; i++) {

                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == targetLength) {

                    nowNode.count += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
                    nowNode.value = target;

                } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {

                    &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;hasChild&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;

                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (Node subNode : nowNode.childSet) {

                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (subNode.nowChar == target.charAt(i)) {

                            nowNode = subNode;
                            hasChild = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
                            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

                        }

                    }

                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!hasChild) {

                        &lt;span class=&quot;hljs-type&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;madeNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Node&lt;/span&gt;(target.charAt(i));
                        nowNode.childSet.add(madeNode);
                        nowNode = madeNode;

                    }

                }

            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;/**
         * 문자열의 고유 별칭을 찾아내는 메서드
         */&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title function_&quot;&gt;findUnique&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String target)&lt;/span&gt; {

            &lt;span class=&quot;hljs-type&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.head;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetLength&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; target.length();
            &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;isFirstTime&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;resultCount&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; targetLength + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++) {

                &lt;span class=&quot;hljs-comment&quot;&gt;// 첫 번째로 만나는 고유값이 해당 문자열의 별칭&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowNode.isUnique &amp;amp;&amp;amp; isFirstTime) {

                    nowNode.isUnique = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
                    isFirstTime = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
                    result = i;
                    resultCount = nowNode.count;

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 이후로도 만나는 고유값은 고유값이 아니도록 처리&lt;/span&gt;
                } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {

                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowNode.isUnique) {
                        nowNode.isUnique = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
                    }

                }

                &lt;span class=&quot;hljs-comment&quot;&gt;// 마지막 문자까지 확인&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == targetLength) {

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 마지막 문자까지 고유값을 체크하지 못한 경우&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (result == -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                        result = targetLength;
                        resultCount = nowNode.count;
                    }

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 카운팅 갯수에 따른 값을 반환&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowNode.count == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; target.substring(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, result);

                    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
                        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; target + resultCount;
                    }

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 마지막 문자 이전까지는 트라이 내 탐색 방식으로 진행&lt;/span&gt;
                } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {

                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (Node subNode : nowNode.childSet) {

                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (subNode.nowChar == target.charAt(i)) {
                            nowNode = subNode;
                            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

                        }

                    }

                }

            }

            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ERROR!&amp;quot;&lt;/span&gt;;

        }

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-comment&quot;&gt;// Trie Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 트라이 인스턴스 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;Trie&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nickNameTrie&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Trie&lt;/span&gt;();

        &lt;span class=&quot;hljs-comment&quot;&gt;// 유저 수 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;userNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(input.readLine());

        &lt;span class=&quot;hljs-comment&quot;&gt;// 모든 유저에 대해 진행&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; userNumber; i++) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 닉네임 입력 및 트라이에 추가&lt;/span&gt;
            &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nickName&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; input.readLine();
            nickNameTrie.addString(nickName);

            &lt;span class=&quot;hljs-comment&quot;&gt;// 함수를 호출하여 해당 닉네임에 대한 별칭 출력&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == userNumber - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                output.write(nickNameTrie.findUnique(nickName));

            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
                output.write(nickNameTrie.findUnique(nickName) + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;);
            }

        }

        output.flush();
        output.close();

    }

}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 17114, Java] 超级番茄</title><link>https://www.traceoflight.dev/zh/blog/boj17114/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj17114/</guid><description>BOJ 17114，“超番茄”题的 Java 解法</description><pubDate>Thu, 22 Dec 2022 04:36:35 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;[BOJ 17114] (&amp;lt;&lt;a href=&quot;https://www.acmicpc.net/problem/17114&amp;amp;gt;&quot;&gt;https://www.acmicpc.net/problem/17114&amp;amp;gt;&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;实现(implementation), 图论(graphs), 图遍历(graph_traversal), 广度优先搜索(bfs)&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;我个人认为这是一个很好地展示了BFS可以变得多么“臃肿”的题目。&lt;/p&gt;
&lt;p&gt;虽然我很早就知道这道题的存在，且解法本身也已广为人知，但这次我再次体会到：即使解法广为人知，将其以自己的方式实现却是另一回事。&lt;/p&gt;
&lt;p&gt;快速输入输出是基础，而在进行广度优先搜索时，如果不剔除冗余部分，就可能导致超时。&lt;/p&gt;
&lt;p&gt;虽然不确定在Python中能否通过sys.stdin.readline解决，但在Java中幸运的是，仅通过BufferedReader就能处理。&lt;/p&gt;
&lt;p&gt;解完这道题后查阅资料发现，似乎另有更巧妙的解法，但这里采用的是对经典BFS进行粗暴扩展的方式来解决。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;将坐标信息输入到11维数组中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;未成熟的西红柿进行计数，成熟的西红柿记录坐标&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;遍历成熟的西红柿，将相邻的未成熟西红柿加入成熟西红柿列表的同时减少计数值，根据条件重复该过程&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若计数值变为0，则表示全部成熟，输出耗时天数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若计数未归零，但在对现有未成熟的西红柿重复执行第(3)步操作时数量未发生变化，则说明无法继续催熟，因此输出-1。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在解决此题时，处理第2步和第3步时若采用其他方式——**即每次循环都重新计数，或者不移除已使用过的成熟番茄的坐标，可能会导致超时……**我在此处纠结了很久才解决。&lt;/p&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;p&gt;代码相当长……但我认为这是因为使用了11层for循环，并且需要表示相邻坐标，所以无可奈何。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; tomatoLeft;

    &lt;span class=&quot;hljs-comment&quot;&gt;/**
     * 토마토가 익는 메커니즘을 반영하여 1일 뒤의 배열로 변경하는 함수
     */&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;ripeTomato&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][][][][][][][][][][] target, Queue&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[]&amp;gt; tomatoQueue, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] sizeInfo)&lt;/span&gt; {

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] movements = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[][]{
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
        };

        ArrayList&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[]&amp;gt; ripeList = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ArrayList&lt;/span&gt;&amp;lt;&amp;gt;();

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] nowIdx : tomatoQueue) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] movement : movements) {

                &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;isNotOverIndex&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;

                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;11&lt;/span&gt;; i++) {
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;gt; nowIdx[i] + movement[i] || nowIdx[i] + movement[i] &amp;gt;= sizeInfo[i]) {
                        isNotOverIndex = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
                        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
                    }
                }

                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx00&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx01&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx02&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx03&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx04&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx05&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx06&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx07&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx08&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx09&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx10&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;];

                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (

                        isNotOverIndex

                                &amp;amp;&amp;amp; target[nextIdx00][nextIdx01][nextIdx02]
                                [nextIdx03][nextIdx04][nextIdx05][nextIdx06]
                                [nextIdx07][nextIdx08][nextIdx09][nextIdx10]
                                == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

                ) {

                    ripeList.add(

                            &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{
                                    nextIdx00, nextIdx01, nextIdx02,
                                    nextIdx03, nextIdx04, nextIdx05, nextIdx06,
                                    nextIdx07, nextIdx08, nextIdx09, nextIdx10
                            }

                    );

                }

            }

        }

        tomatoQueue.clear();

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] ripeCoord : ripeList) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (

                    target[ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]]
                            [ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]]
                            [ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]] == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

            ) {

                target[ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]]
                        [ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]]
                        [ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]] = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

                tomatoLeft -= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

                tomatoQueue.add(ripeCoord);

            }

        }

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-comment&quot;&gt;// 배열 사이즈 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] storageSize = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;11&lt;/span&gt;];
        &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;sizeInput&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;11&lt;/span&gt;; i++) {
            storageSize[i] = Integer.parseInt(sizeInput.nextToken());
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 창고 정보 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][][][][][][][][][][] tomatoStorage = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[storageSize[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]]
                [storageSize[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]]
                [storageSize[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]];

        Queue&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[]&amp;gt; ripeTomatoQueue = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;LinkedList&lt;/span&gt;&amp;lt;&amp;gt;();

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx10&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx10 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]; idx10++) {
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx09&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx09 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;]; idx09++) {
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx08&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx08 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;]; idx08++) {
                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx07&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx07 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]; idx07++) {
                        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx06&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx06 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]; idx06++) {
                            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx05&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx05 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]; idx05++) {
                                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx04&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx04 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]; idx04++) {
                                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx03&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx03 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]; idx03++) {
                                        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx02&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx02 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]; idx02++) {
                                            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx01&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx01 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]; idx01++) {

                                                &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;storageInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

                                                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx00Counter&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx00Counter &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]; idx00Counter++) {

                                                    &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowInput&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(storageInfo.nextToken());

                                                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowInput == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {

                                                        ripeTomatoQueue.add(
                                                                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{
                                                                        idx00Counter, idx01, idx02,
                                                                        idx03, idx04, idx05, idx06,
                                                                        idx07, idx08, idx09, idx10
                                                                }
                                                        );

                                                    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowInput == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {

                                                        tomatoLeft += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

                                                    }

                                                    tomatoStorage[idx00Counter][idx01][idx02]
                                                            [idx03][idx04][idx05][idx06]
                                                            [idx07][idx08][idx09][idx10]
                                                            = nowInput;

                                                }

                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 지난 날짜 카운팅 변수 및 모두 익지 못하는 상황을 체크하기 위한 Flag 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;dayCounter&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
        &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;cantComplete&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 모두 익지 않았다면 반복&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (tomatoLeft &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 함수를 호출하여 기존 배열 깊은 복사 후 1일 뒤의 배열 확인&lt;/span&gt;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;lastTomato&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; tomatoLeft;
            ripeTomato(tomatoStorage, ripeTomatoQueue, storageSize);

            &lt;span class=&quot;hljs-comment&quot;&gt;// 날짜 1 카운트&lt;/span&gt;
            dayCounter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

            &lt;span class=&quot;hljs-comment&quot;&gt;// 아직 다 익지 않았지만 기존이랑 차이가 없다면 전부 익을 수 없는 상황이므로 Flag 변경 후 break&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (tomatoLeft != &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; tomatoLeft == lastTomato) {
                cantComplete = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 문제 조건에 따라서 출력&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (cantComplete) {
            output.write(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;-1&amp;quot;&lt;/span&gt;);
        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
            output.write(Integer.toString(dayCounter));
        }

        output.flush();
        output.close();

    }

}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 3865, Java] 学会会员</title><link>https://www.traceoflight.dev/zh/blog/boj3865/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj3865/</guid><description>BOJ 3865，“学会会员”题的 Java 解法</description><pubDate>Mon, 12 Dec 2022 13:50:33 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/3865&quot;&gt;BOJ 3865&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;广度优先搜索(bfs)，数据结构(data_structures)，深度优先搜索(dfs)，图论(graphs)，图遍历(graph_traversal)，基于哈希的集合与映射(hash_set)，语法分析(parsing)，字符串(string)&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;最近参加的编程测试中，似乎经常出现与字符串相关的问题，因此我在寻找此类题目时发现了这道题。&lt;/p&gt;
&lt;p&gt;由于是使用深度优先搜索的题目，我比较熟悉，但因为对Java语言的掌握还不够熟练，解题花了一点时间，不过整体思路并没有偏离深度优先搜索的框架。&lt;/p&gt;
&lt;p&gt;这道题的关键在于对字符串数据进行妥善处理，同时持续检查学会和学生名字的访问记录集合，对于尚未访问的情况，通过递归+计数的方式处理，最终得以解决。&lt;/p&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-comment&quot;&gt;/**
     * 해당 학회의 총 인원수를 반환하는 함수
     */&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;getTotalPerson&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String target)&lt;/span&gt; {

        &lt;span class=&quot;hljs-comment&quot;&gt;// 결과값 변수 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 아직 방문하지 않은 경우에 대해서만 처리&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!visitLog.contains(target)) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 방문 기록&lt;/span&gt;
            visitLog.add(target);

            &lt;span class=&quot;hljs-comment&quot;&gt;// 사람이 아닌 학회일 경우&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (clubGraph.containsKey(target)) {

                &lt;span class=&quot;hljs-comment&quot;&gt;// 해당 학회의 방문하지 않은 구성원에 대해 재귀함수를 호출, 결과값에 합산&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (String eachPerson : clubGraph.get(target)) {

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 구성원이 학회라면 재귀함수 호출&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (clubGraph.containsKey(eachPerson)) {
                        result += getTotalPerson(eachPerson);

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 학생이라면 아직 방문하지 않았을 경우 결과값 1 추가&lt;/span&gt;
                    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {

                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!visitLog.contains(eachPerson)) {

                            visitLog.add(eachPerson);
                            result += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

                        }

                    }

                }

            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 결과값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result;

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;strToInt&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String inputString)&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; Integer.parseInt(inputString);
    }

    &lt;span class=&quot;hljs-comment&quot;&gt;// 학회 수, 첫 학회, 학회 관계 그래프, 학생 기록 집합 정적 변수 선언&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; clubNumber;
    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String firstClub;
    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; HashMap&amp;lt;String, ArrayList&amp;lt;String&amp;gt;&amp;gt; clubGraph = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashMap&lt;/span&gt;&amp;lt;&amp;gt;();
    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; Set&amp;lt;String&amp;gt; visitLog = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashSet&lt;/span&gt;&amp;lt;&amp;gt;();

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));

        &lt;span class=&quot;hljs-comment&quot;&gt;// 학회의 수 입력, 입력값이 0이라면 반복 종료&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; ((clubNumber = strToInt(input.readLine())) != &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {

            clubGraph.clear();
            visitLog.clear();

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; clubNumber; i++) {

                &lt;span class=&quot;hljs-comment&quot;&gt;// 줄 단위 입력&lt;/span&gt;
                &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;clubInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(),&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[:,.]&amp;quot;&lt;/span&gt;);

                &lt;span class=&quot;hljs-comment&quot;&gt;// 학회 이름 변수 선언&lt;/span&gt;
                &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;clubName&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; clubInfo.nextToken();

                &lt;span class=&quot;hljs-comment&quot;&gt;// 첫 학회라면 따로 변수에 기록&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                    firstClub = clubName;
                }

                &lt;span class=&quot;hljs-comment&quot;&gt;// 기존에 없던 학회라면 추가&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!clubGraph.containsKey(clubName)) {
                    clubGraph.put(clubName, &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ArrayList&lt;/span&gt;&amp;lt;&amp;gt;());
                }

                &lt;span class=&quot;hljs-comment&quot;&gt;// 나머지를 전부 학회의 원소로 추가&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (clubInfo.hasMoreTokens()) {
                    clubGraph.get(clubName).add(clubInfo.nextToken());
                }

            }

            &lt;span class=&quot;hljs-comment&quot;&gt;// 함수를 호출하여 결과값을 출력 스택에 추가&lt;/span&gt;
            System.out.println(getTotalPerson(firstClub));

        }

    }

}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>SQLD 通过心得及资料</title><link>https://www.traceoflight.dev/zh/blog/sqld/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/sqld/</guid><description>SQLD 通过心得</description><pubDate>Tue, 29 Nov 2022 15:32:31 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-0d43c36638e8bf56-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;我通过了第47届SQL开发者资格考试。这是我在彻底改变职业方向后考取的第一张证书，因此感到非常自豪。&lt;/p&gt;
&lt;p&gt;起初我本想投入一个月左右的时间，但后来被其他事情耽搁，或者过于理论化地去学习……感觉浪费了不少时间，这让我有些遗憾。在此记录下学习过程中总结的一些要点。&lt;/p&gt;
&lt;p&gt;最后一部分记录了个人整理的概念，其中包含一些实操内容，以及为了便于记忆而进行的编辑，因此可能存在某些地方与实际情况不符！不过，考虑到或许能对他人备考有所帮助，我决定保留全部内容，日后若想起会再进行修改。&lt;/p&gt;
&lt;h1&gt;耗时及学习方法&lt;/h1&gt;
&lt;p&gt;实际花费的时间约为2周，其中解题大约耗时1周。&lt;/p&gt;
&lt;p&gt;起初，我本想通过[Data on Air](&lt;a href=&quot;https://dataonair.or.kr/&quot;&gt;https://dataonair.or.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;)提供的概念讲解，以一种近乎“王道”的方式进行学习，但发现SQLD考试本身提供的题目中，以实战SQL语句形式呈现的题目远多于概念性内容，因此我在初期就放弃了这种方式。不过，我仍然认为其内容本身很不错，如果时间充裕，建议大家去看看！&lt;/p&gt;
&lt;p&gt;接下来，我通过YouTube上各种形式的讲座掌握了大致的框架。仅就SQLD而言，已有相当数量的系统化讲座，因此挑选看起来不错的课程即可。&lt;/p&gt;
&lt;p&gt;最后是解题环节。关于习题，相关论坛或博客上都有复原历年真题的资料。俗称 “黄皮书”虽然不错，但切勿忽视对真题的解题练习！我仅对黄皮书的前两章进行了通读并整理了错题笔记，剩余时间全部用于真题练习。&lt;/p&gt;
&lt;p&gt;个人推荐的真题复原合集网站是[这个博客](&lt;a href=&quot;https://yunamom.tistory.com/category/%EC%9E%90%EA%B2%A9%EC%A6%9D/SQLD%20%EA%B8%B0%EC%B6%9C%EB%AC%B8%EC%A0%9C&quot;&gt;https://yunamom.tistory.com/category/자격증/SQLD 기출문제&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;)。因为只需输入答案，就能立即确认该题的正误。&lt;/p&gt;
&lt;h1&gt;概念整理&lt;/h1&gt;
&lt;p&gt;参考事项：由于第1章的习题比重小于第2章，因此被排在后序，相应地仅记录了必要内容，内容可能不够充分&lt;/p&gt;
&lt;h2&gt;第1单元&lt;/h2&gt;
&lt;h2&gt;实体的分类&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;基本/主键实体&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;核心实体&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;行为实体&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;数据建模&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用于构建信息系统的数据视角业务分析技术&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过约定好的表示法来表达现实世界中的数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用于构建数据库的分析/设计过程&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;进行数据建模时的注意事项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;冗余&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缺乏灵活性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不一致&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;数据建模的类型&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;概念型：抽象层次较高，以业务为中心进行全面建模&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;逻辑型：准确表达键、属性、关系等，设计时注重可重用性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;物理型：考虑物理特性，以便移植到实际数据库中。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;数据库模式的结构&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;外部&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;概念&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内部&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;ERD绘制顺序&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;绘制实体。&lt;/li&gt;
&lt;li&gt;合理布局实体。&lt;/li&gt;
&lt;li&gt;设定实体之间的关系。&lt;/li&gt;
&lt;li&gt;标注关系名称。&lt;/li&gt;
&lt;li&gt;标注关系参与度。&lt;/li&gt;
&lt;li&gt;标注关系的必选性。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;实体的特征&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;该业务中需要且必须管理的信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必须是唯一的标识符。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;拥有两个或以上的实例。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必须实际被使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必须拥有属性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必须形成至少一个关系。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1개 엔터티: 2개 이상의 인스턴스 집합 + 2개 이상의 속성
1개 속성: 1개 이상의 속성값
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;根据属性特征的分类&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;基本属性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设计属性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;派生属性&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;域&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;各属性可能取值的范围&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;指定实体内属性的数据类型、大小及约束条件&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;属性命名&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;必须是该业务中使用的名称。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不使用描述性属性名。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尽量避免使用缩写。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必须确保在整个数据模型中具有唯一性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ERD中不区分存在关系和行为关系。
但在类图中需进行区分，并描述关联关系和依赖关系。&lt;/p&gt;
&lt;h2&gt;关系的表示法&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;关系名：关系的名称&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关系度：1 : 1, 1 : M, M : N&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关系选定规格：必选、可选&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;关系解读&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;基准实体读作“1个”（One）或“每个”（Each）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解读目标实体的关系参与度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解读关系选定规格和关系名称。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;标识符类型&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;代表性：主标识符 vs 辅助标识符&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自生成性：内部 vs 外部&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;单一属性标识：单一 vs 复合&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;是否具有语义：本质 vs 人为&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;主标识符的特征&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;唯一性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;稀有性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不变性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存在性&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;性能数据建模&lt;/h2&gt;
&lt;p&gt;以提升数据库性能为目的，将性能相关事项反映到数据建模中&lt;/p&gt;
&lt;h2&gt;第一范式规范对象&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;分离冗余属性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;行级重复&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;列级重复&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;反规范化&lt;/h2&gt;
&lt;p&gt;通过规范化实体、属性及关系的重复、整合与分离
提升系统性能，简化开发与运维
当预计性能下降时，即使可能导致完整性受损，仍可执行。&lt;/p&gt;
&lt;h3&gt;流程&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;调查反规范化的对象&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;范围处理频率&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;大量范围处理&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;统计性处理&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;表连接（JOIN）数量&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若可通过其他方法实现，则考虑引导采用该方法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;连接（JOIN）较多的情况，使用视图表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;处理大量数据时，采用聚簇&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;持有大量数据时，通过分区进行数据分割&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;索引维护&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应用程序逻辑变更&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;超级/子类型数据模型转换技术&lt;/h2&gt;
&lt;p&gt;单独发生的事务 -&amp;gt; 单独的表
超级 + 子类型 -&amp;gt; 超级 + 子表
整体 -&amp;gt; 单一表&lt;/p&gt;
&lt;h2&gt;确定主键顺序的标准&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;指定以高效利用索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;位于前面的属性值应作为比较条件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尽可能使用 &apos;=&apos;, BETWEEN, &apos;&amp;lt;&amp;gt;&apos;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;分布式数据库的优缺点&lt;/h2&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;优点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;区域自治性，可逐步扩展系统容量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可靠性与可用性 / 实用性与灵活性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;响应速度快，降低通信成本，更好地满足区域用户需求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提高数据可用性与可靠性，便于调节系统规模&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;缺点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;开发成本及潜在错误增加，处理成本上升，威胁数据完整性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设计过程困难，管理复杂且成本高，响应速度不稳定，难以控制&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;第2单元&lt;/h2&gt;
&lt;h2&gt;SQL语句的种类&lt;/h2&gt;
&lt;h3&gt;DCL&lt;/h3&gt;
&lt;p&gt;数据控制语言（Data Control Language），用于管理权限的命令&lt;/p&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;GRANT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;授予权限的作用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;GRANT {permission} ON {table} TO {user};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```text
WITH GRANT, WITH ADMIN의 비교

GRANT: 특정 사용자에게 권한 부여가 가능한 권한을 부여, 부여한 부모의 권한이 회수될 때 자식의 권한도 회수
ADMIN: 테이블에 대한 모든 권한을 부여, 부여한 부모의 권한 회수와 관계 없는 권한
```
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;REVOKE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用于撤销权限&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;REVOKE {permission} ON {table} FROM {user};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;权限的种类&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;ALL&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;-- 모든 권한 부여&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;/*  */&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;REFERENCES&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;ALTER&lt;/span&gt; INDEX &lt;span class=&quot;hljs-comment&quot;&gt;/*  */&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;/* ROLE: 다양한 권한을 하나의 그룹으로 묶어서 관리 */&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;CREATE&lt;/span&gt; ROLE {role_name}; &lt;span class=&quot;hljs-comment&quot;&gt;-- 권한 그룹 생성&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;GRANT&lt;/span&gt; {permission_type} &lt;span class=&quot;hljs-keyword&quot;&gt;TO&lt;/span&gt; {role_name}; &lt;span class=&quot;hljs-comment&quot;&gt;-- 해당 그룹에 권한 등록&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;GRANT&lt;/span&gt; {role_name} &lt;span class=&quot;hljs-keyword&quot;&gt;TO&lt;/span&gt; {user_1}, {user_2}...; &lt;span class=&quot;hljs-comment&quot;&gt;-- 다른 유저들에게 권한 그룹 부여&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;DDL&lt;/h3&gt;
&lt;p&gt;数据定义语言（Data Definition Language），用于定义数据的命令&lt;/p&gt;
&lt;p&gt;以SQL Server为例，支持自动提交（Auto Commit）&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CREATE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;创建表结构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;CREATE TABLE {table_name} {table_elements};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```sql
CREATE TABLE EXAMPLE (
/* 
  컬럼명은 영어, 한글, 숫자 전부 가능 
  첫 글자를 문자로 지정해야 하며, 컬럼의 데이터 타입은 반드시 설정해야 한다.
*/
		NAME  varchar2(max_length)  -- 최대 길이를 가진 가변길이 문자열
  	ID번호 char(length)          -- 고정된 길이 문자열
		나이_2 number(max_length)    -- 숫자형 데이터 타입
  	생일   date                  -- 날짜형 데이터 타입
);
```
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;##### CONSTRAINT (条件)

* default：指定默认值

* not null：不允许输入NULL

* primary key：指定主键（not null、unique，支持多主键）

* foreign key：指定外键（支持多外键）
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;ALTER&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用于修改表及列的名称、属性，以及进行结构修改（如添加、删除等）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;ALTER TABLE {table_name} {detail_order} {detail_property(if need)} TO {change_target};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式使用&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### 详细命令

* RENAME：更改表、列的名称

* MODIFY：更改列的属性

* ADD：添加列

* DROP：删除列

* ADD CONSTRAINT / DROP CONSTRAINT：添加、删除约束
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;RENAME&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;无需通过 ALTER 即可更改表或列的名称&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可同时更改多个表名&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;DROP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;无需通过 ALTER 即可删除表或列&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### TABLE {table_name} CASCADE CONSTRAINT

* 仅存在于 Oracle 的选项，SQL Server 中不存在

* 对于外键约束，先删除引用表，再删除该表。

* 同时删除该表数据及所有外键引用约束
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;TRUNCATE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;表初始化 （并非删除！）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;仅清除内部数据，表的存在及列结构仍保留。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### DROP vs TRUNCATE vs DELETE

* DROP：彻底删除表并释放内存

* TRUNCATE：保留表和列的存在，仅释放剩余数据的内存

* DELETE：删除记录，数据操作日志保留，可在提交前回滚，且不释放内存
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;DML&lt;/h3&gt;
&lt;p&gt;数据操作语言（Data Manipulation Language），用于操作记录的命令&lt;/p&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;INSERT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;将数据插入记录&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;INSERT INTO {table_name} {column_name} VALUES {change_column_name};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;虽可不指定列名进行插入，但若未指定，则必须填入所有字段值&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;UPDATE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;修改现有数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;UPDATE {table_name} SET {column_name} = {column_value} WHERE {condition};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;DELETE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;删除现有数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;DELETE FROM {table_name} WHERE {condition};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可省略FROM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;SELECT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;查询特定数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;SELECT {select_target} FROM {select_origin} WHERE {condition};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;也可使用&lt;code&gt;GROUP BY {calc_type} HAVING {condition} / ORDER BY {sort_condition}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式添加条件&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### DISTINCT

用于查询不包含重复值的条件 (a, b, NULL, a, b, NULL) =&amp;amp;gt; (a, b, NULL)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;COUNT&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;(\*): 统计包含 NULL 值的全部行数

({column\_name}): 统计特定列的行数（不包含 NULL 值）
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;TCL&lt;/h3&gt;
&lt;p&gt;事务控制语言（Transaction Control Language），事务控制命令&lt;/p&gt;
&lt;p&gt;事务（Transaction）：改变数据库状态的操作&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;* transaction의 특징
고립성: 실행되는 동안 다른 transaction에 영향을 받아 잘못된 결과를 만들면 안됨
일관성: 실행 전 데이터베이스에 잘못된 점이 없다면 transaction 수행 후에도 내용에 오류가 있으면 안됨
지속성: transaction이 갱신한 데이터베이스 내용은 영구적으로 저장
원자성: transaction에서 정의한 연산은 모두 성공적으로 실행되거나 전혀 실행되지 않음 (All or Nothing)
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;COMMIT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将数据变更反映到数据库中&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;SAVEPOINT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;指定保存点（savepoint）作为代码分割的分支点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用&lt;code&gt;SAVEPOINT {savepoint_name};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式使用&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;ROLLBACK&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用于恢复到先前状态的命令&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可回滚至SAVEPOINT或上一次COMMIT&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用形式为&lt;code&gt;ROLLBACK TO {rollback_point};&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若无SAVEPOINT，则恢复至最近一次COMMIT&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;TCL的效果&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;保障数据完整性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在永久更改数据前确认数据变更情况&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可对具有逻辑关联的操作进行分组处理&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;函数&lt;/h2&gt;
&lt;h3&gt;字符型函数&lt;/h3&gt;
&lt;p&gt;常用于指定 SELECT、WHERE 等条件&lt;/p&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;LOWER&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将英文字符串转换为小写&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;UPPER&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;将英文字符串转换为大写&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CONCAT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;合并两个字符串&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与 Oracle 的 &apos;||&apos;、SQL Server 的 &apos;+&apos; 功能相同&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;SUBSTR&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;从字符串的第 M 位开始，保留 N 个字符并删除其余部分&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;LENGTH, LEN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;包含空格的字符串长度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;TRIM, LTRIM, RTRIM&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;移除两端指定的字符；若未指定字符，则移除空格&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;数值型函数&lt;/h3&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;ROUND&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;四舍五入&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;TRUNC&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;向下取整&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CEIL&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;取不小于该数的最小整数&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;FLOOR&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;取不大于该数的最大整数&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;MOD&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;模运算&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;SIGN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;正数返回 1，0 返回 0，负数返回 -1&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;ABS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;绝对值&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;日期型函数&lt;/h3&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;SYSDATE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;输出执行查询时的当前日期和时间&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;EXTRACT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;以&lt;code&gt;EXTRACT ({information} FROM {data})&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式使用&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如何从日期型数据中提取所需值&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;类型转换&lt;/h3&gt;
&lt;p&gt;可通过这些函数更改数据类型&lt;/p&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;TO_NUMBER&lt;/h4&gt;
&lt;p&gt;字符串 &amp;gt; 数字&lt;/p&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;TO_CHAR&lt;/h4&gt;
&lt;p&gt;数字、日期 &amp;gt; 字符串（根据格式不同生成结果）&lt;/p&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;TO_DATE&lt;/h4&gt;
&lt;p&gt;字符串 &amp;gt; 日期（根据格式不同生成结果）&lt;/p&gt;
&lt;h3&gt;基本结构&lt;/h3&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;DECODE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IF语句&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当条件可以简单整理时&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;CASE WHEN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;扩展版的 IF 语句&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当需要对条件进行较长整理时&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;ORDER BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对查询到的表进行排序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以使用多个排序条件&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;WHERE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IN, NOT IN：只要列表中的值与其中任意一个匹配或不匹配，即满足条件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IS NULL, IS NOT NULL：判断是否为NULL，返回T/F&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BETWEEN a AND b：检查值是否在a和b之间，返回T/F（包含a和b）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;比较运算符：=, &amp;gt;, &amp;lt;, &amp;gt;=, &amp;lt;= 等&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A LIKE B：根据a查找与b相似的字符串&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;%：表示存在一个或多个字符&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;_：表示一个字符&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;명시적 형변환 vs 암시적 형변환

명시적 형변환: 함수를 활용하여 데이터 타입을 변경
암시적 형변환: 데이터베이스가 알아서 바꿔주는 것
&amp;gt;&amp;gt; 숫자 타입의 PK는 암묵적으로 인덱스가 되는데 데이터의 조회 등으로 암시적 형변환이 발생한 경우, 인덱스로 사용이 불가능
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;WITH&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可使用子查询，像临时表或视图一样使用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可指定别名&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;被视为内联视图或临时表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以&lt;code&gt;WITH {table_name} AS {table_condition}&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;的形式使用&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;GROUP BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;根据条件进行分组的命令&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若值的组合不同，则属于不同组&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HAVING&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;基于分组后状态的条件语句&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可使用 COUNT（计数）、SUM（求和）、AVG（平均值）、MAX（最大值）、MIN（最小值）、STDDEV（标准差）、VARIAN（方差）等&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可使用 DISTINCT（去除重复）、ALL（全部）等条件&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;NULL 函数&lt;/h3&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;NVL, ISNULL&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;若为 NULL 则替换为其他值的函数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据类型不同时无法使用&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;NVL2&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;根据是否为NULL返回不同结果的函数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若非NULL则返回第1个参数，若为NULL则返回第2个参数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;NULLIF&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;若两个参数相同则返回NULL，不同则返回第1个参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;COALESCE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;返回第一个非NULL的值&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;GROUP 函数&lt;/h3&gt;
&lt;p&gt;分组对象列的值和聚合对象列的值将输出为NULL&lt;/p&gt;
&lt;p&gt;可通过普通分组函数提取相同的结果&lt;/p&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;ROLLUP&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;显示部分和与总和。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;函数的参数顺序会影响结果，并以分层结构返回聚合值。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CUBE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;针对所有可分组的情况生成参数组合&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;GROUPING SETS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;可按括号括起的集合进行聚合&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;GROUPING&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;当计算出小计、总计等时返回1，否则返回0的函数&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;JOIN&lt;/h3&gt;
&lt;p&gt;通常指表与表之间的连接，类似于集合&lt;/p&gt;
&lt;p&gt;支持表与表之间、连接结果与表之间、以及连接结果之间的JOIN&lt;/p&gt;
&lt;p&gt;当两个相关表至少存在一个共同属性时可应用&lt;/p&gt;
&lt;p&gt;既有明确指定 JOIN 的 ANSI 标准查询，也存在未明确指定的非标准查询。&lt;/p&gt;
&lt;p&gt;若列出了 JOIN，则每次处理两个，无法同时处理所有 JOIN&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;交集&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;INNER JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;非标准表示法，用 “ ” 缩写&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;连接两个表的交集&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;LEFT JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;非标准形式使用时，左侧标注 (+)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;左侧表全部数据与右侧表的交集进行连接&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;RIGHT JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;非标准形式使用时，右侧标注 (+)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;右侧表全部数据与左侧表的交集进行连接&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;OUTER JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;由于两侧均不可使用 (+) 符号，因此无法使用 OUTER JOIN，必须使用 ANSI 标准查询。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与 UNION 不同，即使仅存在一个共同属性也可应用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;并集&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;UNION (ALL)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;当查询对象的列数相同且各列属性一致时可应用的连接方式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据量为 Data1 + Data2。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UNION ALL 合并时不会去除重复数据&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;差集&lt;/p&gt;
&lt;p&gt;当仅需确认排除交集后的单一集合时适用&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;MINUS(Oracle)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;EXCEPT(SQL Server)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;连接对象之间的一致程度&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;EQUI JOIN：使用相同的列连接两个关系&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;non-EQUI JOIN：使用不完全匹配的列连接两个关系&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;ex) A.key &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;= B.key
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CROSS JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;若不使用键进行连接，则会对两个表产生笛卡尔积&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;5개의 행 * 3개의 행 = 15개의 행으로 조회
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;自连接&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在同一张表内，对具有关联关系的两个列进行连接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于表名和列名完全一致，因此必须使用别名&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;优化器连接&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;在执行连接的过程中，为性能优化而选择的方法，需通过提示（Hint）指定&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;层级查询&lt;/h3&gt;
&lt;p&gt;对树形数据进行查询&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;层级结构的起点通过 START WITH 设定（ROOT NODE）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有子节点的节点 = LEAF NODE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;层级用 LEVEL 表示&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CONNECT BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;确认层级结构的连接方向&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;子节点 &amp;gt; 父节点&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;父节点 &amp;gt; 子节点&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;##### CONNECT BY PRIOR a = b

* 当 a 列和 b 列在同一条记录中相同时，会形成层级关系

* 按 b -&amp;amp;gt; a 的顺序重新排列
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;SIBLINGS BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;确定兄弟节点之间的排列顺序&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;窗口函数&lt;/h3&gt;
&lt;p&gt;用于轻松定义记录之间关系的函数，采用&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT WINDOW_FUNCTION {arguments} OVER {partition by column} {order_style} FROM {table};&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;的形式&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;WINDOW_FUNCTION&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;窗口函数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;组内聚合函数：COUNT、SUM、MIN、MAX、AVG 等&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;组内排名函数&lt;/p&gt;
&lt;p&gt;即使创建了排名函数，也不会自动排序，因此必须使用 ORDER BY 子句。&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;RANK&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对相同排名赋予相同的排名&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不将相同排名计为同一条记录&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;DENSE_RANK&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对相同排名赋予相同的排名&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将相同排名计为同一条记录&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;ROW_NUMBER&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;对相同排名赋予唯一的排名&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;组内比例相关函数&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;PERCENT_RANK&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;以“顺序”而非数值为对象，查询分区内各顺序对应的百分比&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;NTILE(n)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;返回按分区将总记录数均分为 n 份后的数值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;CUME_DIST&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;查询分区内当前行值及以下记录数的累积百分比&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在累积分布中取值范围为 0 至 1&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;组内行序函数&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;FIRST_VALUE&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;返回分区内出现的第一个值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;LAST_VALUE&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;返回分区内出现的最后一个值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;LAG(column_name, record_difference)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;获取前一行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;LEAD(column_name, record_difference, value_if_null)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;获取下一行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;默认值为 1&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;参数&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;参数（列名等函数操作的对象）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;PARTITION BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;分割表中记录的依据&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;ORDER BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;指定在分割后的记录范围内或整个表中，按何种标准对记录进行排序&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;WINDOWING&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;确定函数运算对象的记录范围&lt;/p&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;RANGE&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;用于指定范围&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;BETWEEN a AND b&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;应用于从 a 到 b 的范围&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;UNBOUNDED PRECEDING&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;起始位置 = 第一行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;UNBOUNDED FOLLOWING&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;起始位置 = 最后一行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h5&gt;CURRENT ROW&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;起始位置 = 当前行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;表分区&lt;/h3&gt;
&lt;p&gt;将大型表拆分为多个数据文件进行存储&lt;/p&gt;
&lt;p&gt;存储在物理上分离的数据文件中 =&amp;gt; 性能提升且可独立管理&lt;/p&gt;
&lt;p&gt;缩小查询范围的效果 =&amp;gt; 性能提升&lt;/p&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;范围分区&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;基于值的范围进行分区存储的方法&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;列表分区&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;基于特定值进行分区&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;哈希分区&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;数据库管理系统自行使用哈希函数进行分区和管理的方式&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;优化器&lt;/h2&gt;
&lt;p&gt;即使是相同的SQL语句，根据执行方式的不同，性能也会有所差异（性能指标：耗时、资源使用量等）&lt;/p&gt;
&lt;p&gt;因此，需要分析SQL语句并根据特定标准制定执行计划，此时便会使用优化器。&lt;/p&gt;
&lt;p&gt;优化器可能会影响执行性能，但结果值不会改变。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-test&quot;&gt;SQL문 작성 =&amp;gt; 파싱 (문법 검사, 구문 분석) =&amp;gt; 옵티마이저 (비용 기반 / 규칙 기반) =&amp;gt; 실행 계획 (PLAN_TABLE 저장) =&amp;gt; SQL 실행
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;成本驱动&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;最新版本的Oracle默认使用成本驱动优化器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过系统统计信息和对象统计信息计算该SQL语句执行的总成本，然后制定成本最低的执行计划&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;规则驱动&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;根据15项优先级规则制定执行计划&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通常基于ROWID进行扫描的优先级最高&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;索引&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;按索引键排序 =&amp;gt; 查找速度加快&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;主键（PK）会自动生成索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以在一张表上创建多个索引，一个索引可以由多个列组成&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按降序创建和排序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不建议将频繁变化的属性设置为索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;除非是具有UNIQUE属性的索引，否则辅助索引允许输入重复数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与索引扫描相比，全表扫描可能更高效且在成本上更具优势&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于分区表，可以针对分区创建分区键索引，称为全局索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;索引增加必然导致数据量增加，因此可能会导致插入、删除和修改速度下降&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所有数据类型均可创建索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;索引的种类包括顺序索引、位图索引、组合索引、簇索引和哈希索引。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### SCAN 方式

*&amp;lt;br /&amp;gt;



  ##### 唯一索引扫描 (Index Unique SCAN)

  * 当索引键值不重复时，通过该键进行查找

*&amp;lt;br /&amp;gt;



  ##### 唯一索引扫描 (Index Unique SCAN)

  * 使用查询特定范围的 WHERE 子句来扫描该区域

  * 根据范围的不同，可能只返回一个结果，甚至返回 0 个结果

*&amp;lt;br /&amp;gt;



  ##### 索引全扫描

  * 从索引的开头到结尾进行全范围扫描
&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;优化器连接的类型&lt;/h3&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### 嵌套循环连接

* 先查询外部（驱动）表以查找连接对象数据，再连接内部（从属）表

* 处理量由先行表的处理范围决定，因此需要寻找大小较小的先行表

* 行间处理和表间处理均按顺序进行

* 寻找最佳顺序至关重要

* 由于会发生随机访问（在先行表中引用第二个表时发生），为减少性能延迟，应尽量减少随机访问的发生

* 当先行表的处理范围较广或随机访问范围较广时，存在比排序合并连接（SORT MERGE JOIN）更不利的情况

* “必须使用索引”，使用唯一索引时更有利

* 适用于在线事务处理（OLTP）

* 与嵌套循环相同，根据满足先行表条件的记录数进行循环执行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;*&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#### 排序合并连接 (Sort Merge JOIN)

* 分别对两张表进行排序，完成后进行合并

* 由于涉及排序，当数据量较大时会变慢。

* 当待排序的数据量较大时，会使用临时磁盘，从而导致性能下降。

* 支持等值连接 (EQIU JOIN) 和非等值连接 (non-EQIU JOIN)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;哈希连接&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;* 将两张表中较小的一张加载到哈希内存中，使用两张表的连接键生成哈希表

* 同时扫描两张表

* 先行表中必须先出现“较小数据”

* 能最大限度利用系统资源，但可能消耗过多资源，且存在负载过高等风险

* 在处理海量数据时表现出色

* 仅适用于等值连接（EQUI JOIN）

* 不使用索引

* 连接方式

  ```text
  먼저 선행 테이블을 결정, 선행 테이블에서 주어진 조건에 해당하는 레코드를 선택
  해당 행이 선택되면 JOIN Key를 기준으로 해시 함수를 사용
  해시 테이블을 메인 메모리에 생성, 후행 테이블에서 주어진 조건을 만족하는 행을 찾음
  후행 테이블의 JOIN Key를 사용해서 해시함수를 적용, 해당 버킷을 검색
  ```
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;PL/SQL&lt;/h2&gt;
&lt;p&gt;一种通过扩展SQL实现多种过程化编程的语言&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;采用块结构，可按功能进行模块化&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以 DECLARE 语句开头，通过声明变量和常量进行使用&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DECLARE、BEGIN ~ END 为必备，EXCEPTION 为可选&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 DML、IF、LOOP 等多种过程化语言&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内置于 Oracle 中，可与使用相同语言的程序兼容&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提升应用程序的性能&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可编写过程、用户定义函数和触发器对象&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;过程内部编写的程序代码由 PL/SQL 引擎处理，而一般的 SQL 语句则由 SQL 执行器处理&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;分布式数据库&lt;/h2&gt;
&lt;p&gt;一种由单个数据库管理系统（DBMS）通过网络控制物理上分离的数据库的 DB 形式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;性能提升：由于分布式数据库可进行并行处理，因此速度较快&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采用模块化设计，可在不影响其他模块的情况下更新系统&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可通过添加分布式数据库来扩展容量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;便于保护重要数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可靠性高&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;管理与控制困难&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安全管理和完整性控制困难&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结构复杂&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;메모

count(*): 전체 행의 수를 카운팅, null 포함
count({column_name}) null 을 제외한 행의 수를 카운팅
null: 모르는 값을 상징, 값의 부재를 말함
(null is null) = TRUE
null과의 모든 비교는 null 반환
0 혹은 &amp;#x27; &amp;#x27;과 동일한 값이 아님 

서브쿼리: SELECT문 내의 SELECT문이 반복 사용된 쿼리, 단일행 및 다중행으로 구분
- 정렬을 수행하는 ORDER BY를 사용할 수 없다.
- 여러 행을 반환하는 서브 쿼리는 다중 행 연산자를, 단일 행을 반환하는 서브쿼리는 단일 행 연산자를 사용
- 메인 쿼리에서 서브 쿼리의 컬럼을 자유롭게 사용할 수 없음
- EXIST는 True 혹은 False를 반환한다

스칼라 서브쿼리: 한 행과 한 컬럼만 반환하는 서브쿼리
인라인뷰: 서브쿼리가 FROM 절 내에 쓰여진 것

view 테이블
- 사용상의 편의를 위해 사용
- 수행속도의 향상을 위해 사용
- SQL의 성능을 향상시키기 위해 사용
- 임시적인 작업을 위해 사용
- 보안관리를 위해 사용

실행 순서
SELECT ALIAS =&amp;gt; FROM =&amp;gt; WHERE =&amp;gt; GROUP BY =&amp;gt; HAVING =&amp;gt; SELECT =&amp;gt; ORDER BY

조회 행수 제한
몇 번째 행을 조회하는지 부여하는 조건문
ROWNUM {row_number}: Oracle
TOP {row_number}: SQL Server
LIMIT {row_number}: MySQL

ROWID
해당 데이터가 어떤 데이터 파일 상에서 어느 블록에 저장되었는지 알려준다.
데이터베이스에 저장되어 있는 데이터를 구분할 수 있는 유일한 값이다.
ROWID의 번호는 데이터 블록에 데이터가 저장된 순서이다.
테이블에 데이터를 입력하면 자동으로 생성된다.
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 17471, Python] 选区划分</title><link>https://www.traceoflight.dev/zh/blog/boj17471/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj17471/</guid><description>BOJ 17471，“选区划分”问题的 Python 解法</description><pubDate>Mon, 07 Nov 2022 11:14:53 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/17471&quot;&gt;BOJ 17471&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;广度优先搜索(bfs)，暴力搜索算法(bruteforcing)，组合数学(combinatorics)，深度优先搜索(dfs)，图论(graphs)，图遍历(graph_traversal)，数学(math)&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;起初我以为这是一个并集查找问题，尝试过删除边、设置其他约束条件，但实际上这是一个需要采用直截了当的方法来解决的问题。&lt;/p&gt;
&lt;p&gt;如果忽略0.5秒的限制条件，可以考虑对所有组合进行深度遍历来检查，但由于使用Python，时间限制过短导致我排除了直截了当的解法，这成为了致命失误。&lt;/p&gt;
&lt;p&gt;考虑到区域数量最多仅限10个，完全可以通过暴力搜索解决，若将精力投入其他方向反而可能陷入困境。&lt;/p&gt;
&lt;p&gt;因此，本题的解法是将所有区域二分，检查是否能形成选区；若能形成选区，则比较两个选区的人口差，若该值小于原有人口差，则进行更新。&lt;/p&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 게리맨더링&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; itertools &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; combinations

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-comment&quot;&gt;# 상한값 선언&lt;/span&gt;
INF = &lt;span class=&quot;hljs-number&quot;&gt;2000000000&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 구역 갯수 입력&lt;/span&gt;
area_number = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())

&lt;span class=&quot;hljs-comment&quot;&gt;# 구역별 인구 정보 입력&lt;/span&gt;
people_number = [&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))

&lt;span class=&quot;hljs-comment&quot;&gt;# 인접 구역 관계 그래프 입력&lt;/span&gt;
graph = [[] &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; area_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):
    near_area, *graph[area_idx] = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

&lt;span class=&quot;hljs-comment&quot;&gt;# 총 인구수 확인&lt;/span&gt;
max_people = &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;(people_number)

&lt;span class=&quot;hljs-comment&quot;&gt;# 최소 차이값 변수 선언&lt;/span&gt;
min_difference = INF

&lt;span class=&quot;hljs-comment&quot;&gt;# 한 선거구의 포함될 모든 구역 수에 대해 체크 &lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; areas &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, area_number // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):

    &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 구역 중에서 한 선거구에 포함될 구역 확정&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; target_areas &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; combinations(&lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), areas):

        &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 선거구에 포함되는 구역 집합 선언 및 해당 선거구 인원수 변수 선언&lt;/span&gt;
        target_set = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;(target_areas)
        sum_areas = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# Depth First Search&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 집합에 포함된 한 구역에서 시작하는 깊이 탐색&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; first_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; target_set:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 선거구 내 구역 수 체크 카운터 선언&lt;/span&gt;
            counter = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 방문 리스트 선언&lt;/span&gt;
            is_visited = [&lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]

            &lt;span class=&quot;hljs-comment&quot;&gt;# 깊이 탐색을 진행할 스택 선언 및 초기 조건 입력&lt;/span&gt;
            progress_stack = [first_area]
            sum_areas += people_number[first_area]
            is_visited[first_area] = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 탐색 진행&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; progress_stack:

                &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 구역 확인&lt;/span&gt;
                now_area = progress_stack.pop()

                &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 인접 구역에 대해 확인&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; next_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; graph[now_area]:

                    &lt;span class=&quot;hljs-comment&quot;&gt;# 같은 선거구에 속해있고 방문하지 않았을 경우만 조사&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; next_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; target_set:
                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; is_visited[next_area]:

                            &lt;span class=&quot;hljs-comment&quot;&gt;# 방문 처리, 인구수 합산, 선거구 카운팅&lt;/span&gt;
                            is_visited[next_area] = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;
                            sum_areas += people_number[next_area]
                            counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

                            &lt;span class=&quot;hljs-comment&quot;&gt;# 다음 구역 스택에 추가&lt;/span&gt;
                            progress_stack.append(next_area)

            &lt;span class=&quot;hljs-comment&quot;&gt;# 1회의 조사로 선거구의 모든 정보를 획득하므로 반복하지 않음&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 남은 구역들에 대해서 다른 하나의 선거구라 가정하고 깊이 탐색 진행&lt;/span&gt;

        other_set = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)) - &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;(target_set)
        sum_other_areas = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; first_other_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; other_set:

            other_counter = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
            sum_other_areas += people_number[first_other_area]

            progress_stack = [first_other_area]
            is_visited[first_other_area] = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; progress_stack:
                
                now_area = progress_stack.pop()

                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; next_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; graph[now_area]:
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; next_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; other_set:
                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; is_visited[next_area]:
                            is_visited[next_area] = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;
                            sum_other_areas += people_number[next_area]
                            progress_stack.append(next_area)
                            other_counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 양쪽 선거구를 조사했을 때 남는 구역이 없을 경우만 성립&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; counter + other_counter == area_number:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 두 선거구의 인구 차이를 확인하여 기존값보다 작다면 갱신&lt;/span&gt;
            now_min = &lt;span class=&quot;hljs-built_in&quot;&gt;abs&lt;/span&gt;(sum_areas - sum_other_areas)
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; min_difference &amp;gt; now_min:
                min_difference = now_min

&lt;span class=&quot;hljs-comment&quot;&gt;# 한 번도 갱신하지 못했다면 선거구 분할 실패이므로 -1 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; min_difference == INF:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hljs-comment&quot;&gt;# 갱신한 경우 결과를 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(min_difference)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 14438, Python] 数列与查询 17</title><link>https://www.traceoflight.dev/zh/blog/boj14438/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj14438/</guid><description>BOJ 14438，“数列与查询 17” 题的 Python 解法</description><pubDate>Tue, 01 Nov 2022 13:52:01 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;[BOJ 14438](&lt;a href=&quot;https://www.acmicpc.net/problem/14438&quot;&gt;https://www.acmicpc.net/problem/14438&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;)&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;段树(segtree)，数据结构(data_structures)&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;我认为这是初次接触段树的人最常遇到的段树类型题目。&lt;/p&gt;
&lt;p&gt;其优势在于，相比线性列表，它能在O(NlogN)的时间复杂度内构建出支持区间和、区间积、区间最大值等各种运算的结构，并能以O(logN)的高速访问各区间的信息。&lt;/p&gt;
&lt;p&gt;本题主要可分为构建分段树的函数、查询区间信息的函数以及更新值的函数。&lt;/p&gt;
&lt;h4&gt;构建函数&lt;/h4&gt;
&lt;p&gt;首先来看构建分段树的函数&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;make_segtree&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, result_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end:&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    최소 숫자 정보를 담는 세그먼트 트리를 생성하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 한 곳으로 모인 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 노드는 포인터가 가리키는 인덱스의 값과 동일&lt;/span&gt;
        result_list[now_node] = target_list[start]

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 범위를 나타내는 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
        mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 구간을 분할하여 최소값으로 갱신&lt;/span&gt;
        val_1 = make_segtree(target_list, result_list, start, mid, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
        val_2 = make_segtree(target_list, result_list, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 두 구간의 최소값을 비교하여 둘 중 최소값을 현재 노드에 기록&lt;/span&gt;
        result_list[now_node] = &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(val_1, val_2)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 노드의 값을 반환&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result_list[now_node]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;，该函数基本展示了将整个列表按区间拆分，并将各区间的信息存储到分段树各节点中的过程。&lt;/p&gt;
&lt;p&gt;由于采用了递归方式，因此会不断堆积递归栈，直到区间长度为1为止；若递归成功，则将该地址对应的单个列表值信息写入其中。&lt;/p&gt;
&lt;p&gt;随后，通过返回的值，非叶子节点会筛选符合条件的值，最终到达根节点。&lt;/p&gt;
&lt;p&gt;因此，根节点中存储的值就是整个区间内最符合题目要求的值。&lt;/p&gt;
&lt;h4&gt;搜索函数&lt;/h4&gt;
&lt;p&gt;接下来查看查找区间内最小值的函数：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;find_min_number&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_tree: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, left: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, right: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    해당 구간의 최소값을 찾는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위 내로 포인터가 좁혀진 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; left &amp;lt;= start &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; right &amp;gt;= end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 노드값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; target_tree[now_node]

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위를 아예 벗어난 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; left &amp;gt; end &lt;span class=&quot;hljs-keyword&quot;&gt;or&lt;/span&gt; right &amp;lt; start:

        &lt;span class=&quot;hljs-comment&quot;&gt;# None 값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위가 걸친 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
        mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 구간을 분할하여 값을 확인&lt;/span&gt;
        val_1 = find_min_number(target_tree, start, mid, left, right, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
        val_2 = find_min_number(target_tree, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, left, right, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 반환된 값들 중 None이 존재하는 경우&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; val_1 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; val_2 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; val_1 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; val_2

        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; val_2 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; val_1

        &lt;span class=&quot;hljs-comment&quot;&gt;# None이 없다면&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 두 구간의 최소값 중에서 더 작은 값을 반환&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(val_1, val_2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;。该函数的基本逻辑是：只要包含目标区间，就进行详细搜索，直到仅包含目标区间为止，并返回该值以便上级函数进行验证。&lt;/p&gt;
&lt;p&gt;如果超出范围，则返回None。通过条件判断进行剪枝（Pruning），即可确保仅选择范围内的区间进行比较。&lt;/p&gt;
&lt;h4&gt;修改函数&lt;/h4&gt;
&lt;p&gt;最后来看反映值被修改情况的函数&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;change_segtree&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_tree: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_idx: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_val: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    리스트에 생긴 변경점을 트리에 반영하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;
    
    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 한 곳으로 모인 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 목표로 하는 인덱스랑 동일하다면 변경값을 반영&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == target_idx:
            target_tree[now_node] = target_val

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 범위로 주어진 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 목표 인덱스가 범위 내에 존재할 경우에만 갱신 가능성 존재&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start &amp;lt;= target_idx &amp;lt;= end:

            &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
            mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 변경될 수 있는 인덱스를 재조사&lt;/span&gt;
            change_segtree(target_tree, start, mid, target_idx, target_val, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
            change_segtree(target_tree, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, target_idx, target_val, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 하위 노드들의 갱신이 진행된 이후 현재 노드의 갱신 진행&lt;/span&gt;
        target_tree[now_node] = &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(target_tree[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node], target_tree[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于如果包含当前被修改值的索引的区间，则必须全部更改，因此以该索引是否包含在区间内为标准进行区分。&lt;/p&gt;
&lt;p&gt;与生成函数类似，会不断堆叠递归栈直至缩小到单个索引，并从仅包含该索引的节点开始更新其值，在返回过程中反映修改后的值，最终检查至根节点以完成操作。&lt;/p&gt;
&lt;h3&gt;解题代码&lt;/h3&gt;
&lt;p&gt;通过上述过程，可以将题目要求的全部操作模块化，以下是完整的代码。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 수열과 쿼리 17&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; math &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; ceil, log2

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;make_segtree&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, result_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end:&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    최소 숫자 정보를 담는 세그먼트 트리를 생성하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 한 곳으로 모인 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 노드는 포인터가 가리키는 인덱스의 값과 동일&lt;/span&gt;
        result_list[now_node] = target_list[start]

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 범위를 나타내는 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
        mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 구간을 분할하여 최소값으로 갱신&lt;/span&gt;
        val_1 = make_segtree(target_list, result_list, start, mid, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
        val_2 = make_segtree(target_list, result_list, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 두 구간의 최소값을 비교하여 둘 중 최소값을 현재 노드에 기록&lt;/span&gt;
        result_list[now_node] = &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(val_1, val_2)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 노드의 값을 반환&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result_list[now_node]

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;find_min_number&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_tree: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, left: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, right: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    해당 구간의 최소값을 찾는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위 내로 포인터가 좁혀진 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; left &amp;lt;= start &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; right &amp;gt;= end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 노드값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; target_tree[now_node]

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위를 아예 벗어난 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; left &amp;gt; end &lt;span class=&quot;hljs-keyword&quot;&gt;or&lt;/span&gt; right &amp;lt; start:

        &lt;span class=&quot;hljs-comment&quot;&gt;# None 값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위가 걸친 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
        mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 구간을 분할하여 값을 확인&lt;/span&gt;
        val_1 = find_min_number(target_tree, start, mid, left, right, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
        val_2 = find_min_number(target_tree, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, left, right, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 반환된 값들 중 None이 존재하는 경우&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; val_1 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; val_2 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; val_1 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; val_2

        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; val_2 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; val_1

        &lt;span class=&quot;hljs-comment&quot;&gt;# None이 없다면&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 두 구간의 최소값 중에서 더 작은 값을 반환&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(val_1, val_2)

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;change_segtree&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_tree: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_idx: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_val: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    리스트에 생긴 변경점을 트리에 반영하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;
    
    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 한 곳으로 모인 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 목표로 하는 인덱스랑 동일하다면 변경값을 반영&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == target_idx:
            target_tree[now_node] = target_val

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 범위로 주어진 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 목표 인덱스가 범위 내에 존재할 경우에만 갱신 가능성 존재&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start &amp;lt;= target_idx &amp;lt;= end:

            &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
            mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 변경될 수 있는 인덱스를 재조사&lt;/span&gt;
            change_segtree(target_tree, start, mid, target_idx, target_val, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
            change_segtree(target_tree, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, target_idx, target_val, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 하위 노드들의 갱신이 진행된 이후 현재 노드의 갱신 진행&lt;/span&gt;
        target_tree[now_node] = &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(target_tree[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node], target_tree[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])

&lt;span class=&quot;hljs-comment&quot;&gt;# 수열의 크기 및 수열 정보 입력&lt;/span&gt;
target_length = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
target_arr = [&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;*&amp;#x27;&lt;/span&gt;] + &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))

&lt;span class=&quot;hljs-comment&quot;&gt;# 수열의 구간 최소 숫자를 담을 세그먼트 트리 리스트 선언&lt;/span&gt;
segtree_arr = [&lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, ceil(log2(target_length) + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)))]

&lt;span class=&quot;hljs-comment&quot;&gt;# 함수를 호출하여 트리 생성&lt;/span&gt;
make_segtree(target_arr, segtree_arr, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, target_length, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hljs-comment&quot;&gt;# 퀴리 갯수 입력 및 출력 리스트 선언&lt;/span&gt;
query_number = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
output = []

&lt;span class=&quot;hljs-comment&quot;&gt;# 쿼리 실행&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(query_number):

    &lt;span class=&quot;hljs-comment&quot;&gt;# 각 쿼리의 정보&lt;/span&gt;
    order_type, num_1, num_2 = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

    &lt;span class=&quot;hljs-comment&quot;&gt;# 타입 1의 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; order_type == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 리스트 값을 변경 및 함수를 호출하여 트리에 반영&lt;/span&gt;
        target_arr[num_1] = num_2
        change_segtree(segtree_arr, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, target_length, num_1, num_2, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 타입 2의 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; order_type == &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 함수를 호출하여 해당 구간의 최소 숫자를 출력 리스트에 추가&lt;/span&gt;
        output.append(find_min_number(segtree_arr, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, target_length, num_1, num_2, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;))

&lt;span class=&quot;hljs-comment&quot;&gt;# 결과 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; output:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Git 入门</title><link>https://www.traceoflight.dev/zh/blog/git-intro/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/git-intro/</guid><description>关于Git之前的版本控制系统以及Git的工作原理和命令的总结文章</description><pubDate>Fri, 28 Oct 2022 13:19:01 GMT</pubDate><content:encoded>&lt;h1&gt;简介&lt;/h1&gt;
&lt;p&gt;这是一篇在学习 Git 过程中整理所需内容的博文，如果没有重大变化或不需要进一步学习，我认为这既是一篇简介，也将是最后一篇文章。&lt;/p&gt;
&lt;h2&gt;什么是 Git？&lt;/h2&gt;
&lt;p&gt;Git 是一种版本控制工具，它通过版本控制记录文件的变更，从而允许用户重新使用特定时间点的记录。&lt;/p&gt;
&lt;h3&gt;本地版本控制&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;复制目录&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;最简单的方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可能会不小心修改错误的文件，或者复制错误。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;VCS（版本控制系统）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;利用数据库管理文件的变更信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修订控制系统（Revision Control System）是典型的代表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;管理补丁集（文件中发生变更的部分）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;利用一系列补丁集，可以将所有文件恢复到特定时间点&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;集中式版本管理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;进行项目开发时，经常需要与其他开发人员协作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在这种情况下，单独设置一个管理文件的服务器，由客户端从中央服务器获取并使用文件的方式更为有利&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果中央服务器出现问题，且系统没有备份，可能会丢失所有历史记录，而这在本地也同样存在&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;分布式版本控制系统&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不仅简单地保存快照，还会同时复制存储库和历史记录。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若服务器出现问题，可通过相应的副本恢复工作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;也可从任意客户端中选择一个来恢复服务器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;远程存储库的存在使得多种协作方式成为可能&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GitHub也是此类远程存储库的一种&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;基本用法&lt;/h2&gt;
&lt;h3&gt;配置及文件访问命令&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 전역 사용자 설정&lt;/span&gt;
git config --global user.name {name} &lt;span class=&quot;hljs-comment&quot;&gt;# 이름&lt;/span&gt;
git config --global user.email {email_address} &lt;span class=&quot;hljs-comment&quot;&gt;# 이메일&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 로컬 사용자 설정 (해당 디렉토리에서 실행)&lt;/span&gt;
git config user.name {name} &lt;span class=&quot;hljs-comment&quot;&gt;# 이름&lt;/span&gt;
git config user.email {email_address} &lt;span class=&quot;hljs-comment&quot;&gt;# 이메일&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 설정 조회&lt;/span&gt;
git config --list

&lt;span class=&quot;hljs-comment&quot;&gt;# 생성&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;mkdir&lt;/span&gt; {path}/{folder_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 폴더&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;touch&lt;/span&gt; {file_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 파일&lt;/span&gt;
git init &lt;span class=&quot;hljs-comment&quot;&gt;# 파일 관리 시스템&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 저장소 및 히스토리 복제&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;clone&lt;/span&gt; {repository_url}

&lt;span class=&quot;hljs-comment&quot;&gt;# 원격 저장소&lt;/span&gt;
git remote add {remote_repo_name} {remote_repo_url} &lt;span class=&quot;hljs-comment&quot;&gt;# 추가&lt;/span&gt;
git remote -v &lt;span class=&quot;hljs-comment&quot;&gt;# 정보 확인&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# commit history&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;log&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;log&lt;/span&gt; --oneline &lt;span class=&quot;hljs-comment&quot;&gt;# 정보 표시 간략화&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;log&lt;/span&gt; --all &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 head 이후의 최신 기록들을 포함한 전체 정보를 표시&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;log&lt;/span&gt; --graph &lt;span class=&quot;hljs-comment&quot;&gt;# 브랜치를 시각화하여 분기를 표현한 그래프 형태로 정보를 표시&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;仓库管理命令&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git status &lt;span class=&quot;hljs-comment&quot;&gt;# 변경사항을 확인하는 명령어&lt;/span&gt;
git commit -m {message} &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 스테이지에 존재하는 변경 사항을 커밋&lt;/span&gt;

git add {file_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 특정한 파일을 스테이지에 추가하는 경우&lt;/span&gt;
git add . &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 레포지토리의 변경사항을 전부 스테이지에 추가하는 경우&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git 撤销操作&lt;/h2&gt;
&lt;h3&gt;清空暂存区&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; --cached &lt;span class=&quot;hljs-comment&quot;&gt;# root commit이 존재하지 않을 때&lt;/span&gt;
git restore --staged &lt;span class=&quot;hljs-comment&quot;&gt;# root commit이 존재할 때&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;修改提交&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git commit --amend 
&lt;span class=&quot;hljs-comment&quot;&gt;# 스테이지에 파일이 없는 경우: 직전 커밋의 메시지를 수정&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# 스테이지에 파일이 있는 경우: 기존 커밋에 현재 스테이지를 더하여 덮어쓰기 진행&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;将提交回滚至特定时间点&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git reset --soft {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 미래 파일들 전부 stage에 돌려놓음&lt;/span&gt;
git reset --mixed {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# default, 미래 파일들을 전부 working directory에 유지 (add 필요)&lt;/span&gt;
git reset --hard {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 미래 파일 전부 제거&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;删除历史提交&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git revert {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 과거 commit을 제거 후, 제거했음을 commit으로 추가&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于 reset 会减少提交数量，因此不适合协作环境；建议协作时使用 revert 代替 reset&lt;/p&gt;
&lt;h2&gt;Git 分支&lt;/h2&gt;
&lt;p&gt;分支：用于划分工作空间，帮助实现独立工作的机制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;能持续保持原始状态，因此很安全&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在一个分支上进行单一任务，从而提高协作效率&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 Git 中，创建分支的速度很快，且文件体积不大&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;相关命令&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 조회&lt;/span&gt;
git branch &lt;span class=&quot;hljs-comment&quot;&gt;# 로컬 저장소의 브랜치 대상&lt;/span&gt;
git branch -r &lt;span class=&quot;hljs-comment&quot;&gt;# 원격 저장소의 브랜치 대상&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 생성&lt;/span&gt;
git branch {branch_name}
git branch {branch_name} {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 특정 커밋 지점을 기준점으로 생성&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 제거&lt;/span&gt;
git branch -d {branch_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 병합 완료된 경우&lt;/span&gt;
git branch -D {branch_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 병합하지 못한 브랜치 강제 삭제&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 브랜치 이동&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# 이동 전 반드시 현재 브랜치의 변경사항을 기록할 것&lt;/span&gt;
git switch {branch_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 이미 있는 브랜치로 이동&lt;/span&gt;
git switch -c {branch_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 이름의 브랜치를 생성 후 이동&lt;/span&gt;
git switch -c {branch_name} {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 특정 커밋 지점을 기준점으로 하는 해당 이름의 브랜치를 생성 후 이동&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git Merge&lt;/h2&gt;
&lt;p&gt;合并分支的过程&lt;/p&gt;
&lt;h3&gt;合并类型&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Fast-Forward：将分支指向的提交移至最前端&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;三向合并（3-Way Merge）：使用各分支的两个最新提交 + 两个分支的共同祖先进行合并&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;合并冲突：当修改了相同的文件时会发生冲突 =&amp;gt; 解决冲突后进行三向合并&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 해당 브랜치를 현재 위치한 브랜치에 병합&lt;/span&gt;
git merge {merged_branch}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git Fork&lt;/h2&gt;
&lt;p&gt;复制没有所有权的远程仓库，主要用于开源等协作对象较多的情况&lt;/p&gt;
&lt;h3&gt;我的提交反映到分叉源代码的过程&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#    원본 원격 저장소 (upstream) &amp;lt;----------- 복제본 원격 저장소 (origin)&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                \           merge request      /|&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                 \                              |&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                  \                 push branch | pull master&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                   \                            |&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                    \     ( pull upstream )     |/&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                     ------------------&amp;gt; 로컬 저장소 (user)&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;将原始仓库复制到我的远程仓库&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将该远程仓库保存到本地&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在本地创建分支进行开发，并提交相关更改&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;向原始远程仓库推送合并请求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在原始远程仓库中合并该更改&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从原始仓库拉取更新内容&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;pull upstream&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sync origin &amp;amp; pull origin&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;删除本地已合并的分支&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>[BOJ 7579，Python] 应用程序</title><link>https://www.traceoflight.dev/zh/blog/boj7579/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj7579/</guid><description>针对 BOJ 7579 &quot;应用程序 &quot;问题的 Python 解决方案</description><pubDate>Fri, 28 Oct 2022 10:13:23 GMT</pubDate><content:encoded>&lt;h3&gt;问题链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;@@tlp1@@&quot;&gt;boj 7579&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;动态编程 (DP)、Knapsack 问题&lt;/p&gt;
&lt;h3&gt;描述&lt;/h3&gt;
&lt;p&gt;我个人认为，解决这个问题最重要的是问题条件。&lt;/p&gt;
&lt;p&gt;使用中的内存字节数条件是 10^7，活动应用程序的数量必须最多为 100，成本必须小于或等于 100。&lt;/p&gt;
&lt;p&gt;使用内存字节条件来检查误报率的范围非常大，因此我决定将成本设置为相应的变量，为每个成本分配一个地址，并记录我可以节省的内存量。&lt;/p&gt;
&lt;p&gt;我推断这里应该使用 DP，并进一步设计了一个使用 knapsack 算法的解决方案，该算法使用代价和值，当值存在时，根据值更新现有值。&lt;/p&gt;
&lt;h4&gt;求解代码&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 앱&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-comment&quot;&gt;# 앱 갯수, 필요 메모리 입력&lt;/span&gt;
app_number, need_memory = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

&lt;span class=&quot;hljs-comment&quot;&gt;# 각 앱의 메모리와 비활성화 시의 비용 입력&lt;/span&gt;
app_memories = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))
disable_costs = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))

&lt;span class=&quot;hljs-comment&quot;&gt;# 앱의 메모리와 비용 합쳐서 짝을 지어줌&lt;/span&gt;
memories_and_costs = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;zip&lt;/span&gt;(app_memories, disable_costs))

&lt;span class=&quot;hljs-comment&quot;&gt;# 최대 필요 비용 연산&lt;/span&gt;
sum_cost = &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;(disable_costs)

&lt;span class=&quot;hljs-comment&quot;&gt;# 각 비용별 최대 절약 가능한 메모리 리스트 선언&lt;/span&gt;
cost_list = [&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(sum_cost + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]

&lt;span class=&quot;hljs-comment&quot;&gt;# Knapsack Algorithm&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 모든 앱에 대해 확인&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; now_memory, now_cost &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; memories_and_costs:

    &lt;span class=&quot;hljs-comment&quot;&gt;# 최대 필요 비용까지 조사&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; last_cost &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(sum_cost, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):

        &lt;span class=&quot;hljs-comment&quot;&gt;# 최대 비용을 넘지 않는 선에서 확인&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; last_cost + now_cost &amp;lt;= sum_cost:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 기존 최대값보다 컸다면 갱신&lt;/span&gt;
            cost_list[last_cost + now_cost] = &lt;span class=&quot;hljs-built_in&quot;&gt;max&lt;/span&gt;(
                cost_list[last_cost + now_cost], cost_list[last_cost] + now_memory
            )

&lt;span class=&quot;hljs-comment&quot;&gt;# 비용을 0에서부터 조사해서 기준 메모리 이상을 절약한 경우의 비용을 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(sum_cost + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; cost_list[idx] &amp;gt;= need_memory:
        &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(idx)
        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 15683, Python] 监视</title><link>https://www.traceoflight.dev/zh/blog/boj15683/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/boj15683/</guid><description>BOJ 15683，“监视”题的 Python 解法</description><pubDate>Sun, 23 Oct 2022 10:46:34 GMT</pubDate><content:encoded>&lt;h3&gt;题目链接&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/15683&quot;&gt;BOJ 15683&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;分类&lt;/h3&gt;
&lt;p&gt;暴力搜索算法（bruteforcing）、实现（implementation）、模拟（simulation）&lt;/p&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;p&gt;虽然该题的分类属于暴力搜索算法，但在实现过程中使用了回溯算法。&lt;/p&gt;
&lt;p&gt;基本思路是遍历所有监控摄像头可见的方向，当所有监控摄像头的方向设置完成后，调用函数检查监控盲区的数量，如果该数值小于当前最小值，则更新该数值。&lt;/p&gt;
&lt;p&gt;由于我习惯在完成解题后立即添加注释，因此后续的博文中，详细的解题方法也将包含在代码注释中。&lt;/p&gt;
&lt;h3&gt;解法代码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 감시&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;check_blind_spot&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;matrix: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, y_range: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, x_range: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    현재 사무실 내 사각지대 갯수를 반환하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 사각지대 변수 선언&lt;/span&gt;
    blind_here = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 좌표에 대해서 조사&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; y_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(y_range):
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; x_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(x_range):

            &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 좌표값이 0일 경우만 카운팅&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; matrix[y_idx][x_idx]:
                blind_here += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 결과 반환&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; blind_here

&lt;span class=&quot;hljs-comment&quot;&gt;# 사무실 가로 및 세로 크기 입력&lt;/span&gt;
height, width = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

&lt;span class=&quot;hljs-comment&quot;&gt;# CCTV 정보 및 사무실 정보를 담을 리스트 선언&lt;/span&gt;
cctvs = []
work_space = []

&lt;span class=&quot;hljs-comment&quot;&gt;# 초기 사각지대 갯수 확인&lt;/span&gt;
blind_spot = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 사무실 정보 입력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; y_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(height):

    &lt;span class=&quot;hljs-comment&quot;&gt;# 행 정보 확인&lt;/span&gt;
    temp = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

    &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 요소들에 대해 조사&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; x_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(width):

        &lt;span class=&quot;hljs-comment&quot;&gt;# 만약 CCTV가 있다면 리스트에 추가&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; temp[x_idx] &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;12345&amp;#x27;&lt;/span&gt;:
            cctvs.append(((y_idx, x_idx), &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(temp[x_idx])))

        &lt;span class=&quot;hljs-comment&quot;&gt;# CCTV도 아니고 벽도 아니라면 초기 사각지대&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; temp[x_idx] == &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0&amp;#x27;&lt;/span&gt;:
                blind_spot += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 행 정보를 리스트에 추가&lt;/span&gt;
    work_space.append(&lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;lambda&lt;/span&gt; x: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(x), temp)))

&lt;span class=&quot;hljs-comment&quot;&gt;# CCTV 갯수 변수 선언&lt;/span&gt;
cctv_amount = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(cctvs)

&lt;span class=&quot;hljs-comment&quot;&gt;# CCTV 방향 정보 딕셔너리 선언&lt;/span&gt;
cctv_directions = {
    &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: [(-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]},
    &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]},
    &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)]},
    &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]},
    &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]},
}

&lt;span class=&quot;hljs-comment&quot;&gt;# 각 CCTV의 방향 정보를 담은 리스트 선언&lt;/span&gt;
max_direction = [&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;dummy&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]

&lt;span class=&quot;hljs-comment&quot;&gt;# CCTV가 존재하지 않는 경우 기존 사각지대의 갯수를 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; cctv_amount:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(blind_spot)

&lt;span class=&quot;hljs-comment&quot;&gt;# 만약 존재한다면 CCTV 방향에 따른 사각지대의 갯수를 조사&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

    &lt;span class=&quot;hljs-comment&quot;&gt;# 최종 사각지대 갯수 변수 선언&lt;/span&gt;
    result = blind_spot

    &lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;min_blind_spot&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;field: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, cctv_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, sight: &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt;, max_direction: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;,
                       now_cctv: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, y_range: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = height, x_range: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = width,
                       limit_cctv: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = cctv_amount&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
        CCTV를 모두 최적의 상태로 설치할 때 최소 사각지대 갯수를 확인하는 함수
        &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 결과값 전역 변수 등록&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;global&lt;/span&gt; result

        &lt;span class=&quot;hljs-comment&quot;&gt;# Back Tracking&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 CCTV를 전부 확인한 경우&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_cctv == limit_cctv:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 사각지대 갯수 확인&lt;/span&gt;
            now_result = check_blind_spot(field, y_range, x_range)

            &lt;span class=&quot;hljs-comment&quot;&gt;# 기존 최소값보다 작은 경우 갱신&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; result &amp;gt; now_result:
                result = now_result

            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 아직 확인하지 않은 CCTV가 존재하는 경우&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 확인할 CCTV 정보 확인&lt;/span&gt;
            cctv_idx, cctv_type = cctv_list[now_cctv]

            &lt;span class=&quot;hljs-comment&quot;&gt;# 좌표 분리&lt;/span&gt;
            y_cctv, x_cctv = cctv_idx

            &lt;span class=&quot;hljs-comment&quot;&gt;# CCTV에 종류에 따라 감시 방향의 경우의 수만큼 조사&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; direction_code &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(max_direction[cctv_type]):

                &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 주시 방향 확인&lt;/span&gt;
                cctv_directions_now = sight[cctv_type][direction_code]

                &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 주시 방향에서 볼 수 있는 좌표를 담을 리스트 선언&lt;/span&gt;
                now_view = []

                &lt;span class=&quot;hljs-comment&quot;&gt;# 깊이 탐색을 진행할 방향 설정&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; direction &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; cctv_directions_now:

                    &lt;span class=&quot;hljs-comment&quot;&gt;# 이동 방향 좌표 분리&lt;/span&gt;
                    move_y, move_x = direction

                    &lt;span class=&quot;hljs-comment&quot;&gt;# 초기 좌표 설정&lt;/span&gt;
                    now_y, now_x = y_cctv, x_cctv

                    &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 방향에 대해서 반복 조사&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;:

                        next_y, next_x = now_y + move_y, now_x + move_x

                        &lt;span class=&quot;hljs-comment&quot;&gt;# 사무실 범위를 벗어나지 않은 경우&lt;/span&gt;
                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;lt;= next_y &amp;lt; y_range &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;lt;= next_x &amp;lt; x_range:

                            &lt;span class=&quot;hljs-comment&quot;&gt;# 벽을 만났다면 반복 종료&lt;/span&gt;
                            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; field[next_y][next_x] == &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;:
                                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

                            &lt;span class=&quot;hljs-comment&quot;&gt;# 벽을 만난 것이 아닐 경우&lt;/span&gt;
                            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

                                &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 좌표가 사각지대일 경우&lt;/span&gt;
                                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; field[next_y][next_x]:

                                    &lt;span class=&quot;hljs-comment&quot;&gt;# 리스트에 기록 후 비사각지대 처리&lt;/span&gt;
                                    now_view.append((next_y, next_x))
                                    field[next_y][next_x] = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;#&amp;#x27;&lt;/span&gt;

                                &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 좌표 갱신&lt;/span&gt;
                                now_y, now_x = next_y, next_x

                        &lt;span class=&quot;hljs-comment&quot;&gt;# 사무실 범위를 벗어났다면 반복 종료&lt;/span&gt;
                        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
                            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

                &lt;span class=&quot;hljs-comment&quot;&gt;# 수집한 좌표들을 다음 CCTV에 조사&lt;/span&gt;
                min_blind_spot(field, cctvs, cctv_directions, max_direction, now_cctv + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

                &lt;span class=&quot;hljs-comment&quot;&gt;# 초기화&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; y_idx, x_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; now_view:
                    field[y_idx][x_idx] = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 함수를 호출하여 결과 도출&lt;/span&gt;
    min_blind_spot(work_space, cctvs, cctv_directions, max_direction)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 결과값 출력&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>第一篇</title><link>https://www.traceoflight.dev/zh/blog/intro/</link><guid isPermaLink="true">https://www.traceoflight.dev/zh/blog/intro/</guid><description>开设这个博客的原因</description><pubDate>Sat, 22 Oct 2022 18:26:40 GMT</pubDate><content:encoded>&lt;p&gt;以前，我都是把笔记整理成个人专用的，只供自己查看。&lt;/p&gt;
&lt;p&gt;但后来我开始思考：既然如此，那还有必要费心把它整理得那么漂亮吗？于是，在“精心整理后发布到显眼处”与“草草记下后发布到显眼处”之间，我选择了后者。&lt;/p&gt;
&lt;p&gt;希望我学习并整理的内容，不仅能对我自己有所帮助，也能对可能读到这篇文章的其他人有所裨益。&lt;/p&gt;
</content:encoded></item></channel></rss>