<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>可可西里-博客</title>
  
  <subtitle>好好吃饭 好好睡觉 好好上班</subtitle>
  <link href="https://huajun-chen.github.io/atom.xml" rel="self"/>
  
  <link href="https://huajun-chen.github.io/"/>
  <updated>2023-04-01T05:43:43.809Z</updated>
  <id>https://huajun-chen.github.io/</id>
  
  <author>
    <name>可可西里</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>岗位面试</title>
    <link href="https://huajun-chen.github.io/2023/03/05/%E5%B2%97%E4%BD%8D%E9%9D%A2%E8%AF%95/"/>
    <id>https://huajun-chen.github.io/2023/03/05/%E5%B2%97%E4%BD%8D%E9%9D%A2%E8%AF%95/</id>
    <published>2023-03-05T03:13:45.000Z</published>
    <updated>2023-04-01T05:43:43.809Z</updated>
    
    <content type="html"><![CDATA[<p>与后端有关的不同的岗位要求面试题整理</p><h4 id="1-调度相关"><a href="#1-调度相关" class="headerlink" title="1. 调度相关"></a><font color=DarkOrange>1. 调度相关</font></h4><h5 id="1-1-调度系统有哪些，主流调度系统的异同点"><a href="#1-1-调度系统有哪些，主流调度系统的异同点" class="headerlink" title="1.1 调度系统有哪些，主流调度系统的异同点"></a><font color=DarkOrange>1.1 调度系统有哪些，主流调度系统的异同点</font></h5><p>调度系统是一种可以自动安排和管理任务的软件工具，它可以帮助用户在一组计算机资源上执行任务，并监控这些任务的执行情况，以确保任务按时完成</p><p><strong>主流调度系统：</strong></p><ol><li><p>Kubernetes</p><p>Kubernetes是一个用于容器编排的开源平台，它可以自动化部署、扩展和管理容器化应用程序。Kubernetes使用Pods作为部署和管理的基本单位，并提供了丰富的API接口，方便进行扩展和集成其他工具和服务。Kubernetes的优点包括高度可扩展、强大的API接口和控制器、良好的社区支持等。但是，它的学习曲线比较陡峭，需要一定的学习成本。</p></li><li><p>Apache Mesos</p><p>Mesos是一个高度可扩展的分布式系统内核，可以用于管理和调度多个应用程序框架。Mesos支持多种任务类型，并提供了API接口和命令行工具，方便进行扩展和管理。Mesos的优点包括高度可扩展、支持多种任务类型、良好的社区支持等。但是，它的配置比较繁琐，需要一定的技术水平</p></li><li><p>Docker Swarm</p><p>Docker Swarm是一个轻量级的容器编排工具，用于管理和调度Docker容器。它具有简单易用、集成性强等特点，适合小型或中小型部署。但是，Docker Swarm不支持多种任务类型，可扩展性比Kubernetes差。</p></li><li><p>Nomad</p><p>Nomad是一个现代化的应用程序调度器和编排器，支持多种类型的任务，包括容器、批处理、周期性作业等。Nomad提供了API接口和CLI工具，方便进行扩展和管理。Nomad的优点包括支持多种任务类型、易于部署和管理等。但是，它的社区支持不如Kubernetes和Mesos</p></li></ol><p><strong>调度系统对比：</strong></p><ol><li><p>Kubernetes vs Mesos</p><p>Kubernetes和Mesos是目前比较受欢迎的调度系统。它们都可以用于部署和管理容器，但两者有些许区别</p><ul><li>Kubernetes: 是一个基于容器的开源平台，支持自动化部署、扩展和管理容器化应用程序。Kubernetes使用Pods作为部署和管理的基本单位。它还提供了丰富的API接口，可以方便地扩展和集成其他工具和服务</li><li>Mesos: 是一个高度可扩展的分布式系统内核，可以用于管理和调度多个应用程序框架。Mesos支持多种任务类型，并提供了API接口和命令行工具，可以方便地进行扩展和管理</li></ul></li><li><p>Kubernetes vs Docker Swarm</p><p>Kubernetes和Docker Swarm都是用于部署和管理容器的调度系统，但两者有一些明显的区别</p><ul><li>Kubernetes: 是一个高度可扩展的平台，可以支持多种容器和非容器应用程序。它还提供了多种API接口和控制器，可以方便地进行自定义配置和扩展</li><li>Docker Swarm: 是一个轻量级的容器编排工具，主要用于管理和调度Docker容器。它具有简单易用、集成性强等特点，适合小型或中小型部署。但Docker Swarm不支持多种任务类型，并且可扩展性比Kubernetes差</li></ul></li></ol><p><strong>总结：</strong>如果需要高度可扩展和强大的API接口和控制器，可以选择Kubernetes或Mesos；如果需要简单易用和集成性强，可以选择Docker Swarm；如果需要支持多种任务类型，可以选择Nomad</p><h5 id="1-2-请解释下什么是任务调度，并举例说明一下任务调度的应用场景"><a href="#1-2-请解释下什么是任务调度，并举例说明一下任务调度的应用场景" class="headerlink" title="1.2 请解释下什么是任务调度，并举例说明一下任务调度的应用场景"></a><font color=DarkOrange>1.2 请解释下什么是任务调度，并举例说明一下任务调度的应用场景</font></h5><p>任务调度是指按照预定的计划或规则，自动地调度和执行各种任务的过程。任务调度系统通常是一个计算机程序或服务，它可以根据特定的需求、优先级和时间窗口来分配和管理计算机资源和任务</p><p>任务调度系统的应用场景非常广泛，例如：</p><ol><li>数据备份和数据清理：数据备份和数据清理通常需要定期执行，而任务调度系统可以自动地定期执行这些任务，减少人工干预，提高效率</li><li>系统维护和监控：任务调度系统可以定期执行系统维护任务，例如清理缓存、更新软件、优化数据库等等。同时，它还可以执行系统监控任务，例如检查服务器负载、监控日志等等</li><li>批处理和数据处理：许多企业需要处理大量的数据，例如批量生成报告、数据清洗、数据导入导出等等。任务调度系统可以自动执行这些任务，减少人工干预，提高效率</li><li>任务队列和消息队列：任务调度系统可以将任务加入到队列中，并根据一定的规则和优先级自动地分配和执行任务</li><li>负载均衡和资源管理：任务调度系统可以根据资源的使用情况和任务的需求，自动地分配和管理计算机资源，以达到负载均衡和资源优化的目的</li></ol><p>举例来说，一个电商网站需要定期生成销售报告、清理无效数据、更新商品库存等等任务，而这些任务可以通过一个任务调度系统来自动执行，减少人工干预，提高效率和准确性。同时，任务调度系统还可以根据网站的访问量和服务器的负载情况，自动地分配和管理服务器资源，以达到负载均衡和资源优化的目的</p><h5 id="1-3-如何保证调度任务的可靠性和容错性"><a href="#1-3-如何保证调度任务的可靠性和容错性" class="headerlink" title="1.3 如何保证调度任务的可靠性和容错性"></a><font color=DarkOrange>1.3 如何保证调度任务的可靠性和容错性</font></h5><p>保证调度任务的可靠性和容错性是一个任务调度系统中非常重要的问题，以下是一些常用的技术和方法：</p><ol><li>异常处理和日志记录：当任务执行出现异常或错误时，需要对异常进行捕获和处理，同时记录日志以便后续查找和分析问题</li><li>任务依赖和优先级：任务之间可能存在依赖关系，例如任务 A 必须在任务 B 完成后才能执行，这时需要对任务的依赖关系进行建模，并按照优先级进行调度</li><li>任务重试和超时处理：当任务执行失败或超时时，可以尝试重新执行任务，同时设置重试次数和超时时间</li><li>任务状态和心跳监测：任务状态和心跳监测可以帮助系统及时发现任务执行状态，并进行相应的处理和调度</li><li>集群化和高可用：将任务调度系统部署在多台服务器上，采用集群化和高可用技术，可以保证系统的稳定性和可靠性</li><li>容器化和自动化部署：采用容器化技术和自动化部署工具，可以快速部署和管理任务调度系统，同时提高系统的可靠性和容错性</li><li>测试和验证：对任务调度系统进行充分的测试和验证，包括单元测试、集成测试、性能测试等等，可以帮助发现和解决系统的问题，提高系统的可靠性和容错性</li></ol><p>综上所述，保证任务调度系统的可靠性和容错性需要综合考虑各种技术和方法，并根据具体场景进行相应的设计和实现</p><h5 id="1-4-什么是调度算法，举例说明一下几种常见的调度算法"><a href="#1-4-什么是调度算法，举例说明一下几种常见的调度算法" class="headerlink" title="1.4 什么是调度算法，举例说明一下几种常见的调度算法"></a><font color=DarkOrange>1.4 什么是调度算法，举例说明一下几种常见的调度算法</font></h5><p>调度算法是指在任务调度系统中，为了提高任务执行效率和资源利用率而采用的一系列算法。调度算法通常会考虑任务的优先级、资源的限制、任务的依赖关系等因素，来实现对任务的合理分配和调度。下面是几种常见的调度算法：</p><ol><li>先来先服务（First-Come, First-Served，简称 FCFS）调度算法：任务按照到达时间的先后顺序进行调度，先到达的任务先执行，后到达的任务后执行</li><li>最短作业优先（Shortest Job First，简称 SJF）调度算法：任务按照执行时间的长短顺序进行调度，执行时间短的任务先执行，执行时间长的任务后执行</li><li>优先级调度（Priority Scheduling）算法：任务按照优先级进行调度，优先级高的任务先执行，优先级低的任务后执行</li><li>时间片轮转（Round Robin）调度算法：将任务分配一个固定的时间片，每个任务在时间片内进行执行，时间片用完之后，就将任务放回队列，等待下一次调度</li><li>最短剩余时间优先（Shortest Remaining Time Next，简称 SRTN）调度算法：任务按照执行时间的长短和剩余时间的多少进行调度，剩余时间少的任务先执行，剩余时间多的任务后执行</li><li>最高响应比优先（Highest Response Ratio Next，简称 HRRN）调度算法：任务按照响应比进行调度，响应比是指任务等待时间加上执行时间除以执行时间，响应比高的任务先执行，响应比低的任务后执行</li></ol><p>举例来说，假设有三个任务需要执行，它们的执行时间和优先级如下表所示：</p><table><thead><tr><th>任务名称</th><th>执行时间</th><th>优先级</th></tr></thead><tbody><tr><td>任务 A</td><td>4</td><td>1</td></tr><tr><td>任务 B</td><td>2</td><td>2</td></tr><tr><td>任务 C</td><td>3</td><td>3</td></tr></tbody></table><p>对于这个例子，采用不同的调度算法会有不同的执行顺序和效率。例如，对于 FCFS 算法，任务的执行顺序为 A-&gt;B-&gt;C，总执行时间为 9；对于 SJF 算法，任务的执行顺序为 B-&gt;C-&gt;A，总执行时间为 6；对于 HRRN 算法，任务的执行顺序为 B-&gt;C-&gt;A，总执行时间为 6。可以看出，不同的调度算法会对任务的执行效率产生很大的影响，需要根据具体场景进行选择和优化</p><h5 id="1-5-分布式调度系统的设计和实现"><a href="#1-5-分布式调度系统的设计和实现" class="headerlink" title="1.5 分布式调度系统的设计和实现"></a><font color=DarkOrange>1.5 分布式调度系统的设计和实现</font></h5><p>分布式调度系统是一个用于管理和调度分布式计算资源的系统，它可以在分布式环境中自动地分配和管理任务，优化资源利用率，并确保任务的可靠执行。下面是一个分布式调度系统的设计和实现步骤：</p><ol><li>架构设计：设计分布式调度系统的架构，确定系统的组成部分，如调度器、节点管理器、资源管理器等。架构设计需要考虑系统的可伸缩性、可靠性、安全性等方面，保证系统能够在大规模分布式环境中高效运行</li><li>数据模型设计：设计数据模型，包括任务模型、资源模型、节点模型等。数据模型需要支持分布式存储和访问，保证数据的可靠性和高效性</li><li>调度算法设计：根据具体需求和场景，选择合适的调度算法，如最短作业优先、最高响应比优先等，以实现任务的高效分配和调度</li><li>接口设计：设计系统的接口，包括用户接口和程序接口。用户接口需要提供任务提交、查询等功能，程序接口需要提供任务调度、资源管理等功能</li><li>节点管理器实现：实现节点管理器，负责管理分布式节点的状态和资源，包括节点的注册、心跳、资源分配等</li><li>资源管理器实现：实现资源管理器，负责管理系统的资源，如 CPU、内存、磁盘、网络等，包括资源的分配、释放、回收等</li><li>调度器实现：实现调度器，负责任务的调度和分配，根据任务的优先级、资源的限制、任务的依赖关系等因素，选择合适的节点和资源，以实现任务的高效执行</li><li>监控和日志记录：实现系统的监控和日志记录，包括任务执行状态、节点状态、资源使用情况等，以便及时发现和解决问题</li><li>集成测试和性能测试：进行集成测试和性能测试，验证系统的功能和性能，以保证系统的正确性和稳定性</li></ol><p>总体来说，分布式调度系统的设计和实现需要综合考虑系统的架构、数据模型、调度算法、节点管理、资源管理、调度器实现等方面，以满足分布式环境中的任务调度和管理需求</p><h4 id="2-存储相关"><a href="#2-存储相关" class="headerlink" title="2. 存储相关"></a><font color=DarkOrange>2. 存储相关</font></h4><h5 id="2-1-数据存储方式有哪些，并举例说明它们的优缺点"><a href="#2-1-数据存储方式有哪些，并举例说明它们的优缺点" class="headerlink" title="2.1 数据存储方式有哪些，并举例说明它们的优缺点"></a><font color=DarkOrange>2.1 数据存储方式有哪些，并举例说明它们的优缺点</font></h5><p>数据存储方式主要包括关系型数据库、非关系型数据库、文件系统和内存数据库等。下面是它们的优缺点及举例说明：</p><ol><li><p>关系型数据库</p><p> 优点：</p><ul><li>支持 SQL，易于查询和操作</li><li>数据结构清晰，支持 ACID 事务</li><li>能够保证数据一致性和完整性</li><li>可以存储复杂的数据关系</li></ul><p> 缺点：</p><ul><li>难以处理海量数据</li><li>性能不如非关系型数据库</li><li>需要花费较多时间和资源进行表设计和数据规范化</li></ul><p> 举例：MySQL、Oracle、SQL Server等</p><hr></li><li><p>非关系型数据库</p><p> 优点：</p><ul><li>高性能，适合处理海量数据</li><li>支持分布式，容易实现高可用性</li><li>可扩展性好，支持动态添加节点</li><li>适合存储非结构化和半结构化数据</li></ul><p> 缺点：</p><ul><li>不支持 SQL，查询需要编写程序</li><li>数据一致性和完整性无法保证</li><li>不支持事务</li></ul><p> 举例：MongoDB、Cassandra、Redis等</p><hr></li><li><p>文件系统</p><p> 优点：</p><ul><li>支持任意数据格式，适合存储大量文本和二进制文件</li><li>易于使用和备份</li><li>能够处理大量数据和高并发访问</li></ul><p> 缺点：</p><ul><li>不支持事务和复杂查询</li><li>难以保证数据的一致性和完整性</li><li>不适合存储结构化数据</li></ul><p> 举例：NTFS、EXT4等</p><hr></li><li><p>内存数据库</p><p> 优点：</p><ul><li>高速，数据存储在内存中，能够快速读写</li><li>支持事务，能够保证数据的一致性和完整性</li><li>支持复杂查询和高并发访问</li></ul><p> 缺点：</p><ul><li>数据容量有限，不适合存储海量数据</li><li>内存数据库的开销比较大，不适合存储小数据</li></ul><p> 举例：Redis、Memcached等</p><hr></li></ol><p>不同的数据存储方式各有优缺点，应根据实际需求选择合适的数据存储方式。例如，对于需要高效处理大量结构化数据的应用场景，可以选择关系型数据库；对于需要高性能处理非结构化数据的应用场景，可以选择非关系型数据库；对于需要存储大量文本和二进制文件的应用场景，可以选择文件系统；对于需要快速读写数据和保证数据一致性和完整性的应用场景，可以选择内存数据库</p><h5 id="2-2-如何设计一种高性能、高可靠性的分布式存储系统"><a href="#2-2-如何设计一种高性能、高可靠性的分布式存储系统" class="headerlink" title="2.2 如何设计一种高性能、高可靠性的分布式存储系统"></a><font color=DarkOrange>2.2 如何设计一种高性能、高可靠性的分布式存储系统</font></h5><ol><li>数据分布策略：数据如何在不同的节点之间分配是非常重要的。在分布式存储系统中，通常采用哈希函数对数据进行分片，然后将每个数据分片存储在不同的节点上。这样可以保证数据的负载均衡和高可用性</li><li>数据副本备份：为了保证数据的高可靠性，在设计分布式存储系统时通常需要采用数据副本备份的策略。当某个节点发生故障时，系统可以从其他节点中获取数据副本来保证数据的可用性。同时，还需要考虑如何在不同的节点之间同步数据，以避免数据不一致的问题</li><li>存储介质的选择：在设计分布式存储系统时，需要选择合适的存储介质来存储数据。不同的存储介质有不同的特点，例如磁盘、SSD、内存等。需要根据不同的应用场景选择合适的存储介质</li><li>网络传输的优化：在分布式存储系统中，数据的传输是非常重要的。需要优化网络传输协议，减少数据传输的延迟和带宽占用</li><li>集群管理和监控：在设计分布式存储系统时，需要考虑如何进行集群管理和监控。需要实现集群节点的自动发现和管理，以及对集群状态和性能的监控和调优</li><li>安全性：在设计分布式存储系统时，需要考虑数据的安全性问题。需要采用加密技术对数据进行保护，以防止数据泄露或被篡改</li></ol><p><strong>总结：</strong>设计一个高性能、高可靠性的分布式存储系统需要综合考虑数据分布策略、数据副本备份、存储介质的选择、网络传输的优化、集群管理和监控以及安全性等方面的因素。同时，需要不断进行性能测试和优化，以保证系统的高性能和可靠性</p><h5 id="2-3-什么是一致性哈希算法，以及在分布式存储系统中的应用场景"><a href="#2-3-什么是一致性哈希算法，以及在分布式存储系统中的应用场景" class="headerlink" title="2.3 什么是一致性哈希算法，以及在分布式存储系统中的应用场景"></a><font color=DarkOrange>2.3 什么是一致性哈希算法，以及在分布式存储系统中的应用场景</font></h5><p>一致性哈希算法（Consistent Hashing）是一种用于缓存和分布式系统中数据分布的算法，它通过将数据映射到一个哈希环上来实现数据的分布</p><p>具体来说，一致性哈希算法将一个哈希环分成一些小的区间，每个区间对应一个节点。当需要存储一个数据时，首先对数据进行哈希操作，然后将哈希结果映射到哈希环上，最终将数据存储在距离它最近的节点上</p><p>在一致性哈希算法中，如果有一个节点故障或者新加入了一个节点，那么只会对它附近的节点造成影响，其他节点的数据分布不会改变。这种特性使得一致性哈希算法在动态增减节点的分布式存储系统中具有很好的可扩展性和负载均衡性</p><p>在分布式存储系统中，一致性哈希算法通常被用于数据分片和数据节点的选择。通过一致性哈希算法，可以将数据均匀地分布到不同的存储节点上，并且在节点故障或新增节点时，能够保持数据的分布不变，从而实现高可用性和负载均衡</p><p>一致性哈希算法还可以用于缓存系统中，通过将缓存数据分布到不同的缓存节点上，提高缓存系统的性能和可用性。在一些互联网应用中，如分布式文件系统、分布式数据库、CDN（内容分发网络）等，一致性哈希算法也得到了广泛的应用</p><h5 id="2-4-介绍下分布式文件系统的设计和实现"><a href="#2-4-介绍下分布式文件系统的设计和实现" class="headerlink" title="2.4 介绍下分布式文件系统的设计和实现"></a><font color=DarkOrange>2.4 介绍下分布式文件系统的设计和实现</font></h5><p>分布式文件系统是一种支持文件共享和管理的分布式系统，它将文件数据分布在多个节点上，可以提高系统的性能和可用性。一个典型的分布式文件系统由以下组件构成：</p><ol><li>元数据服务器：负责存储文件系统的元数据，包括文件名、文件属性、文件所在节点等信息。元数据服务器通常是单点故障，为了提高可用性，可以采用多主备份或者分布式元数据存储等策略</li><li>存储节点：负责存储文件的实际数据。存储节点通常由多个节点组成，可以实现数据的冗余备份和负载均衡</li><li>客户端：负责向分布式文件系统发送请求，包括文件的读取、写入、删除等操作。客户端通常需要具备缓存、负载均衡、故障恢复等功能</li></ol><p>在分布式文件系统的设计和实现中，需要考虑以下几个方面：</p><ol><li>数据分布策略：文件数据如何在不同的节点之间分配是非常重要的。通常采用哈希函数对文件进行分片，然后将每个文件分片存储在不同的节点上。这样可以保证数据的负载均衡和高可用性</li><li>数据副本备份：为了保证数据的高可靠性，在设计分布式文件系统时通常需要采用数据副本备份的策略。当某个节点发生故障时，系统可以从其他节点中获取数据副本来保证数据的可用性</li><li>网络传输的优化：在分布式文件系统中，数据的传输是非常重要的。需要优化网络传输协议，减少数据传输的延迟和带宽占用</li><li>集群管理和监控：在设计分布式文件系统时，需要考虑如何进行集群管理和监控。需要实现集群节点的自动发现和管理，以及对集群状态和性能的监控和调优</li><li>安全性：在设计分布式文件系统时，需要考虑数据的安全性问题。需要采用加密技术对数据进行保护，以防止数据泄露或被篡改</li></ol><p><strong>总结：</strong>分布式文件系统的设计和实现需要综合考虑数据分布策略、数据副本备份、网络传输的优化、集群管理和监控以及安全性等方面的因素。同时，需要不断进行性能测试和优化，以保证系统的高性能和可靠性</p><h5 id="2-5-什么是数据冗余，以及在存储系统中的应用场景"><a href="#2-5-什么是数据冗余，以及在存储系统中的应用场景" class="headerlink" title="2.5 什么是数据冗余，以及在存储系统中的应用场景"></a><font color=DarkOrange>2.5 什么是数据冗余，以及在存储系统中的应用场景</font></h5><p>数据冗余指的是存储系统中同一份数据被存储多次的情况。冗余数据的存在可以提高存储系统的可靠性、容错性和性能。在存储系统中，通常会采用以下几种数据冗余的方式：</p><ol><li>数据备份：将数据备份到另外一台或多台设备上，以防止数据丢失或损坏。备份数据通常是完整的数据拷贝，可以在主数据损坏或丢失时快速恢复数据</li><li>RAID技术：RAID技术是一种将多个硬盘组合起来提供更高性能和可靠性的技术。RAID技术的主要思想是将数据划分成多个块，分别存储在多个硬盘上，同时提供数据校验和容错机制</li><li>冗余数据存储：将数据冗余存储在多个设备上，以提高数据的可靠性和容错性。冗余数据存储通常采用多个备份节点、多个存储节点等方式</li></ol><p>数据冗余在存储系统中的应用场景主要有以下几种：</p><ol><li>数据备份：在企业数据中心、云存储、备份恢复等场景中，通常需要对重要数据进行备份，以防止数据丢失或损坏</li><li>数据可靠性：在存储关键业务数据时，需要保证数据的可靠性和安全性。采用数据冗余技术可以提高存储系统的容错能力和可靠性</li><li>数据可用性：在高可用性应用中，需要保证数据的快速访问和传输。采用数据冗余技术可以提高存储系统的性能和可用性，减少数据访问的延迟</li></ol><p><strong>总结：</strong>数据冗余是存储系统中的一种重要技术，它可以提高系统的可靠性、容错性和性能，保证存储数据的安全性和可用性</p><h4 id="3-监控相关"><a href="#3-监控相关" class="headerlink" title="3. 监控相关"></a><font color=DarkOrange>3. 监控相关</font></h4><h5 id="3-1-介绍下系统监控的基本原理和常见的监控手段"><a href="#3-1-介绍下系统监控的基本原理和常见的监控手段" class="headerlink" title="3.1 介绍下系统监控的基本原理和常见的监控手段"></a><font color=DarkOrange>3.1 介绍下系统监控的基本原理和常见的监控手段</font></h5><p>系统监控是一种通过收集和分析系统运行数据来评估系统健康状况、性能和安全性的过程。系统监控的基本原理是收集系统各个方面的性能数据，包括 CPU 使用率、内存使用率、磁盘 I&#x2F;O、网络流量等，通过分析这些数据来评估系统的状态，并识别潜在问题和性能瓶颈，进而采取必要的措施来优化系统性能、提高可用性和安全性</p><p>常见的系统监控手段包括：</p><ol><li>监控软件：常用的监控软件包括 Nagios、Zabbix、Cacti、Ganglia等，这些软件可以监控系统各个方面的性能数据，并提供相应的报告和警报</li><li>日志分析：系统日志记录了系统的操作和事件，通过对日志进行分析可以发现潜在的问题和异常情况</li><li>性能测试：性能测试可以模拟实际工作负载，评估系统的性能和响应时间</li><li>负载测试：负载测试可以模拟实际的用户访问负载，测试系统的并发性能和稳定性</li><li>安全审计：安全审计可以跟踪系统中的安全事件，包括入侵尝试、异常访问等，并提供报告和警报</li><li>实时监控：实时监控可以通过实时采集和分析系统性能数据来监测系统的状态和性能，及时发现和解决潜在问题和性能瓶颈</li></ol><p><strong>总结：</strong>系统监控是一种重要的管理和优化系统性能、提高系统可用性和安全性的手段。通过采用合适的监控手段，可以及时发现并解决系统问题，提高系统的可靠性和性能</p><h5 id="3-2-什么是指标监控，以及在系统监控中的应用场景"><a href="#3-2-什么是指标监控，以及在系统监控中的应用场景" class="headerlink" title="3.2 什么是指标监控，以及在系统监控中的应用场景"></a><font color=DarkOrange>3.2 什么是指标监控，以及在系统监控中的应用场景</font></h5><p>指标监控是指通过监测和收集各种系统指标，来评估系统的运行状况，从而能够及时发现问题和性能瓶颈。这些指标通常包括 CPU、内存、磁盘、网络、应用程序等方面的性能数据，如 CPU 使用率、内存使用率、磁盘 I&#x2F;O、网络流量、请求响应时间等等</p><p>指标监控在系统监控中有着广泛的应用场景，以下是一些典型的应用场景：</p><ol><li>实时监控系统健康状况：通过监控关键指标，能够实时监控系统的健康状况，及时发现问题，并快速进行诊断和处理，从而保障系统的稳定运行</li><li>诊断系统性能问题：指标监控可以帮助发现性能瓶颈，比如系统响应时间变慢，磁盘 I&#x2F;O 繁忙等等，从而能够帮助开发人员和运维人员快速定位问题，加速问题解决过程</li><li>帮助进行容量规划：通过收集系统资源使用情况，比如 CPU、内存、磁盘等，可以帮助系统管理员预测系统容量使用情况，从而提前规划系统的升级和扩容</li><li>支持系统自动化运维：指标监控是自动化运维的重要组成部分，通过监控和自动化脚本可以快速处理大量的运维工作，提高运维效率</li><li>提高系统安全性：指标监控可以帮助发现系统的异常行为和安全事件，比如大量的登录失败、网络攻击、异常访问等等，从而能够提高系统的安全性</li></ol><p><strong>总结：</strong>指标监控是系统监控中不可或缺的一环，通过指标监控可以实时监测系统的运行情况，及时发现问题，提高系统的可用性、性能和安全性</p><h5 id="3-3-如何实现对分布式系统的监控和故障诊断"><a href="#3-3-如何实现对分布式系统的监控和故障诊断" class="headerlink" title="3.3 如何实现对分布式系统的监控和故障诊断"></a><font color=DarkOrange>3.3 如何实现对分布式系统的监控和故障诊断</font></h5><p>要实现对分布式系统的监控和故障诊断，需要以下步骤：</p><ol><li>设计监控指标：为了对分布式系统进行监控，首先需要确定关键性能指标，例如：吞吐量、响应时间、错误率等。可以根据应用的具体情况来设计监控指标</li><li>部署监控系统：在分布式系统中，每个节点都需要部署监控代理，收集监控指标，并将数据发送到中央监控系统。中央监控系统可以是一台服务器或者是一个集群，可以使用开源工具如Prometheus、Grafana等来实现监控系统</li><li>数据存储：收集到的监控数据需要进行存储和处理，以便进行故障诊断。可以使用开源数据库如InfluxDB、Elasticsearch等来存储监控数据</li><li>数据分析和告警：对收集到的监控数据进行分析，识别异常和故障，同时触发告警机制。可以使用开源工具如Alertmanager等来实现告警机制</li><li>故障诊断和排查：当监控系统发出警报时，需要进行故障诊断和排查。可以通过分析监控数据、查看日志、跟踪请求等方式来定位故障所在，并采取相应的措施来解决问题</li><li>容灾和备份：在分布式系统中，容灾和备份也非常重要。可以使用备份系统和容灾机制来保证系统的高可用性和数据的安全性</li></ol><p><strong>总结：</strong>实现对分布式系统的监控和故障诊断需要综合考虑监控指标、监控系统、数据存储、数据分析和告警、故障排查、容灾备份等多个方面</p><h5 id="3-4-什么是日志监控，以及在系统监控中的应用场景"><a href="#3-4-什么是日志监控，以及在系统监控中的应用场景" class="headerlink" title="3.4 什么是日志监控，以及在系统监控中的应用场景"></a><font color=DarkOrange>3.4 什么是日志监控，以及在系统监控中的应用场景</font></h5><p>日志监控是指通过对系统产生的日志进行实时监控、分析和诊断，以检测系统运行状态、识别问题并做出相应的响应和调整的过程。在系统监控中，日志监控是非常重要的一环，它可以帮助我们追踪系统的状态，及时发现并解决问题，从而保证系统的稳定性和可靠性</p><p>在系统监控中，日志监控通常用于以下场景：</p><ol><li>故障分析和排查：日志监控可以帮助我们快速定位故障点，分析问题并采取措施解决问题</li><li>性能监控和优化：日志监控可以记录系统的性能数据和运行情况，及时发现性能问题，优化系统性能</li><li>安全监控和防范：日志监控可以监测系统中的异常行为，识别潜在的安全威胁，并及时采取措施防范安全风险</li><li>运营监控和优化：日志监控可以记录用户行为和操作数据，分析用户需求和行为模式，提供数据支持和决策依据，从而优化运营效率和用户体验</li></ol><p><strong>总结：</strong>日志监控在系统监控中扮演着重要的角色，可以帮助我们实时追踪系统的状态和性能，及时发现和解决问题，保证系统的高可用性和可靠性</p><h5 id="3-5-如何设计一个可扩展的监控系统"><a href="#3-5-如何设计一个可扩展的监控系统" class="headerlink" title="3.5 如何设计一个可扩展的监控系统"></a><font color=DarkOrange>3.5 如何设计一个可扩展的监控系统</font></h5><p>设计一个可扩展的监控系统，需要考虑以下几个方面：</p><ol><li>采集架构的设计：监控系统需要采集大量的监控数据，因此需要设计一个高效的数据采集架构。可以采用分布式采集、采用轮询或主动推送方式采集数据等方式</li><li>存储架构的设计：监控系统需要处理大量的监控数据，因此需要设计一个高效的数据存储架构。可以采用分布式存储、采用列存储或时序数据库等方式存储数据</li><li>数据处理的设计：监控系统需要对采集到的数据进行处理和分析，以便进行故障诊断和性能优化等操作。可以采用分布式计算框架、MapReduce等方式进行数据处理</li><li>告警机制的设计：监控系统需要根据监控数据产生告警，及时通知管理员进行处理。可以采用消息队列等方式实现告警机制，支持多种告警方式如邮件、短信、微信等</li><li>可视化的设计：监控系统需要提供可视化的监控界面，便于管理员查看监控数据和告警信息。可以采用大屏展示、图表展示等方式进行数据可视化</li><li>可扩展性的设计：监控系统需要具备可扩展性，以便应对未来的业务扩展和监控需求的变化。可以采用微服务架构、容器化等方式，支持快速部署和扩展</li></ol><p><strong>总结：</strong>设计一个可扩展的监控系统需要从采集架构、存储架构、数据处理、告警机制、可视化、可扩展性等多个方面进行考虑，以满足不同场景下的监控需求。同时，需要根据实际情况进行适当的优化和调整，以达到最佳的监控效果</p><h4 id="4-日志相关"><a href="#4-日志相关" class="headerlink" title="4. 日志相关"></a><font color=DarkOrange>4. 日志相关</font></h4><h5 id="4-1-常见的日志记录方式，并举例说明它们的优缺点"><a href="#4-1-常见的日志记录方式，并举例说明它们的优缺点" class="headerlink" title="4.1 常见的日志记录方式，并举例说明它们的优缺点"></a><font color=DarkOrange>4.1 常见的日志记录方式，并举例说明它们的优缺点</font></h5><p>常见的日志记录方式有以下几种：</p><ol><li>基于文本日志：将日志记录为文本文件的形式，使用简单，可以直接通过文本编辑器进行查看和分析。例如，Apache服务器的访问日志就是使用文本日志进行记录的。文本日志的缺点是可读性较差，不易于进行高效的数据处理和分析</li><li>基于二进制日志：将日志记录为二进制格式，可以提高日志的可读性和可处理性。例如，MySQL数据库的二进制日志就是使用二进制格式进行记录的。二进制日志的缺点是不易于进行人工查看和分析，需要使用专门的工具进行解析和处理</li><li>基于数据库日志：将日志记录到数据库中，可以方便进行数据分析和查询。例如，Java应用程序常常使用Log4j或Logback等日志框架将日志记录到数据库中。数据库日志的缺点是对数据库的性能有一定的影响，并且需要对数据库进行备份和管理</li><li>基于消息队列日志：将日志记录到消息队列中，可以实现日志的异步处理和分发。例如，Kafka等消息队列可以用于日志的收集、存储和分发。消息队列日志的缺点是需要对消息队列进行管理和维护，并且可能会增加系统的复杂度</li></ol><p><strong>总结：</strong>不同的日志记录方式都有各自的优缺点，需要根据实际情况进行选择和使用。通常情况下，基于文本日志的方式简单易用，基于数据库日志的方式方便进行数据分析，基于消息队列日志的方式可以实现异步处理和分发</p><h5 id="4-2-如何设计一个高性能、高可靠性的日志系统"><a href="#4-2-如何设计一个高性能、高可靠性的日志系统" class="headerlink" title="4.2 如何设计一个高性能、高可靠性的日志系统"></a><font color=DarkOrange>4.2 如何设计一个高性能、高可靠性的日志系统</font></h5><p>要设计一个高性能、高可靠性的日志系统，需要从以下几个方面进行考虑：</p><ol><li>日志采集：日志采集是日志系统的第一步，需要设计一个高效、可靠的数据采集架构，支持多种数据源的接入。可以采用分布式采集，通过轮询或者主动推送方式来采集日志数据，避免过度依赖日志收集代理，提高系统的可靠性和扩展性</li><li>日志存储：日志存储是日志系统的核心，需要设计一个高性能、高可靠性的存储架构，支持快速的数据查询和访问。可以采用分布式存储，支持数据的水平扩展，避免数据单点故障，提高系统的可靠性和扩展性。同时可以考虑使用高性能的时序数据库或者列存储数据库，来支持快速的数据查询和分析</li><li>数据处理：日志数据量巨大，需要设计一个高效的数据处理架构，支持快速的数据查询和分析。可以采用分布式计算框架，如Hadoop、Spark等，来进行大数据处理，避免数据的串行处理，提高数据处理的效率和性能</li><li>数据可视化：为了便于用户查看和分析日志数据，需要设计一个高可用、高可靠性的数据可视化架构。可以使用大屏展示、图表展示等方式来进行数据可视化，同时需要支持实时的数据更新和查询，提高用户的交互体验</li><li>告警机制：为了及时发现系统的异常情况，需要设计一个高效、可靠的告警机制，支持多种告警方式的接入，如邮件、短信、微信等。同时需要支持可配置的告警规则，便于管理员根据实际情况进行设置和调整</li><li>日志的安全性：日志系统中包含着大量的敏感信息，需要考虑数据的安全性和保密性。可以采用加密、身份认证等措施，保证日志数据的安全性和保密性</li></ol><p><strong>总结：</strong>设计一个高性能、高可靠性的日志系统需要从多个方面进行考虑，包括日志采集、日志存储、数据处理、数据可视化、告警机制和日志的安全性等。需要根据实际情况进行选择和使用，并进行合理的配置和优化，以达到最佳的性能和可靠性</p><h5 id="4-3-什么是日志聚合，以及在日志系统中的应用场景"><a href="#4-3-什么是日志聚合，以及在日志系统中的应用场景" class="headerlink" title="4.3 什么是日志聚合，以及在日志系统中的应用场景"></a><font color=DarkOrange>4.3 什么是日志聚合，以及在日志系统中的应用场景</font></h5><p>日志聚合是指将多个来源的日志数据集中到一个统一的地方进行存储和分析的过程。在日志系统中，日志聚合是非常重要的一环，它可以帮助用户更加方便地对系统运行状态进行监控和分析</p><p>在实际应用中，日志聚合的应用场景非常广泛，以下是一些常见的应用场景：</p><ol><li>系统监控：通过对多个系统的日志数据进行聚合，可以获得全局的系统状态，帮助管理员及时发现异常情况，并采取相应的措施来保证系统的稳定性</li><li>故障排查：当系统出现故障时，可以通过对多个系统的日志数据进行聚合分析，快速定位问题，减少排查时间，提高系统的可用性</li><li>安全监控：通过对多个系统的日志数据进行聚合，可以快速发现系统中的安全漏洞和攻击，及时采取措施来防范安全风险</li><li>性能优化：通过对多个系统的日志数据进行聚合分析，可以发现系统中存在的性能瓶颈，并采取相应的措施来优化系统性能</li><li>统计分析：通过对多个系统的日志数据进行聚合分析，可以获得全局的统计信息，帮助用户了解系统的使用情况和趋势，以便采取相应的措施来提高系统的效率和性能</li></ol><p><strong>总结：</strong>日志聚合在日志系统中具有非常重要的应用场景，可以帮助用户更加方便地对系统运行状态进行监控和分析，从而提高系统的可用性、性能和安全性</p><h5 id="4-4-如何实现对分布式系统的日志收集和分析"><a href="#4-4-如何实现对分布式系统的日志收集和分析" class="headerlink" title="4.4 如何实现对分布式系统的日志收集和分析"></a><font color=DarkOrange>4.4 如何实现对分布式系统的日志收集和分析</font></h5><p>对于分布式系统的日志收集和分析，通常需要考虑以下几个方面：</p><ol><li>选择合适的日志收集工具：常见的日志收集工具包括Logstash、Fluentd、Filebeat等，这些工具都具有不同的特点和优缺点，需要根据实际场景进行选择</li><li>定义统一的日志格式：为了方便日志的收集和分析，需要定义统一的日志格式，包括日志的字段和数据类型等，以便于后续的处理和分析</li><li>配置日志收集器：根据实际情况，配置日志收集器，包括指定日志文件的路径、过滤日志、设置采集频率等，以便于采集需要的日志数据</li><li>日志的存储和索引：采集到的日志数据需要进行存储和索引，以便于后续的查询和分析。常见的存储方式包括Elasticsearch、Hadoop等</li><li>日志的分析：采集到的日志数据需要进行分析，以便于发现系统中存在的问题，常见的分析工具包括Kibana、Splunk等</li></ol><p>在实际应用中，需要根据实际场景进行配置和调优，以提高日志收集和分析的效率和准确性。同时，为了保证分布式系统的稳定性和可用性，需要采用高可用和容错的技术，例如使用多个日志收集器进行采集、采用主从复制的方式进行数据备份等</p><h5 id="4-5-分布式日志系统的设计和实现"><a href="#4-5-分布式日志系统的设计和实现" class="headerlink" title="4.5 分布式日志系统的设计和实现"></a><font color=DarkOrange>4.5 分布式日志系统的设计和实现</font></h5><p>分布式日志系统的设计和实现可以分为以下几个方面：</p><ol><li>日志收集：分布式系统中的日志数据通常会分散在多个节点上，需要采用合适的工具进行日志的收集。常见的工具包括Fluentd、Logstash、Filebeat等。可以根据实际情况选择合适的工具进行日志收集，并配置相关参数以便于实现高效的日志收集</li><li>数据传输和存储：收集到的日志数据需要进行传输和存储，通常可以采用消息队列的方式进行传输，例如使用Kafka、RabbitMQ等。在存储方面，常见的方案包括使用Elasticsearch、Hadoop等，以便于实现高效的数据存储和检索</li><li>数据处理和分析：分布式日志系统的设计需要考虑到数据处理和分析的问题，例如数据清洗、格式化、归一化等。可以采用流处理技术进行数据处理和分析，例如使用Spark、Storm等技术，以便于实现高效的数据处理和分析</li><li>查询和展示：分布式日志系统需要提供高效的查询和展示功能，例如使用Kibana、Grafana等工具进行数据展示和可视化。同时，需要考虑到分布式系统的复杂性，采用合适的查询技术进行查询，例如使用分布式搜索引擎技术等</li><li>容错和可扩展性：为了保证分布式日志系统的稳定性和可扩展性，需要采用容错和可扩展的技术，例如使用集群模式进行部署、采用主从复制的方式进行数据备份等</li></ol><p><strong>总结：</strong>分布式日志系统的设计和实现需要考虑到多个方面，包括日志收集、数据传输和存储、数据处理和分析、查询和展示、容错和可扩展性等，需要根据实际场景进行选择和调整。同时，需要关注系统的性能和可靠性，以便于提高系统的稳定性和可用性</p><hr><hr><h4 id="5-Git相关"><a href="#5-Git相关" class="headerlink" title="5. Git相关"></a><font color=DarkOrange>5. Git相关</font></h4><h5 id="5-1-什么是Git？Git常用命令"><a href="#5-1-什么是Git？Git常用命令" class="headerlink" title="5.1 什么是Git？Git常用命令"></a><font color=DarkOrange>5.1 什么是Git？Git常用命令</font></h5><p>Git是一种分布式版本控制系统，它能够追踪文件的更改历史并帮助团队进行协作开发。Git可以记录每个版本的变化，帮助开发者在项目开发过程中进行更好的版本管理，方便代码的分享、合并和撤销。Git还提供了分支、合并等功能，可以让多个开发者同时进行不同的代码开发，最终合并成一个完整的代码库</p><p>熟练使用Git是非常重要的技能，可以提高代码开发效率、协作效率和代码质量。在日常开发工作中，我们可以使用Git来跟踪文件变化、查看历史记录、创建和合并分支等等。同时，我们还可以使用Git与其他开发者协作，共同开发和维护代码库</p><p><strong>常用命令：</strong></p><table><thead><tr><th>命令</th><th>解释</th></tr></thead><tbody><tr><td><code>git init</code></td><td>在当前目录中创建一个新的Git仓库</td></tr><tr><td><code>git clone &lt;url&gt;</code></td><td>克隆一个远程Git仓库到本地</td></tr><tr><td><code>git add &lt;file&gt;</code></td><td>将文件添加到Git仓库的暂存区中</td></tr><tr><td><code>git commit -m &quot;&lt;message&gt;&quot;</code></td><td>提交暂存区中的文件到Git仓库，并添加提交信息</td></tr><tr><td><code>git status</code></td><td>显示当前Git仓库的状态，包括已修改、已暂存和未跟踪的文件</td></tr><tr><td><code>git log</code></td><td>查看Git仓库的提交历史记录</td></tr><tr><td><code>git branch</code></td><td>查看本地分支列表，以及当前所在分支</td></tr><tr><td><code>git checkout &lt;branch&gt;</code></td><td>切换到指定的分支</td></tr><tr><td><code>git merge &lt;branch&gt;</code></td><td>将指定分支的更改合并到当前分支</td></tr><tr><td><code>git pull</code></td><td>从远程Git仓库拉取最新的更改到本地</td></tr><tr><td><code>git push</code></td><td>将本地的更改推送到远程Git仓库</td></tr><tr><td><code>git diff</code></td><td>显示未暂存文件与上次提交之间的差异</td></tr><tr><td><code>git reset &lt;file&gt;</code></td><td>将指定文件从暂存区中移除，但不会删除文件</td></tr><tr><td><code>git rm &lt;file&gt;</code></td><td>从Git仓库中删除指定的文件</td></tr><tr><td><code>git remote -v</code></td><td>显示Git仓库的远程地址列表</td></tr><tr><td><code>git config</code></td><td>配置Git仓库的全局或局部参数，如用户名、邮箱等</td></tr></tbody></table><h5 id="5-2-Git中的分支有哪些类型？请描述它们的特点"><a href="#5-2-Git中的分支有哪些类型？请描述它们的特点" class="headerlink" title="5.2 Git中的分支有哪些类型？请描述它们的特点"></a><font color=DarkOrange>5.2 Git中的分支有哪些类型？请描述它们的特点</font></h5><ol><li>主分支（master branch）：主分支是Git中默认的分支，通常用于发布稳定版本或者生产环境。所有的提交都会基于主分支进行合并，保证代码的稳定性和可靠性</li><li>开发分支（develop branch）：开发分支是主分支的一个副本，通常用于开发新功能或者进行大型的重构。在开发过程中，开发者可以在开发分支上进行自由的提交和修改，最终再将开发分支合并回主分支</li><li>功能分支（feature branch）：功能分支通常用于实现某个具体的功能，比如添加一个新的页面或者修改某个模块的逻辑。功能分支是从开发分支上切出来的，开发者可以在功能分支上自由地进行开发和提交，等到功能开发完成之后再将功能分支合并回开发分支</li><li>发布分支（release branch）：发布分支通常用于准备发布新版本，包括进行测试、修改bug、更新文档等工作。发布分支是从开发分支上切出来的，一旦发布完成之后，发布分支就会被合并回主分支和开发分支</li><li>补丁分支（hotfix branch）：补丁分支通常用于修复已经发布的版本中的紧急bug，它是从主分支上切出来的。一旦修复完成之后，补丁分支会被合并回主分支和开发分支</li></ol><h5 id="5-3-如果想要合并两个分支，应该如何操作？请简要描述一下"><a href="#5-3-如果想要合并两个分支，应该如何操作？请简要描述一下" class="headerlink" title="5.3 如果想要合并两个分支，应该如何操作？请简要描述一下"></a><font color=DarkOrange>5.3 如果想要合并两个分支，应该如何操作？请简要描述一下</font></h5><p>合并两个分支可以使用<code>git merge</code>命令。具体操作步骤如下：</p><ol><li>首先，切换到需要被合并的目标分支上。比如，如果你要将特性分支合并到主分支上，那么你需要先切换到主分支上，使用命令<code>git checkout main</code></li><li>然后，使用<code>git merge</code>命令将需要合并的分支合并到当前分支上。比如，如果你要将特性分支<code>feature-branch</code>合并到主分支上，那么你需要使用命令<code>git merge feature-branch</code></li><li>如果存在冲突，Git会提示你需要手动解决冲突。你可以使用命令<code>git status</code>来查看哪些文件存在冲突，然后手动编辑这些文件，解决冲突</li><li>最后，提交合并的结果。如果没有冲突，Git会自动创建一个新的提交，包含两个分支的修改。如果存在冲突，你需要手动编辑冲突的文件并使用<code>git add</code>命令将修改添加到暂存区，最后使用<code>git commit</code>命令提交合并结果</li></ol><p>合并分支是Git中非常重要的操作，在合并分支的过程中，需要注意避免冲突，保证代码的稳定性和可靠性</p><h5 id="5-4-如果想要撤销已经提交的Git提交记录，应该如何操作？请简要描述一下"><a href="#5-4-如果想要撤销已经提交的Git提交记录，应该如何操作？请简要描述一下" class="headerlink" title="5.4 如果想要撤销已经提交的Git提交记录，应该如何操作？请简要描述一下"></a><font color=DarkOrange>5.4 如果想要撤销已经提交的Git提交记录，应该如何操作？请简要描述一下</font></h5><p>在Git中，如果想要撤销已经提交的提交记录，可以使用<code>git revert</code>或者<code>git reset</code>命令。具体操作步骤如下：</p><ol><li>使用<code>git log</code>命令查看提交记录，找到需要撤销的提交记录的commit ID</li><li>如果想要保留提交记录并创建一个新的提交来撤销该提交记录，可以使用<code>git revert</code>命令。比如，如果要撤销commit ID为<code>abc123</code>的提交记录，可以使用命令<code>git revert abc123</code>，Git会自动创建一个新的提交记录来撤销该提交记录</li><li>如果想要完全删除该提交记录以及其之后的提交记录，可以使用<code>git reset</code>命令。比如，如果要删除commit ID为<code>abc123</code>及其之后的提交记录，可以使用命令<code>git reset abc123</code>，Git会将HEAD指针和当前分支指针都指向该提交记录，从而删除该提交记录及其之后的提交记录。注意，使用<code>git reset</code>命令删除提交记录是一种非常危险的操作，应该谨慎使用</li></ol><p>无论是使用<code>git revert</code>还是<code>git reset</code>命令，都需要注意该操作会改变Git仓库中的历史记录，可能会对其他开发者产生影响，因此需要谨慎操作。建议在进行该操作前先备份代码，并且在团队协作开发中与其他开发者进行充分的沟通和协商</p><h5 id="5-5-Git中的三个工作区是哪些？它们之间的区别是什么"><a href="#5-5-Git中的三个工作区是哪些？它们之间的区别是什么" class="headerlink" title="5.5 Git中的三个工作区是哪些？它们之间的区别是什么"></a><font color=DarkOrange>5.5 Git中的三个工作区是哪些？它们之间的区别是什么</font></h5><ol><li>工作区（working directory）：也称为工作目录，是指Git仓库中存储项目文件的目录，它包含了所有源代码文件、文档、图像等文件。在工作区中进行的所有修改都会被记录在Git中，但还没有被提交</li><li>暂存区（staging area）：也称为索引（index），是介于工作区和版本库之间的一个区域。它是一个临时的区域，用来存储已经被修改的文件，这些修改还没有被提交到版本库中</li><li>版本库（repository）：也称为Git目录，是Git仓库中存储版本历史记录的地方。它包含了所有的提交记录、分支、标签等信息，是Git中最重要的部分。版本库通常包括了一个HEAD指针，指向当前所在的分支和一个对象库，存储了所有的历史版本快照</li></ol><p>这三个工作区之间的主要区别在于它们所存储的内容和作用：</p><ul><li>工作区：存储了未被跟踪的文件和修改的文件，是用户在本地编辑代码的地方</li><li>暂存区：存储了已被修改的文件，这些修改已经被暂时保存起来，准备提交到版本库中</li><li>版本库：存储了所有的历史版本记录，包括了所有的提交记录、分支、标签等信息，是Git中最重要的部分</li></ul><h4 id="6-gRPC相关"><a href="#6-gRPC相关" class="headerlink" title="6. gRPC相关"></a><font color=DarkOrange>6. gRPC相关</font></h4><h5 id="6-1-gRPC是什么？它的工作原理是什么"><a href="#6-1-gRPC是什么？它的工作原理是什么" class="headerlink" title="6.1 gRPC是什么？它的工作原理是什么"></a><font color=DarkOrange>6.1 gRPC是什么？它的工作原理是什么</font></h5><p>gRPC是一种高性能、跨语言的远程过程调用（RPC）框架，由Google开发。它基于协议缓冲区（Protocol Buffers）和HTTP&#x2F;2协议构建，并支持多种语言（如C++, Java, Python, Go等）。gRPC的设计目标是使得客户端可以像本地方法调用一样方便地调用远程服务，同时提供高效的网络传输和序列化机制</p><p>gRPC的工作原理如下：</p><ol><li>定义服务：首先需要定义要提供的服务和接口，这是使用协议缓冲区定义的。这个定义文件包含服务名称、方法名称和参数以及返回值等信息</li><li>生成代码：接下来需要根据定义文件生成客户端和服务端的代码。通过使用gRPC提供的工具，可以生成不同语言的代码，以便在客户端和服务端中使用</li><li>实现服务端：服务端实现具体的业务逻辑。在实现过程中需要继承自动生成的代码中提供的服务接口，并重写接口中的方法</li><li>实现客户端：客户端使用生成的代码中提供的客户端Stub对象，调用远程服务。通过客户端Stub对象调用远程服务时，gRPC将负责将数据序列化并通过HTTP&#x2F;2协议传输给服务端</li><li>序列化和传输数据：gRPC使用协议缓冲区将数据序列化为二进制格式，并使用HTTP&#x2F;2协议传输。HTTP&#x2F;2协议支持流、多路复用和头部压缩等特性，可以有效提高网络传输效率</li><li>处理数据：服务端接收到请求后，将数据反序列化，处理请求并返回响应。服务端通过gRPC提供的Context对象可以访问请求的元数据，如请求的来源地址、身份验证信息等</li><li>返回响应：服务端将处理结果序列化，并使用HTTP&#x2F;2协议返回给客户端。客户端接收到响应后，将数据反序列化，并返回给应用程序</li></ol><h5 id="6-2-gRPC支持哪些序列化协议？请简要描述它们的特点"><a href="#6-2-gRPC支持哪些序列化协议？请简要描述它们的特点" class="headerlink" title="6.2 gRPC支持哪些序列化协议？请简要描述它们的特点"></a><font color=DarkOrange>6.2 gRPC支持哪些序列化协议？请简要描述它们的特点</font></h5><p>gRPC支持使用Google开发的协议缓冲区（Protocol Buffers）进行数据序列化和反序列化。Protocol Buffers是一种高效的二进制序列化协议，具有以下特点：</p><ol><li>紧凑性：Protocol Buffers序列化后的数据非常紧凑，相比XML和JSON等文本协议，可以节省大量的网络带宽和存储空间</li><li>可扩展性：Protocol Buffers支持定义可扩展的消息类型，可以很方便地添加、删除和修改消息的字段，而不会影响现有的消息格式</li><li>语言无关性：Protocol Buffers支持多种编程语言，包括C++, Java, Python, Go等，可以方便地实现跨语言的数据交换</li></ol><p>除了使用Protocol Buffers，gRPC还支持使用JSON进行数据序列化和反序列化。JSON是一种轻量级的文本协议，具有以下特点：</p><ol><li>可读性：JSON序列化后的数据具有可读性，易于调试和理解</li><li>易于使用：JSON在很多编程语言中都有内置的支持，可以很方便地进行编码和解码</li><li>可扩展性：JSON支持嵌套结构，可以很方便地实现复杂的数据模型</li></ol><p><strong>注意：</strong>相比于使用Protocol Buffers，使用JSON进行数据序列化和反序列化会带来一定的性能损失，同时JSON不支持所有的数据类型，因此在选择序列化协议时需要根据实际情况进行权衡</p><h5 id="6-3-gRPC支持哪些负载均衡策略？请简述它们的优点和缺点"><a href="#6-3-gRPC支持哪些负载均衡策略？请简述它们的优点和缺点" class="headerlink" title="6.3 gRPC支持哪些负载均衡策略？请简述它们的优点和缺点"></a><font color=DarkOrange>6.3 gRPC支持哪些负载均衡策略？请简述它们的优点和缺点</font></h5><p>gRPC支持多种负载均衡策略，如轮询（Round Robin）、最少连接（Least Connection）、随机（Random）和一致性哈希（Consistent Hashing）等。每种负载均衡策略都有其优点和缺点，具体如下：</p><ol><li>轮询（Round Robin）：将请求依次分配给每个可用的服务端，循环往复。优点是实现简单，适用于服务数量较少的情况，缺点是当服务的处理能力不均衡时，可能会导致某些服务的负载过高</li><li>最少连接（Least Connection）：将请求分配给当前连接数最少的服务端，以实现负载均衡。优点是可以更加均衡地分配请求，缺点是需要实时监测每个服务端的连接数，实现复杂</li><li>随机（Random）：随机选择一个可用的服务端处理请求。优点是实现简单，适用于服务数量较少的情况，缺点是负载不够均衡，可能会导致某些服务的负载过高</li><li>一致性哈希（Consistent Hashing）：将每个服务端的地址映射到一个哈希环上，并根据请求的哈希值选择一个服务端处理请求。优点是在服务端的动态上下线时，能够保持原有的哈希环不变，避免大量请求被重新路由，缺点是实现相对复杂，需要维护哈希环和哈希函数</li></ol><h5 id="6-4-请解释gRPC中的流式RPC是什么？它们有什么用途"><a href="#6-4-请解释gRPC中的流式RPC是什么？它们有什么用途" class="headerlink" title="6.4 请解释gRPC中的流式RPC是什么？它们有什么用途"></a><font color=DarkOrange>6.4 请解释gRPC中的流式RPC是什么？它们有什么用途</font></h5><p>gRPC中的流式RPC是一种允许客户端和服务器之间建立持久连接并在这些连接上发送多个消息的RPC方式。这种类型的RPC可以分为两种：客户端流式RPC和服务器流式RPC</p><p>在客户端流式RPC中，客户端将多个请求消息发送到服务器，并等待服务器对每个请求进行响应。这种方式适用于客户端需要发送一系列相关数据的情况，例如上传文件或流媒体</p><p>在服务器流式RPC中，服务器将多个响应消息发送到客户端，直到处理完请求或客户端中止连接。这种方式适用于服务器需要处理大量数据的情况，例如实时日志记录或向客户端提供流媒体数据</p><p>流式RPC的优势在于它们可以通过单个持久连接处理大量数据，从而减少网络开销和资源占用，并提高系统性能。此外，流式RPC还允许实现实时或流式应用程序，例如视频流或实时数据分析</p><h5 id="6-5-gRPC提供了哪些安全机制？请简述它们的优点和缺点"><a href="#6-5-gRPC提供了哪些安全机制？请简述它们的优点和缺点" class="headerlink" title="6.5 gRPC提供了哪些安全机制？请简述它们的优点和缺点"></a><font color=DarkOrange>6.5 gRPC提供了哪些安全机制？请简述它们的优点和缺点</font></h5><p>gRPC提供了多种安全机制来保护通信的机密性、完整性和身份验证，其中包括：</p><ol><li>SSL &#x2F; TLS：通过SSL &#x2F; TLS提供端到端的加密和身份验证，防止中间人攻击和数据篡改</li><li>Token-based authentication：基于Token的身份验证机制，允许客户端和服务器之间交换认证和授权信息，以确保只有经过身份验证的用户才能访问受保护的资源</li><li>Access control lists（ACLs）：通过ACLs提供基于角色的授权机制，使得只有拥有特定权限的用户才能访问受保护的资源</li></ol><p>这些安全机制都有其优点和缺点：</p><ol><li>SSL &#x2F; TLS的优点在于它提供了端到端的加密和身份验证，同时具有广泛的浏览器和操作系统支持，但其缺点在于它可能会增加通信延迟，并且需要额外的计算资源</li><li>Token-based身份验证的优点在于它是无状态的，不需要维护会话，同时具有可扩展性和灵活性，但其缺点在于Token可以被截获和重播，从而导致安全漏洞</li><li>ACLs的优点在于它提供了基于角色的授权机制，使得只有特定的用户和组可以访问受保护的资源，同时具有灵活性和可扩展性，但其缺点在于管理ACLs可能会变得复杂和繁琐，尤其是在大型系统中</li></ol><hr><hr><h4 id="7-分布式系统"><a href="#7-分布式系统" class="headerlink" title="7. 分布式系统"></a><font color=DarkOrange>7. 分布式系统</font></h4><h5 id="7-1-什么是分布式系统？它有哪些优缺点"><a href="#7-1-什么是分布式系统？它有哪些优缺点" class="headerlink" title="7.1 什么是分布式系统？它有哪些优缺点"></a><font color=DarkOrange>7.1 什么是分布式系统？它有哪些优缺点</font></h5><p>分布式系统是由多个相互协作的计算机组成的系统，这些计算机通过网络进行通信和协作，共同完成一些任务。分布式系统通常具有以下特点：</p><ol><li>分布式系统由多个计算机组成，这些计算机通过网络连接</li><li>分布式系统通常是松耦合的，即不同计算机之间的任务可以相互独立地进行</li><li>分布式系统通常具有高可用性和容错性，即系统中的某个节点出现故障时，系统仍然可以正常运行</li></ol><p>分布式系统的优点包括：</p><ol><li>可扩展性：分布式系统可以通过增加计算机节点来扩展系统的处理能力</li><li>高可用性和容错性：分布式系统中的某个节点出现故障时，系统仍然可以正常运行</li><li>高性能：分布式系统可以将任务分解为多个子任务并行处理，从而提高系统的处理效率</li><li>灵活性：分布式系统可以根据需要选择不同的部署方案，如私有云、公有云、混合云等</li></ol><p>分布式系统的缺点包括：</p><ol><li>复杂性：分布式系统通常比单机系统更为复杂，需要考虑网络通信、数据一致性、容错性等问题</li><li>调试和测试难度：由于分布式系统中的不同节点相互独立，因此调试和测试变得更加困难</li><li>安全性：由于分布式系统的复杂性和多样性，因此安全性也变得更加复杂</li><li>高成本：分布式系统的部署、维护和管理通常比单机系统更加复杂和昂贵</li></ol><h5 id="7-2-解释一下CAP定理和BASE理论，并说明它们在分布式系统中的应用"><a href="#7-2-解释一下CAP定理和BASE理论，并说明它们在分布式系统中的应用" class="headerlink" title="7.2 解释一下CAP定理和BASE理论，并说明它们在分布式系统中的应用"></a><font color=DarkOrange>7.2 解释一下CAP定理和BASE理论，并说明它们在分布式系统中的应用</font></h5><p>CAP定理和BASE理论是分布式系统中常用的两个理论，它们都是为了解决分布式系统的可用性和一致性问题而提出的</p><p>CAP定理指的是在一个分布式系统中，无法同时满足以下三个特性：一致性（Consistency）、可用性（Availability）和分区容错性（Partition tolerance）。其中，分区容错性指的是系统中任意两个节点之间可能发生的网络分区问题。因此，在分布式系统中，需要在一致性和可用性之间做出取舍。例如，在分布式数据库系统中，有些系统可能会选择放弃一致性来保证系统的可用性</p><p>BASE理论是指基本可用（Basically Available）、软状态（Soft state）和最终一致性（Eventually consistent）。它强调了在分布式系统中，不需要强制要求所有节点在任何时候都达到一致状态，而是可以在满足基本可用性的前提下，通过软状态和最终一致性来保证系统的稳定性和可靠性。例如，NoSQL数据库就是基于BASE理论设计的</p><p>在实际的分布式系统中，CAP定理和BASE理论都具有重要的应用意义。在设计分布式系统时，需要根据实际情况进行取舍，权衡一致性和可用性的关系，同时需要根据实际需求来选择合适的数据一致性模型和分布式算法。同时，在分布式系统的实际应用中，需要结合CAP定理和BASE理论，选择合适的分布式存储和处理技术，从而保证系统的稳定性和可靠性</p><h5 id="7-3-什么是负载均衡？它的实现方法有哪些"><a href="#7-3-什么是负载均衡？它的实现方法有哪些" class="headerlink" title="7.3 什么是负载均衡？它的实现方法有哪些"></a><font color=DarkOrange>7.3 什么是负载均衡？它的实现方法有哪些</font></h5><p>负载均衡是一种将工作负载（workload）分配到多个计算资源上的技术，目的是提高系统的性能和可靠性。负载均衡通常被应用在服务器集群、网络负载均衡、数据库负载均衡等领域</p><p>负载均衡的实现方法包括：</p><ol><li>硬件负载均衡：使用专门的负载均衡硬件设备，例如F5、Cisco等，这些设备通过智能算法将请求分配到不同的服务器上，从而实现负载均衡</li><li>软件负载均衡：通过在普通服务器上安装负载均衡软件，例如Nginx、HAProxy等，这些软件通过负载均衡算法将请求分配到不同的服务器上</li><li>DNS负载均衡：通过DNS服务器来实现负载均衡，将域名解析请求分配到不同的服务器IP地址上</li><li>IP负载均衡：使用负载均衡设备将客户端请求发送到不同的服务器IP地址上，实现负载均衡</li></ol><p>在负载均衡的实现中，常用的负载均衡算法包括：</p><ol><li>轮询（Round Robin）算法：按照顺序将请求分配给不同的服务器</li><li>最少连接（Least Connections）算法：将请求发送到连接数最少的服务器上</li><li>IP哈希（IP Hash）算法：将请求根据客户端IP地址进行哈希计算，然后将请求发送到对应的服务器上</li><li>加权轮询（Weighted Round Robin）算法：按照服务器权重的比例将请求分配给不同的服务器</li></ol><p><strong>注意：</strong>不同的负载均衡算法适用于不同的应用场景，需要根据实际情况选择合适的算法。同时，在实际应用中，还需要注意负载均衡的可用性、容错性、扩展性等方面的问题，从而保证负载均衡系统的稳定性和可靠性</p><h5 id="7-4-分布式系统中的一致性问题，包括强一致性、弱一致性、最终一致性等"><a href="#7-4-分布式系统中的一致性问题，包括强一致性、弱一致性、最终一致性等" class="headerlink" title="7.4 分布式系统中的一致性问题，包括强一致性、弱一致性、最终一致性等"></a><font color=DarkOrange>7.4 分布式系统中的一致性问题，包括强一致性、弱一致性、最终一致性等</font></h5><p>在分布式系统中，一致性是一个重要的问题，它涉及到多个节点之间数据的同步和一致性。在分布式系统中，为了保证数据的正确性和一致性，通常采用以下三种一致性模型：</p><ol><li>强一致性（Strong Consistency）：强一致性要求在任何时候，对于任何一个数据操作，都能够保证所有节点的数据是一致的。强一致性保证了数据的强一致性和可线性化。但是，强一致性的代价是较高的延迟和低的可用性</li><li>弱一致性（Weak Consistency）：弱一致性是指系统允许一定时间内数据不一致的状态，但是最终数据会收敛到一致状态。弱一致性的代价是较低的延迟和较高的可用性。常见的弱一致性模型包括事件ual consistency和session consistency</li><li>最终一致性（Eventual Consistency）：最终一致性是指数据在一段时间内可能出现不一致的状态，但是最终会收敛到一致状态。最终一致性的代价是较低的延迟和较高的可用性。常见的最终一致性模型包括read-your-write consistency和monotonic read consistency</li></ol><p><strong>注意：</strong>在实际应用中，不同的一致性模型适用于不同的应用场景，需要根据实际情况选择合适的一致性模型。同时，为了保证分布式系统的一致性，还需要考虑数据复制、冲突解决、故障恢复等问题，从而保证系统的正确性和可靠性</p><h5 id="7-5-如何避免分布式系统中的单点故障问题"><a href="#7-5-如何避免分布式系统中的单点故障问题" class="headerlink" title="7.5 如何避免分布式系统中的单点故障问题"></a><font color=DarkOrange>7.5 如何避免分布式系统中的单点故障问题</font></h5><p>在分布式系统中，单点故障是指一个节点的故障会导致整个系统的故障。为了避免单点故障问题，可以采取以下措施：</p><ol><li>引入冗余：通过引入多个节点来实现冗余，当某个节点故障时，其他节点可以接管它的工作，从而保证系统的正常运行。常见的冗余技术包括主备复制、多活复制和故障转移</li><li>负载均衡：通过在多个节点之间均衡分配负载，可以避免某个节点的负载过高，从而降低节点故障的风险。常见的负载均衡技术包括轮询、最少连接和IP哈希</li><li>无单点故障架构设计：在系统设计阶段就考虑到单点故障的问题，并采取相应的措施，如使用分布式数据库、分布式缓存等技术，避免单点故障</li><li>容错处理：在系统中引入容错机制，如超时重试、自动恢复等，可以避免节点故障导致系统的故障</li></ol><p><strong>注意：</strong>以上措施都需要结合实际情况进行综合考虑，同时也需要考虑措施的成本和复杂度，从而选择最合适的方案</p><h4 id="8-linux-IO系统"><a href="#8-linux-IO系统" class="headerlink" title="8. linux IO系统"></a><font color=DarkOrange>8. linux IO系统</font></h4><h5 id="8-1-什么是Linux-IO系统？它的架构是怎样的"><a href="#8-1-什么是Linux-IO系统？它的架构是怎样的" class="headerlink" title="8.1 什么是Linux IO系统？它的架构是怎样的"></a><font color=DarkOrange>8.1 什么是Linux IO系统？它的架构是怎样的</font></h5><p>Linux IO系统是指Linux操作系统中负责管理输入输出（IO）的子系统，包括对磁盘、网络、终端等IO设备的读写操作。Linux IO系统的架构包括以下几个层次：</p><ol><li>应用程序层：应用程序通过标准的系统调用（如open、read、write等）来进行IO操作</li><li>VFS层：虚拟文件系统层是Linux内核中的一个抽象层，用于屏蔽不同文件系统的细节，提供统一的文件访问接口</li><li>块设备层：块设备层负责管理块设备（如硬盘）的读写操作，通过设备驱动程序与硬件进行交互</li><li>文件系统层：文件系统层负责管理文件的读写操作，包括缓存管理、索引管理、文件权限管理等</li><li>IO调度层：IO调度层负责管理IO请求的调度，以提高IO的效率。Linux中常用的IO调度算法包括CFQ、NOOP和Deadline等</li><li>设备驱动层：设备驱动层负责与硬件设备进行交互，包括设备的初始化、数据传输、中断处理等操作</li></ol><p>Linux IO系统的架构是分层次的，每一层都提供了不同的功能，并且各层之间通过标准接口进行交互，使得整个系统更加模块化和可扩展</p><h5 id="8-2-阻塞式IO和非阻塞式IO，以及它们的区别"><a href="#8-2-阻塞式IO和非阻塞式IO，以及它们的区别" class="headerlink" title="8.2 阻塞式IO和非阻塞式IO，以及它们的区别"></a><font color=DarkOrange>8.2 阻塞式IO和非阻塞式IO，以及它们的区别</font></h5><p>阻塞式IO和非阻塞式IO都是指应用程序在进行IO操作时的一种模式</p><p>阻塞式IO是指应用程序在进行IO操作时会一直等待IO操作完成后才返回，期间无法进行其他操作。例如，当应用程序调用read()函数读取文件内容时，如果文件内容还未就绪，read()函数会一直等待，直到文件内容就绪后才返回</p><p>非阻塞式IO是指应用程序在进行IO操作时不会一直等待IO操作完成，而是立即返回，由应用程序自行处理其他操作。例如，当应用程序调用read()函数读取文件内容时，如果文件内容还未就绪，read()函数会立即返回一个错误码（如EAGAIN），告诉应用程序当前IO操作无法完成，应用程序可以继续处理其他操作</p><p>阻塞式IO的优点是操作简单、效率高，但缺点是容易出现阻塞，导致应用程序的响应变慢。非阻塞式IO虽然避免了阻塞问题，但其操作比较复杂，需要应用程序自行处理多次IO操作才能完成一个完整的IO任务</p><p>在实际应用中，可以根据实际情况选择阻塞式IO或非阻塞式IO，或者结合两者的优点，使用IO多路复用技术（如epoll、select等）来实现高效的IO操作</p><h5 id="8-3-什么是异步IO？它和同步IO的区别是什么"><a href="#8-3-什么是异步IO？它和同步IO的区别是什么" class="headerlink" title="8.3 什么是异步IO？它和同步IO的区别是什么"></a><font color=DarkOrange>8.3 什么是异步IO？它和同步IO的区别是什么</font></h5><p>异步IO是指应用程序进行IO操作时，不需要等待IO操作完成，而是通过回调函数或事件通知的方式，等IO操作完成后再通知应用程序。在异步IO中，应用程序可以继续执行其他操作，无需等待IO操作完成</p><p>同步IO是指应用程序进行IO操作时，必须等待IO操作完成后才能继续执行后续操作。在同步IO中，应用程序进行IO操作时会一直阻塞，直到IO操作完成才能继续执行后续操作</p><p>异步IO相比同步IO的优点在于能够提高应用程序的并发能力和吞吐量，避免了因IO阻塞导致的性能瓶颈。异步IO适用于需要处理大量IO操作的应用场景，如高并发的网络服务、数据库等</p><p>但是，异步IO的实现比同步IO更加复杂，需要额外的线程或回调函数来处理IO完成后的事件通知，容易引入新的Bug，开发和调试难度较大。同时，异步IO也可能会造成资源的浪费，因为需要预留额外的线程或回调函数来处理IO完成事件，即使IO操作较少，这些线程或回调函数也需要占用一定的资源</p><h5 id="8-4-Linux中的文件描述符和文件IO"><a href="#8-4-Linux中的文件描述符和文件IO" class="headerlink" title="8.4 Linux中的文件描述符和文件IO"></a><font color=DarkOrange>8.4 Linux中的文件描述符和文件IO</font></h5><p>在Linux中，文件描述符（file descriptor）是一个非负整数，用于唯一标识一个进程正在使用的文件。在Linux中，每个进程都有一个文件描述符表，其中包含了当前进程所打开的所有文件的文件描述符。文件描述符通常用于执行文件IO操作，如读取文件内容、写入文件内容等</p><p>文件IO指的是对文件进行读写操作的过程。在Linux中，文件IO操作通常通过系统调用实现。常见的文件IO系统调用包括read、write、open、close等。这些系统调用都需要一个文件描述符作为参数，用于标识需要读写的文件</p><p>文件描述符和文件IO之间的关系是，应用程序通过打开文件获得文件描述符，然后使用文件描述符进行文件IO操作。文件描述符是应用程序和操作系统之间的接口，操作系统通过文件描述符识别应用程序正在使用的文件，并控制文件IO操作的流程和实现</p><p><strong>注意：</strong>文件描述符和文件之间并没有直接的关系。文件描述符只是一个抽象的概念，用于标识进程中正在使用的文件，而文件则是实际存在于磁盘上的数据存储实体。在文件IO操作中，操作系统会根据文件描述符找到相应的文件，然后进行实际的读写操作</p><h5 id="8-5-如何避免Linux中IO系统的瓶颈问题"><a href="#8-5-如何避免Linux中IO系统的瓶颈问题" class="headerlink" title="8.5 如何避免Linux中IO系统的瓶颈问题"></a><font color=DarkOrange>8.5 如何避免Linux中IO系统的瓶颈问题</font></h5><p>在Linux中，IO系统的瓶颈问题通常出现在磁盘IO和网络IO上，因为这些IO操作通常比较耗时，会影响应用程序的性能。下面是一些避免IO系统瓶颈问题的方法：</p><ol><li>使用缓存：在读写大文件时，可以使用缓存来避免频繁的磁盘IO操作。将数据先读取到内存中，然后在内存中进行操作，最后再一次性写回磁盘。使用缓存可以减少磁盘IO次数，提高应用程序的性能</li><li>使用多线程&#x2F;多进程：可以将IO操作放在独立的线程或进程中进行，以避免IO操作对主线程&#x2F;进程的阻塞。可以使用线程池或进程池来管理IO操作线程&#x2F;进程的创建和销毁</li><li>使用非阻塞IO：使用非阻塞IO可以避免IO操作对主线程&#x2F;进程的阻塞，提高应用程序的并发能力。非阻塞IO需要结合使用事件驱动机制，如epoll或select，以等待IO操作的完成事件通知</li><li>使用异步IO：异步IO和非阻塞IO类似，但是它通过回调函数或事件通知的方式来处理IO操作的完成事件。使用异步IO可以避免频繁的系统调用，提高应用程序的性能</li><li>调整IO系统参数：可以调整Linux内核中的IO系统参数来优化系统的IO性能。如修改文件系统的最大打开文件数、调整磁盘调度算法、增大内核中socket缓存的大小等</li></ol><p><strong>总结：</strong>避免Linux中IO系统的瓶颈问题需要综合考虑应用程序的需求、系统硬件环境和Linux内核的特性，并根据实际情况选择合适的优化方法</p><h4 id="9-高性能系统设计"><a href="#9-高性能系统设计" class="headerlink" title="9. 高性能系统设计"></a><font color=DarkOrange>9. 高性能系统设计</font></h4><h5 id="9-1-什么是高性能系统？它与传统系统的区别是什么"><a href="#9-1-什么是高性能系统？它与传统系统的区别是什么" class="headerlink" title="9.1 什么是高性能系统？它与传统系统的区别是什么"></a><font color=DarkOrange>9.1 什么是高性能系统？它与传统系统的区别是什么</font></h5><p>高性能系统通常指能够在高负载下仍然保持高效稳定运行的系统。与传统系统相比，高性能系统通常具有以下特点：</p><ol><li>更高的性能指标：高性能系统通常具有更高的吞吐量、更低的延迟和更高的并发能力，能够支持更多的用户并处理更多的请求</li><li>更好的可伸缩性：高性能系统能够随着负载的增加而自动扩展，并能够有效地利用多核处理器和分布式集群等硬件资源</li><li>更高的可用性和容错性：高性能系统通常具有更好的容错性和可用性，能够在硬件故障、网络故障等异常情况下仍然保持高效稳定运行</li><li>更多的高级特性：高性能系统通常支持更多的高级特性，如事务处理、多版本并发控制、分布式锁等，能够满足复杂应用场景的需求</li></ol><p>与传统系统相比，高性能系统需要更高的硬件资源、更复杂的软件架构和更多的设计工作。同时，高性能系统也需要更加严格的测试和运维流程，以确保其稳定性和可靠性</p><h5 id="9-2-如何设计一个高性能的数据库系统？需要考虑哪些因素"><a href="#9-2-如何设计一个高性能的数据库系统？需要考虑哪些因素" class="headerlink" title="9.2 如何设计一个高性能的数据库系统？需要考虑哪些因素"></a><font color=DarkOrange>9.2 如何设计一个高性能的数据库系统？需要考虑哪些因素</font></h5><ol><li>数据库架构：数据库系统的架构是设计高性能的关键。需要选择适当的数据库类型（关系型、非关系型、图形数据库等）和架构（单节点、主从复制、分片、集群等），以支持高并发、高可用、高容错等需求</li><li>数据库设计：在设计数据库结构时，需要考虑数据的关系、规模、类型等因素，以保证查询效率和数据存储效率。需要优化数据库的表结构、索引、存储引擎等</li><li>数据库调优：对数据库进行调优可以提高其性能。需要对数据库的查询语句、索引、缓存、锁等进行调优，以提高查询效率和响应速度</li><li>数据库集群：将数据库部署在集群中可以提高系统的可用性和性能。需要考虑集群的架构、节点数、负载均衡等因素，以确保系统的高可用和高性能</li><li>存储优化：选择适当的存储硬件和存储架构可以提高数据库系统的性能。需要考虑存储类型、存储容量、IOPS、带宽等因素，以满足系统的性能需求</li><li>缓存优化：使用缓存可以减轻数据库的负载，提高系统性能。需要考虑缓存的类型、大小、淘汰策略等因素，以提高系统的性能和稳定性</li><li>高可用性和容错性：需要设计高可用和容错性方案，以确保系统在故障和异常情况下的稳定运行。需要考虑备份、恢复、故障转移等因素，以保证系统的可靠性和稳定性</li><li>安全性：数据库系统的安全性是保护数据完整性和保密性的重要方面。需要考虑身份认证、权限管理、加密等安全机制，以确保数据库系统的安全性</li></ol><p><strong>注意：</strong>设计高性能的数据库系统是一项复杂的工作，需要综合考虑多个因素，并根据实际情况进行调整和优化</p><h5 id="9-3-如何设计一个高性能的消息队列系统？需要考虑哪些因素"><a href="#9-3-如何设计一个高性能的消息队列系统？需要考虑哪些因素" class="headerlink" title="9.3 如何设计一个高性能的消息队列系统？需要考虑哪些因素"></a><font color=DarkOrange>9.3 如何设计一个高性能的消息队列系统？需要考虑哪些因素</font></h5><ol><li>消息持久化：消息队列需要支持消息的持久化，以确保消息不会在传输过程中丢失。可以采用日志文件、数据库等方式来实现消息的持久化</li><li>消息传输协议：选择适当的消息传输协议可以提高消息队列的性能。需要考虑消息传输的可靠性、传输效率、拥塞控制等因素，以确保系统的高性能和高可靠性</li><li>集群架构：将消息队列部署在集群中可以提高系统的可用性和性能。需要考虑集群的架构、节点数、负载均衡等因素，以确保系统的高可用和高性能</li><li>网络优化：优化网络性能可以提高消息队列的性能。需要考虑网络带宽、延迟、丢包率等因素，以确保消息传输的效率和可靠性</li><li>缓存优化：使用缓存可以减轻消息队列的负载，提高系统性能。需要考虑缓存的类型、大小、淘汰策略等因素，以提高系统的性能和稳定性</li><li>负载均衡：采用负载均衡可以平衡消息队列的负载，提高系统性能。需要考虑负载均衡算法、节点数、响应速度等因素，以确保系统的高可用和高性能</li><li>高可用性和容错性：需要设计高可用和容错性方案，以确保系统在故障和异常情况下的稳定运行。需要考虑备份、恢复、故障转移等因素，以保证系统的可靠性和稳定性</li><li>安全性：消息队列系统的安全性是保护消息完整性和保密性的重要方面。需要考虑身份认证、权限管理、加密等安全机制，以确保消息队列系统的安全性</li></ol><p><strong>注意：</strong>设计高性能的消息队列系统是一项复杂的工作，需要综合考虑多个因素，并根据实际情况进行调整和优化</p><h5 id="9-4-如何设计一个高性能的缓存系统？需要考虑哪些因素"><a href="#9-4-如何设计一个高性能的缓存系统？需要考虑哪些因素" class="headerlink" title="9.4 如何设计一个高性能的缓存系统？需要考虑哪些因素"></a><font color=DarkOrange>9.4 如何设计一个高性能的缓存系统？需要考虑哪些因素</font></h5><ol><li>缓存的选择：选择适合当前业务场景的缓存类型，例如内存缓存、分布式缓存等</li><li>缓存的容量：需要根据实际业务需求和系统负载来确定缓存容量，过小会导致频繁缓存失效，过大会浪费资源</li><li>缓存的淘汰策略：常见的缓存淘汰策略有 LRU、LFU 等，需要根据业务场景选择合适的策略</li><li>缓存的并发性：并发请求会导致缓存的争用，需要设计高效的并发控制机制，例如乐观锁、悲观锁等</li><li>缓存的数据一致性：由于缓存可能存在数据延迟或者缓存失效等问题，需要考虑缓存与数据源的数据一致性问题，例如使用缓存更新、过期时间等方式保证数据一致性</li><li>缓存的高可用性：缓存故障会导致系统性能下降，需要考虑高可用性的设计，例如多节点部署、主从同步等方式</li><li>缓存的监控和运维：需要设计缓存的监控和运维方案，例如缓存性能监控、缓存失效告警、缓存节点扩容缩容等</li></ol><h5 id="9-5-如何避免高性能系统中的并发问题"><a href="#9-5-如何避免高性能系统中的并发问题" class="headerlink" title="9.5 如何避免高性能系统中的并发问题"></a><font color=DarkOrange>9.5 如何避免高性能系统中的并发问题</font></h5><ol><li>采用高效的并发控制机制：例如使用乐观锁、悲观锁、分段锁、读写锁等技术，确保在高并发的场景下，数据的正确性和一致性</li><li>采用异步编程模型：将一些IO密集型或者计算密集型的任务异步化处理，避免阻塞主线程，提高系统的并发性能</li><li>负载均衡：将请求分发到多个处理节点，均衡系统的负载，提高系统的并发处理能力</li><li>采用分布式架构：将系统拆分成多个服务，通过分布式技术实现数据共享和资源调度，提高系统的并发处理能力和容错能力</li><li>避免死锁和饥饿：对于并发控制机制的设计，需要避免死锁和饥饿的问题，例如避免循环等待和资源独占等</li><li>避免共享数据：尽可能避免共享数据，减少锁的竞争，例如使用局部变量、避免全局变量等</li><li>监控和优化：实时监控系统的性能和状态，发现并发问题，及时进行优化和调整，保证系统的稳定性和高性能</li></ol><h4 id="10-性能调优"><a href="#10-性能调优" class="headerlink" title="10. 性能调优"></a><font color=DarkOrange>10. 性能调优</font></h4><h5 id="10-1-什么是性能调优？为什么需要进行性能调优"><a href="#10-1-什么是性能调优？为什么需要进行性能调优" class="headerlink" title="10.1 什么是性能调优？为什么需要进行性能调优"></a><font color=DarkOrange>10.1 什么是性能调优？为什么需要进行性能调优</font></h5><p>性能调优是指对系统、应用程序或者数据库等进行优化，以提高其响应速度、吞吐量、稳定性和可伸缩性等性能指标的过程</p><p>在实际应用中，随着数据量和用户量的不断增加，系统的性能可能会逐渐降低，出现瓶颈，导致系统的响应变慢或者不稳定。而性能调优则可以通过调整系统的硬件资源配置、优化程序代码、采用缓存技术、增加服务器数量等方法，提高系统的性能，避免这些问题的出现</p><p>另外，进行性能调优还可以帮助我们发现系统中的瓶颈，了解系统的性能瓶颈所在，为进一步优化系统提供了重要的参考依据。因此，对于需要处理大量数据、高并发、低延迟等场景的应用，进行性能调优是非常必要的</p><h5 id="10-2-如何分析系统性能瓶颈？可以使用哪些工具"><a href="#10-2-如何分析系统性能瓶颈？可以使用哪些工具" class="headerlink" title="10.2 如何分析系统性能瓶颈？可以使用哪些工具"></a><font color=DarkOrange>10.2 如何分析系统性能瓶颈？可以使用哪些工具</font></h5><p>分析系统性能瓶颈可以采用以下方法：</p><ol><li>监控系统指标：通过监控系统的 CPU、内存、磁盘、网络等指标，了解系统的负载情况和瓶颈所在</li><li>分析日志文件：对系统的日志文件进行分析，查找出现错误或异常的地方，从而确定性能瓶颈</li><li>排查代码问题：通过代码分析、调试等手段，找出代码中存在的性能问题，并进行优化</li><li>压力测试：通过模拟高并发、大数据量等场景对系统进行压力测试，发现系统的瓶颈所在</li></ol><p>在实际操作中，可以使用各种工具来辅助进行系统性能瓶颈分析，例如：</p><ol><li>top、sar、vmstat等命令用于监控系统资源使用情况</li><li>tcpdump、wireshark等网络抓包工具用于分析网络流量和协议</li><li>strace、ltrace等系统调用跟踪工具用于分析程序的系统调用和系统资源使用情况</li><li>perf、gprof等性能分析工具用于分析程序的瓶颈和性能问题</li><li>jstat、jvisualvm等Java性能分析工具用于分析Java应用程序的性能问题</li></ol><p>以上仅是一部分常用的工具，具体选择何种工具需要根据实际情况和需求进行选</p><h5 id="10-3-如何通过代码优化来提高系统性能"><a href="#10-3-如何通过代码优化来提高系统性能" class="headerlink" title="10.3 如何通过代码优化来提高系统性能"></a><font color=DarkOrange>10.3 如何通过代码优化来提高系统性能</font></h5><ol><li>算法优化：对于涉及到大量数据处理的模块，可以通过优化算法来减少时间和空间复杂度，从而提高系统性能</li><li>数据结构优化：合理选择数据结构，可以提高代码的效率和性能。例如，使用哈希表而不是数组可以快速进行查找、插入和删除操作</li><li>编译优化：在编译过程中使用优化选项，例如-O2、-O3等，可以提高程序的执行效率</li><li>并发优化：使用多线程、多进程等技术来提高系统的并发能力，从而提高系统的吞吐量</li><li>内存优化：对于大量数据处理的程序，可以考虑使用内存池、对象池等技术来减少内存分配和回收的开销</li><li>IO优化：通过采用异步IO、缓存等技术来提高IO性能</li><li>数据库优化：对于频繁访问数据库的系统，可以通过合理设计数据库表结构、索引等来提高数据库性能</li></ol><p><strong>注意：</strong>在进行代码优化时，要根据实际情况和业务需求来选择优化策略，不能盲目追求性能，导致代码难以维护和扩展。同时，需要结合性能测试和性能监控等手段来验证优化效果，并及时调整优化策略</p><h5 id="10-4-如何通过系统配置来提高系统性能"><a href="#10-4-如何通过系统配置来提高系统性能" class="headerlink" title="10.4 如何通过系统配置来提高系统性能"></a><font color=DarkOrange>10.4 如何通过系统配置来提高系统性能</font></h5><ol><li>调整内核参数：可以通过修改系统内核参数来提高系统性能。例如，通过调整TCP缓冲区大小、最大文件句柄数等参数来优化网络性能和文件IO性能</li><li>磁盘优化：可以通过调整磁盘调度器、设置RAID、使用SSD等方式来提高磁盘IO性能</li><li>内存优化：可以通过调整系统内存参数、启用大页内存、使用内存压缩等方式来提高内存性能</li><li>网络优化：可以通过调整网络设备参数、配置网络优化工具等方式来提高网络性能</li><li>CPU优化：可以通过禁用不必要的CPU功能、调整CPU频率等方式来提高CPU性能</li></ol><p><strong>注意：</strong>在进行系统配置调整时，要根据实际情况和业务需求来选择优化策略，并进行充分的测试和验证。同时，需要注意系统安全和稳定性，不可盲目调整系统参数，导致系统不稳定或者存在安全风险</p><h5 id="10-5-如何通过硬件升级来提高系统性能？需要注意哪些问题"><a href="#10-5-如何通过硬件升级来提高系统性能？需要注意哪些问题" class="headerlink" title="10.5 如何通过硬件升级来提高系统性能？需要注意哪些问题"></a><font color=DarkOrange>10.5 如何通过硬件升级来提高系统性能？需要注意哪些问题</font></h5><p>通过硬件升级来提高系统性能可以从以下几个方面入手：</p><ol><li>CPU升级：可以将旧的CPU替换为性能更高的CPU，提高计算能力和并发处理能力</li><li>内存升级：可以增加系统内存容量，提高系统运行效率和响应速度</li><li>磁盘升级：可以将机械硬盘替换为固态硬盘（SSD），提高磁盘IO性能和文件读写速度</li><li>网络卡升级：可以将旧的网络接口卡替换为高速网络接口卡，提高网络数据传输速率</li></ol><p>需要注意的是，在进行硬件升级时，需要考虑以下问题：</p><ol><li>兼容性问题：新的硬件设备是否与原有的硬件兼容，是否需要更新驱动程序或操作系统版本</li><li>电源供应问题：新硬件设备是否需要更多的电力支持，是否需要更高级别的电源保护</li><li>空间和散热问题：新硬件设备是否需要更多的空间容纳，是否需要更好的散热装置</li><li>成本和预算问题：硬件升级需要投入一定的成本，需要在业务需求和预算范围内进行权衡和决策</li></ol><p><strong>总结：</strong>在进行硬件升级时，需要综合考虑硬件兼容性、电源供应、空间和散热、成本和预算等因素，进行合理的规划和决策</p><hr><hr>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;与后端有关的不同的岗位要求面试题整理&lt;/p&gt;
&lt;h4 id=&quot;1-调度相关&quot;&gt;&lt;a href=&quot;#1-调度相关&quot; class=&quot;headerlink&quot; title=&quot;1. 调度相关&quot;&gt;&lt;/a&gt;&lt;font color=DarkOrange&gt;1. 调度相关&lt;/font&gt;&lt;/h4</summary>
      
    
    
    
    <category term="面试" scheme="https://huajun-chen.github.io/categories/%E9%9D%A2%E8%AF%95/"/>
    
    
  </entry>
  
  <entry>
    <title>Python面试题</title>
    <link href="https://huajun-chen.github.io/2023/03/01/Python%E9%9D%A2%E8%AF%95%E9%A2%98/"/>
    <id>https://huajun-chen.github.io/2023/03/01/Python%E9%9D%A2%E8%AF%95%E9%A2%98/</id>
    <published>2023-03-01T07:41:41.000Z</published>
    <updated>2023-04-26T05:24:51.628Z</updated>
    
    <content type="html"><![CDATA[<p>Python常见面试题分享，涵盖了常见的Python面试八股文</p><h4 id="Python语言特点"><a href="#Python语言特点" class="headerlink" title="Python语言特点"></a><font color=DarkOrange>Python语言特点</font></h4><ol><li>易学易用：Python语法简单明了，易于学习和上手，代码可读性强，使得开发效率高。</li><li>面向对象：Python支持面向对象编程（OOP），包括封装、继承、多态等OOP特性，可以更方便地组织代码和抽象问题。</li><li>解释型：Python是解释型语言，不需要编译过程，直接运行源代码，这使得开发和调试变得更加容易</li><li>动态类型：Python是动态类型语言，不需要声明变量类型，可以根据需要动态改变变量类型，使得代码更加灵活。</li><li>跨平台：Python可以在各种操作系统上运行，包括Windows、Linux、Mac OS等，具有很强的跨平台性。</li><li>强大的标准库：Python标准库提供了大量的模块和函数，涵盖了网络编程、GUI编程、多线程编程、正则表达式等各种方面，开发者可以直接使用标准库来完成常见的任务，不需要从零开始编写</li><li>第三方库丰富：Python拥有众多的第三方库和框架，如NumPy、Pandas、Django等，可以快速实现各种功能，提高开发效率</li><li>可扩展性：Python可以通过C&#x2F;C++扩展模块来提高性能，还可以与其他语言进行混合编程。</li><li>开放源代码：Python是一种开放源代码语言，拥有大量的贡献者和用户社区，可以获得免费的开发工具和技术支持</li></ol><h4 id="1-Python的数据类型有哪些"><a href="#1-Python的数据类型有哪些" class="headerlink" title="1. Python的数据类型有哪些"></a><font color=DarkOrange>1. Python的数据类型有哪些</font></h4><ol><li>数字（number）：整数、浮点数和复数</li><li>字符串（string）：由字符组成的序列</li><li>列表（list）：由一组有序的值组成的序列，可修改</li><li>元组（tuple）：由一组有序的值组成的序列，不可修改</li><li>集合（set）：由一组唯一的、无序的值组成</li><li>字典（dict）：由一组键-值对组成的映射表</li><li>布尔值（bool）：表示True或False的值</li><li>空值（None）：表示没有值的对象，用None表示</li></ol><h4 id="2-Python可变与不可变数据类型的区别"><a href="#2-Python可变与不可变数据类型的区别" class="headerlink" title="2. Python可变与不可变数据类型的区别"></a><font color=DarkOrange>2. Python可变与不可变数据类型的区别</font></h4><ul><li>可变类型：可以修改其内容的数据类型，包括列表、集合和字典等。修改这些类型的值时，会直接在原始对象上进行修改，而不是创建一个新对象。例如，当向一个列表中添加一个元素时，列表的长度会发生变化，但其身份标识不会改变</li><li>不可变类型：一旦创建就不能更改其内容的数据类型，包括整数、浮点数、布尔值、元组和字符串等。如果对这些类型进行修改，将会创建一个新对象。例如，当对一个字符串进行切片或拼接时，会创建一个新的字符串对象</li></ul><p><strong>注意：</strong>可变类型的修改操作是原地修改，不可变类型的修改操作是创建一个新对象并返回</p><h4 id="3-Python列表和元组的区别"><a href="#3-Python列表和元组的区别" class="headerlink" title="3. Python列表和元组的区别"></a><font color=DarkOrange>3. Python列表和元组的区别</font></h4><ol><li>可变性：列表是可变的，可以在原地添加、删除或修改元素，而元组是不可变的，无法在原地进行修改操作。</li><li>语法：列表使用方括号 [] 来表示，元素之间用逗号分隔；元组使用圆括号 () 来表示，元素之间也用逗号分隔。如果元组只包含一个元素，需要在该元素后面添加一个逗号来表示它是一个元组而不是一个普通的值。</li><li>性能：元组相对于列表来说，在创建、遍历和访问元素时具有更高的性能，因为元组的结构是不可变的，因此在创建后不需要再进行修改，不会出现额外的开销</li><li>用途：列表通常用于需要添加、删除或修改元素的场景，如缓存数据、维护计数器、记录用户输入等；而元组通常用于存储一些固定的、不可变的数据，如坐标点、日期、时间等</li></ol><h4 id="4-Python列表的基本操作"><a href="#4-Python列表的基本操作" class="headerlink" title="4. Python列表的基本操作"></a><font color=DarkOrange>4. Python列表的基本操作</font></h4><ol><li>创建列表：使用方括号 [] 将一组元素括起来即可创建一个列表，例如：<code>a = [1, 2, 3, 4, 5]</code></li><li>索引和切片：可以使用索引和切片操作来访问列表中的元素，例如：<code>a[0]</code> 返回列表中的第一个元素，<code>a[1:3]</code> 返回列表中第二个到第四个元素。</li><li>修改元素：可以通过索引来修改列表中的元素，例如：<code>a[0] = 0</code> 将列表中的第一个元素修改为0</li><li>添加元素：可以使用 <code>append()</code> 方法向列表末尾添加一个元素，使用 <code>insert()</code> 方法在指定位置插入一个元素，例如：<code>a.append(6)</code>，<code>a.insert(0, 0)</code></li><li>删除元素：可以使用 <code>del</code> 语句、<code>remove()</code> 方法或 <code>pop()</code> 方法来删除列表中的元素，例如：<code>del a[0]</code> 删除列表中的第一个元素，<code>a.remove(3)</code> 删除列表中值为3的元素，<code>a.pop()</code> 删除并返回列表中的最后一个元素。</li><li>合并列表：可以使用 <code>+</code> 运算符将两个列表合并成一个新列表，例如：<code>a + [6, 7, 8]</code></li><li>复制列表：可以使用切片或 <code>copy()</code> 方法来复制一个列表，例如：<code>b = a[:]</code> 或 <code>b = a.copy()</code></li><li>获取列表长度：可以使用 <code>len()</code> 函数来获取列表的长度，例如：<code>len(a)</code> 返回列表 a 中元素的个数</li></ol><h4 id="5-Python中的列表推导式"><a href="#5-Python中的列表推导式" class="headerlink" title="5. Python中的列表推导式"></a><font color=DarkOrange>5. Python中的列表推导式</font></h4><p>Python中的列表推导式（List Comprehension）是一种简洁而强大的语法，可以快速地创建一个新的列表，语法形式为：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[expression <span class="keyword">for</span> item <span class="keyword">in</span> iterable <span class="keyword">if</span> condition]</span><br></pre></td></tr></table></figure><p>其中，<code>expression</code> 是一个表达式，用于计算新列表中每个元素的值；<code>item</code> 是 iterable（可迭代对象）中的一个元素；<code>if condition</code> 是一个可选的条件语句，用于过滤 iterable 中的元素。</p><p>举个例子，假设我们需要创建一个列表，其中包含从 0 到 9 的所有偶数的平方，可以使用列表推导式来实现：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">squares = [x**<span class="number">2</span> <span class="keyword">for</span> x <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">10</span>) <span class="keyword">if</span> x % <span class="number">2</span> == <span class="number">0</span>]</span><br></pre></td></tr></table></figure><p>上述代码首先使用 <code>range(10)</code> 函数生成一个从 0 到 9 的整数序列，然后通过 <code>if</code> 语句过滤出其中的偶数，最后对每个偶数进行平方运算并添加到新列表中。因此，<code>squares</code> 列表的值为 <code>[0, 4, 16, 36, 64]</code></p><p>除了基本形式外，列表推导式还支持嵌套、多个 <code>for</code> 循环和多个 <code>if</code> 条件语句的组合，可以根据需要进行组合和使用，以满足不同的需求。列表推导式具有简洁、高效和易读的特点</p><h4 id="6-Python删除list里的重复元素有几种方法"><a href="#6-Python删除list里的重复元素有几种方法" class="headerlink" title="6. Python删除list里的重复元素有几种方法"></a><font color=DarkOrange>6. Python删除list里的重复元素有几种方法</font></h4><ol><li><p>使用 set() 函数去重：将列表转换为 set 集合，再将其转换为列表即可，但是这种方法会改变列表元素的顺序</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">lst = <span class="built_in">list</span>(<span class="built_in">set</span>(lst))</span><br><span class="line"><span class="built_in">print</span>(lst)  <span class="comment"># 输出 [1, 2, 3, 4, 5]</span></span><br></pre></td></tr></table></figure></li><li><p>使用列表推导式去重：利用列表推导式，遍历原列表，将不重复的元素添加到新列表中，缺点是需要额外的空间</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">new_lst = []</span><br><span class="line">[new_lst.append(i) <span class="keyword">for</span> i <span class="keyword">in</span> lst <span class="keyword">if</span> i <span class="keyword">not</span> <span class="keyword">in</span> new_lst]</span><br><span class="line"><span class="built_in">print</span>(new_lst)  <span class="comment"># 输出 [1, 2, 3, 4, 5]</span></span><br></pre></td></tr></table></figure></li><li><p>使用 for 循环去重：利用 for 循环遍历原列表，将不重复的元素添加到新列表中，这种方法比较简单但速度较慢</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">new_lst = []</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> lst:</span><br><span class="line">    <span class="keyword">if</span> i <span class="keyword">not</span> <span class="keyword">in</span> new_lst:</span><br><span class="line">        new_lst.append(i)</span><br><span class="line"><span class="built_in">print</span>(new_lst)  <span class="comment"># 输出 [1, 2, 3, 4, 5]</span></span><br></pre></td></tr></table></figure></li><li><p>使用字典的 fromkeys() 方法去重：利用字典的键不能重复的特性，将列表中的元素作为字典的键，再将字典的键转换为列表即可，但是这种方法也会改变列表元素的顺序</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">lst = <span class="built_in">list</span>(<span class="built_in">dict</span>.fromkeys(lst))</span><br><span class="line"><span class="built_in">print</span>(lst)  <span class="comment"># 输出 [1, 2, 3, 4, 5]</span></span><br></pre></td></tr></table></figure></li></ol><p><strong>注意：</strong>这些方法各有优缺点，可以根据实际情况选择使用，常见的方法有 set() 函数和列表推导式，因为它们简单、直观且效率高</p><h4 id="7-Python类型转换"><a href="#7-Python类型转换" class="headerlink" title="7. Python类型转换"></a><font color=DarkOrange>7. Python类型转换</font></h4><ol><li><code>int(x)</code>：将 x 转换为一个整数。如果 x 无法转换为整数，则会抛出 ValueError 异常</li><li><code>float(x)</code>：将 x 转换为一个浮点数。如果 x 无法转换为浮点数，则会抛出 ValueError 异常。</li><li><code>str(x)</code>：将 x 转换为一个字符串。如果 x 无法转换为字符串，则会抛出 TypeError 异常</li><li><code>bool(x)</code>：将 x 转换为一个布尔值。如果 x 为假值（如空字符串、0、False），则返回 False，否则返回 True。</li><li><code>list(x)</code>：将 x 转换为一个列表。如果 x 不可迭代或没有实现 <strong>iter</strong> 方法，则会抛出 TypeError 异常</li><li><code>tuple(x)</code>：将 x 转换为一个元组。如果 x 不可迭代或没有实现 <strong>iter</strong> 方法，则会抛出 TypeError 异常</li><li><code>set(x)</code>：将 x 转换为一个集合。如果 x 不可迭代或没有实现 <strong>iter</strong> 方法，则会抛出 TypeError 异常。</li><li><code>dict(x)</code>：将 x 转换为一个字典。如果 x 不是映射类型（如字典或实现了 <strong>getitem</strong> 方法的类），则会抛出 TypeError 异常</li></ol><p><strong>注意：</strong>类型转换时可能会出现异常，因此在进行类型转换时需要注意错误处理，避免程序崩溃。同时，Python 中还有其他一些类型转换函数，如 <code>complex()</code> 用于将字符串或数字转换为复数、<code>bytes()</code> 用于将字符串或整数转换为字节串等，可以根据需要进行使用</p><h4 id="8-Python字典以及基本操作"><a href="#8-Python字典以及基本操作" class="headerlink" title="8. Python字典以及基本操作"></a><font color=DarkOrange>8. Python字典以及基本操作</font></h4><p>Python 中的字典是一种无序的可变集合，它包含键和对应的值。字典中的键必须是不可变的类型，例如整数、字符串、元组等，而值可以是任何类型</p><ol><li><p>创建字典：可以使用花括号 {} 或 dict() 函数来创建一个空字典，或者使用键值对的方式来初始化一个字典</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建空字典</span></span><br><span class="line">my_dict = &#123;&#125;</span><br><span class="line">my_dict = <span class="built_in">dict</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 初始化字典</span></span><br><span class="line">my_dict = &#123;<span class="string">&#x27;name&#x27;</span>: <span class="string">&#x27;Alice&#x27;</span>, <span class="string">&#x27;age&#x27;</span>: <span class="number">20</span>&#125;</span><br><span class="line">my_dict = <span class="built_in">dict</span>(name=<span class="string">&#x27;Alice&#x27;</span>, age=<span class="number">20</span>)</span><br></pre></td></tr></table></figure></li><li><p>添加或更新键值对：可以使用赋值运算符或 <code>update()</code> 方法来添加或更新字典中的键值对</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 添加键值对</span></span><br><span class="line">my_dict[<span class="string">&#x27;gender&#x27;</span>] = <span class="string">&#x27;female&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 更新键值对</span></span><br><span class="line">my_dict[<span class="string">&#x27;age&#x27;</span>] = <span class="number">21</span></span><br><span class="line">my_dict.update(&#123;<span class="string">&#x27;gender&#x27;</span>: <span class="string">&#x27;female&#x27;</span>, <span class="string">&#x27;age&#x27;</span>: <span class="number">21</span>&#125;)</span><br></pre></td></tr></table></figure></li><li><p>删除键值对：可以使用 <code>del</code> 关键字或 <code>pop()</code> 方法来删除字典中的键值对</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 删除键值对</span></span><br><span class="line"><span class="keyword">del</span> my_dict[<span class="string">&#x27;gender&#x27;</span>]</span><br><span class="line">my_dict.pop(<span class="string">&#x27;age&#x27;</span>)</span><br></pre></td></tr></table></figure></li><li><p>访问键值对：可以使用键来访问字典中的值，如果键不存在则会抛出 <code>KeyError</code> 异常。可以使用 <code>get()</code> 方法来避免这种情况，并返回一个默认值（默认为 <code>None</code>）</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 访问键值对</span></span><br><span class="line">name = my_dict[<span class="string">&#x27;name&#x27;</span>]</span><br><span class="line">age = my_dict.get(<span class="string">&#x27;age&#x27;</span>)</span><br><span class="line">gender = my_dict.get(<span class="string">&#x27;gender&#x27;</span>, <span class="string">&#x27;unknown&#x27;</span>)</span><br></pre></td></tr></table></figure></li><li><p>遍历字典：可以使用 <code>for</code> 循环来遍历字典的键或值，或者使用 <code>items()</code> 方法来遍历键值对</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 遍历键</span></span><br><span class="line"><span class="keyword">for</span> key <span class="keyword">in</span> my_dict:</span><br><span class="line">    <span class="built_in">print</span>(key)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 遍历值</span></span><br><span class="line"><span class="keyword">for</span> value <span class="keyword">in</span> my_dict.values():</span><br><span class="line">    <span class="built_in">print</span>(value)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 遍历键值对</span></span><br><span class="line"><span class="keyword">for</span> key, value <span class="keyword">in</span> my_dict.items():</span><br><span class="line">    <span class="built_in">print</span>(key, value)</span><br></pre></td></tr></table></figure></li><li><p>其他方法：字典还提供了一些其他常用的方法，例如 <code>keys()</code> 方法用于获取所有键的视图，<code>values()</code> 方法用于获取所有值的视图，<code>clear()</code> 方法用于清空字典等</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 获取键的视图</span></span><br><span class="line">keys = my_dict.keys()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取值的视图</span></span><br><span class="line">values = my_dict.values()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清空字典</span></span><br><span class="line">my_dict.clear()</span><br></pre></td></tr></table></figure></li></ol><p><strong>注意：</strong>字典是一种无序的数据结构，因此不能通过下标来访问字典中的元素，而是需要使用键来访问相应的值。另外，字典中的键必须是唯一的，如果有多个相同的键，则后面的键值对会覆盖前面的</p><h4 id="9-Python中的list和dict是怎么实现的"><a href="#9-Python中的list和dict是怎么实现的" class="headerlink" title="9. Python中的list和dict是怎么实现的"></a><font color=DarkOrange>9. Python中的list和dict是怎么实现的</font></h4><ol><li>列表的实现方式：Python 中的列表是一种动态数组，它实际上是一个由一系列连续的内存块组成的结构。每个元素都存储在内存中的一个单独的位置，通过索引可以直接访问相应位置的元素。当列表的长度发生变化时，Python 会重新分配一块更大或更小的内存空间来存储新的元素，然后将原来的元素拷贝到新的内存空间中。由于这种实现方式需要频繁地分配和拷贝内存，因此当列表较大时会带来一定的性能开销。</li><li>字典：Python 中的字典采用了一种哈希表的实现方式，它通过将键映射到内存地址来实现快速的键值查找。具体来说，字典实际上是一个由哈希桶组成的数组，每个哈希桶中存储着一条链表，链表中的每个节点都包含了一个键值对。当插入一个新的键值对时，Python 会根据键的哈希值将其插入到对应的哈希桶中，如果发现冲突则会将新的节点插入到链表的末尾。当查找一个键值对时，Python 首先计算键的哈希值，然后在相应的哈希桶中查找对应的链表，最后在链表中遍历查找相应的节点。由于哈希表的查找操作复杂度为 O(1)，因此字典在查找键值对时具有很高的效率。当字典中的键值对数量变化时，Python 会根据需要动态调整哈希表的大小，以保证哈希桶的装载因子在一个合理的范围内</li></ol><p><strong>注意：</strong>列表和字典的实现方式不仅影响它们的性能，还影响了它们的特性和用法。例如，由于列表是一种连续的内存结构，因此可以使用切片和排序等操作来修改和排序列表中的元素；而由于字典是一种哈希表结构，因此它不支持切片和排序等操作，但支持键值查找和更新等操作</p><h4 id="10-Python字符串格式化的几种方式"><a href="#10-Python字符串格式化的几种方式" class="headerlink" title="10. Python字符串格式化的几种方式"></a><font color=DarkOrange>10. Python字符串格式化的几种方式</font></h4><ol><li><p>使用 % 运算符：可以使用 % 运算符将变量插入到字符串中</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">name = <span class="string">&quot;Alice&quot;</span></span><br><span class="line">age = <span class="number">20</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;My name is %s and I am %d years old.&quot;</span> % (name, age))</span><br></pre></td></tr></table></figure><p>输出结果为：<code>My name is Alice and I am 20 years old.</code></p></li><li><p>使用 format() 方法：可以使用 format() 方法将变量插入到字符串中</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">name = <span class="string">&quot;Bob&quot;</span></span><br><span class="line">age = <span class="number">25</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;My name is &#123;&#125; and I am &#123;&#125; years old.&quot;</span>.<span class="built_in">format</span>(name, age))</span><br></pre></td></tr></table></figure><p>输出结果为：<code>My name is Bob and I am 25 years old.</code></p></li><li><p>使用 f-string：可以使用 f-string 将变量插入到字符串中</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">name = <span class="string">&quot;Charlie&quot;</span></span><br><span class="line">age = <span class="number">30</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;My name is <span class="subst">&#123;name&#125;</span> and I am <span class="subst">&#123;age&#125;</span> years old.&quot;</span>)</span><br></pre></td></tr></table></figure><p>输出结果为：<code>My name is Charlie and I am 30 years old.</code></p></li><li><p>使用模板字符串：可以使用模板字符串来格式化字符串</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> string <span class="keyword">import</span> Template</span><br><span class="line"></span><br><span class="line">name = <span class="string">&quot;Dave&quot;</span></span><br><span class="line">age = <span class="number">35</span></span><br><span class="line"></span><br><span class="line">template = Template(<span class="string">&quot;My name is $name and I am $age years old.&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(template.substitute(name=name, age=age))</span><br></pre></td></tr></table></figure><p>输出结果为：<code>My name is Dave and I am 35 years old.</code></p></li></ol><h4 id="11-Python中-args和-kwargs"><a href="#11-Python中-args和-kwargs" class="headerlink" title="11. Python中*args和**kwargs"></a><font color=DarkOrange>11. Python中*args和**kwargs</font></h4><p>Python 中，<code>*args</code> 和 <code>**kwargs</code> 用于在函数定义时接受任意数量的参数，<strong>只能放在参数的最后位置</strong></p><ol><li><p><code>*args</code>：<code>*args</code> 表示接受任意数量的位置参数（Positional Arguments），这些参数将被作为元组传递给函数。具体来说，当函数定义时使用 <code>*args</code> 时，它可以接受任意数量的位置参数，这些参数将被打包成一个元组</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">my_func</span>(<span class="params">*args</span>):</span><br><span class="line">    <span class="keyword">for</span> arg <span class="keyword">in</span> args:</span><br><span class="line">        <span class="built_in">print</span>(arg)</span><br><span class="line"></span><br><span class="line">my_func(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)  <span class="comment"># 输出结果为：1 2 3</span></span><br><span class="line">my_func(<span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>, <span class="string">&quot;c&quot;</span>, <span class="string">&quot;d&quot;</span>)  <span class="comment"># 输出结果为：a b c d</span></span><br></pre></td></tr></table></figure><p>在上面的例子中，函数 <code>my_func()</code> 使用了 <code>*args</code>，它可以接受任意数量的位置参数，并将它们打包成一个元组。在函数内部，我们可以使用 <code>for</code> 循环遍历元组中的每个元素</p></li><li><p><code>**kwargs</code>：<code>**kwargs</code> 表示接受任意数量的关键字参数（Keyword Arguments），这些参数将被作为字典传递给函数。具体来说，当函数定义时使用 <code>**kwargs</code> 时，它可以接受任意数量的关键字参数，这些参数将被打包成一个字典</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">my_func</span>(<span class="params">**kwargs</span>):</span><br><span class="line">    <span class="keyword">for</span> key, value <span class="keyword">in</span> kwargs.items():</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;<span class="subst">&#123;key&#125;</span> = <span class="subst">&#123;value&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">my_func(name=<span class="string">&quot;Alice&quot;</span>, age=<span class="number">20</span>)  <span class="comment"># 输出结果为：name = Alice, age = 20</span></span><br><span class="line">my_func(country=<span class="string">&quot;USA&quot;</span>, city=<span class="string">&quot;New York&quot;</span>, language=<span class="string">&quot;English&quot;</span>)  <span class="comment"># 输出结果为：country = USA, city = New York, language = English</span></span><br></pre></td></tr></table></figure><p>在上面的例子中，函数 <code>my_func()</code> 使用了 <code>**kwargs</code>，它可以接受任意数量的关键字参数，并将它们打包成一个字典。在函数内部，我们可以使用字典的 <code>items()</code> 方法遍历字典中的每个键值对</p></li><li><p>除了在函数定义时使用 <code>*args</code> 和 <code>**kwargs</code> 外，它们还可以在函数调用时使用。当在函数调用时使用 <code>*args</code> 和 <code>**kwargs</code> 时，它们的作用是将一个序列或字典拆包成多个参数</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">my_func</span>(<span class="params">a, b, c</span>):</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;a = <span class="subst">&#123;a&#125;</span>, b = <span class="subst">&#123;b&#125;</span>, c = <span class="subst">&#123;c&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">args = (<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>)</span><br><span class="line">my_func(*args)  <span class="comment"># 等价于 my_func(1, 2, 3)</span></span><br><span class="line"></span><br><span class="line">kwargs = &#123;<span class="string">&quot;a&quot;</span>: <span class="number">1</span>, <span class="string">&quot;b&quot;</span>: <span class="number">2</span>, <span class="string">&quot;c&quot;</span>: <span class="number">3</span>&#125;</span><br><span class="line">my_func(**kwargs)  <span class="comment"># 等价于 my_func(a=1, b=2, c=3)</span></span><br></pre></td></tr></table></figure><p>在上面的例子中，我们首先定义了一个函数 <code>my_func()</code>，它接受三个位置参数。然后，我们定义了一个元组 <code>args</code> 和一个字典 <code>kwargs</code>，分别包含三个元素和三个键值对</p></li></ol><h4 id="12-Python中深拷贝和浅拷贝的区别"><a href="#12-Python中深拷贝和浅拷贝的区别" class="headerlink" title="12. Python中深拷贝和浅拷贝的区别"></a><font color=DarkOrange>12. Python中深拷贝和浅拷贝的区别</font></h4><p>Python 中的拷贝操作分为浅拷贝（Shallow Copy）和深拷贝（Deep Copy），它们的主要区别在于复制后的对象是否共享内存</p><ol><li><p>浅拷贝：指创建一个新的对象，但是这个新对象只是原始对象的一个副本，它们共享相同的内存地址。也就是说，当我们修改其中一个对象时，另一个对象也会被修改。在 Python 中，可以使用 <code>copy()</code> 方法或切片操作来进行浅拷贝</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 浅拷贝示例</span></span><br><span class="line">list1 = [<span class="number">1</span>, <span class="number">2</span>, [<span class="number">3</span>, <span class="number">4</span>]]</span><br><span class="line">list2 = list1.copy()  <span class="comment"># 浅拷贝</span></span><br><span class="line">list1[<span class="number">0</span>] = <span class="number">100</span></span><br><span class="line">list1[<span class="number">2</span>][<span class="number">0</span>] = <span class="number">300</span></span><br><span class="line"><span class="built_in">print</span>(list1)  <span class="comment"># [100, 2, [300, 4]]</span></span><br><span class="line"><span class="built_in">print</span>(list2)  <span class="comment"># [1, 2, [300, 4]]</span></span><br></pre></td></tr></table></figure><p>在上面的示例中，我们创建了一个包含三个元素的列表 <code>list1</code>，其中第三个元素是一个嵌套列表。然后，我们对 <code>list1</code> 进行了浅拷贝，得到了一个新的列表 <code>list2</code>。接着，我们修改了 <code>list1</code> 的第一个元素和第三个元素的第一个元素，然后打印出了 <code>list1</code> 和 <code>list2</code>。可以看到，虽然 <code>list1</code> 和 <code>list2</code> 是不同的对象，但是它们共享了第三个元素的内存地址，所以修改其中一个对象的值也会影响另一个对象的值</p></li><li><p>深拷贝：指创建一个新的对象，并且递归地复制它所包含的所有对象。也就是说，当我们修改其中一个对象时，另一个对象不会受到影响。在 Python 中，可以使用 <code>copy.deepcopy()</code> 方法进行深拷贝</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 深拷贝示例</span></span><br><span class="line"><span class="keyword">import</span> copy</span><br><span class="line"></span><br><span class="line">list1 = [<span class="number">1</span>, <span class="number">2</span>, [<span class="number">3</span>, <span class="number">4</span>]]</span><br><span class="line">list2 = copy.deepcopy(list1)  <span class="comment"># 深拷贝</span></span><br><span class="line">list1[<span class="number">0</span>] = <span class="number">100</span></span><br><span class="line">list1[<span class="number">2</span>][<span class="number">0</span>] = <span class="number">300</span></span><br><span class="line"><span class="built_in">print</span>(list1)  <span class="comment"># [100, 2, [300, 4]]</span></span><br><span class="line"><span class="built_in">print</span>(list2)  <span class="comment"># [1, 2, [3, 4]]</span></span><br></pre></td></tr></table></figure><p>在上面的示例中，我们使用 <code>copy.deepcopy()</code> 方法对 <code>list1</code> 进行了深拷贝，得到了一个新的列表 <code>list2</code>。然后，我们修改了 <code>list1</code> 的第一个元素和第三个元素的第一个元素，然后打印出了 <code>list1</code> 和 <code>list2</code>。可以看到，虽然 <code>list1</code> 和 <code>list2</code> 是不同的对象，并且它们不共享任何内存地址，所以修改其中一个对象的值不会影响另一个对象的值</p></li></ol><h4 id="13-Python中的单引号和双引号的区别"><a href="#13-Python中的单引号和双引号的区别" class="headerlink" title="13. Python中的单引号和双引号的区别"></a><font color=DarkOrange>13. Python中的单引号和双引号的区别</font></h4><p>单引号和双引号都可以用来表示字符串，它们的主要区别在于字符串中是否包含了引号本身</p><p>单引号用来表示包含双引号的字符串，双引号用来表示包含单引号的字符串</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用单引号表示包含双引号的字符串</span></span><br><span class="line">str1 = <span class="string">&#x27;I said, &quot;Hello!&quot;&#x27;</span></span><br><span class="line"><span class="built_in">print</span>(str1)  <span class="comment"># I said, &quot;Hello!&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用双引号表示包含单引号的字符串</span></span><br><span class="line">str2 = <span class="string">&quot;It&#x27;s a beautiful day.&quot;</span></span><br><span class="line"><span class="built_in">print</span>(str2)  <span class="comment"># It&#x27;s a beautiful day.</span></span><br></pre></td></tr></table></figure><p>在 Python 中，还有一种特殊的字符串格式，称为三引号（Triple quotes）。它可以用来表示包含多行文本的字符串，不需要在每行文本中使用转义字符</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用三引号表示多行字符串</span></span><br><span class="line">str3 = <span class="string">&#x27;&#x27;&#x27;Hello,</span></span><br><span class="line"><span class="string">           world!</span></span><br><span class="line"><span class="string">        &#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="built_in">print</span>(str3)</span><br><span class="line"><span class="comment"># Hello,</span></span><br><span class="line"><span class="comment">#            world!</span></span><br></pre></td></tr></table></figure><p>上面的示例中，我们使用三引号来表示包含多行文本的字符串，这样可以避免在每行文本中使用转义字符，使代码更加简洁易读</p><h4 id="14-Python中append、insert和extend的区别"><a href="#14-Python中append、insert和extend的区别" class="headerlink" title="14. Python中append、insert和extend的区别"></a><font color=DarkOrange>14. Python中append、insert和extend的区别</font></h4><p>在 Python 中，<code>append()</code>、<code>insert()</code> 和 <code>extend()</code> 都是用来向列表（list）中添加元素的方法</p><ol><li><p><code>append</code>: 在列表末尾添加一个元素</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">lst.append(<span class="number">4</span>)</span><br><span class="line"><span class="built_in">print</span>(lst)  <span class="comment"># [1, 2, 3, 4]</span></span><br></pre></td></tr></table></figure></li><li><p><code>insert</code>: 在指定位置插入一个元素</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">lst.insert(<span class="number">1</span>, <span class="number">4</span>)</span><br><span class="line"><span class="built_in">print</span>(lst)  <span class="comment"># [1, 4, 2, 3]</span></span><br></pre></td></tr></table></figure></li><li><p><code>extend</code>: 将一个列表的所有元素添加到另一个列表的末尾</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">lst1 = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">lst2 = [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>]</span><br><span class="line">lst1.extend(lst2)</span><br><span class="line"><span class="built_in">print</span>(lst1)  <span class="comment"># [1, 2, 3, 4, 5, 6]</span></span><br></pre></td></tr></table></figure></li></ol><h4 id="15-Python中break、continue、pass是什么"><a href="#15-Python中break、continue、pass是什么" class="headerlink" title="15. Python中break、continue、pass是什么"></a><font color=DarkOrange>15. Python中break、continue、pass是什么</font></h4><p>在 Python 中，<code>break</code>、<code>continue</code> 和 <code>pass</code> 都是控制语句，用于控制循环的执行流程</p><ul><li><code>break</code> 语句用于终止循环，并跳出循环体。当循环条件不成立或者执行 <code>break</code> 语句时，循环会立即停止执行。</li><li><code>continue</code> 语句用于跳过当前循环中的某些语句，直接进入下一次循环的判断。当 <code>continue</code> 语句执行时，循环体中后续的语句都不会执行，而是直接跳到下一次循环的判断</li><li><code>pass</code> 语句用于占位，表示一个空语句。当需要在代码中添加一个空语句，但是又不能让 Python 报错时，就可以使用 <code>pass</code> 语句</li></ul><h4 id="16-Python中的remove、del和pop"><a href="#16-Python中的remove、del和pop" class="headerlink" title="16. Python中的remove、del和pop"></a><font color=DarkOrange>16. Python中的remove、del和pop</font></h4><p>在 Python 中，<code>remove</code>、<code>del</code> 和 <code>pop</code> 都是用来删除列表元素的方法</p><ol><li><p><code>remove</code> ：列表的内置函数，用于删除列表中指定的元素。如果列表中有多个相同的元素，它只会删除第一个匹配项，如果元素不存在则会抛出 <code>ValueError</code> 异常。如果要删除所有匹配项，可以使用循环或列表推导式</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">lst.remove(<span class="number">3</span>)  <span class="comment"># 从列表中删除元素 3</span></span><br><span class="line"><span class="built_in">print</span>(lst)     <span class="comment"># [1, 2, 4, 5]</span></span><br><span class="line">lst.remove(<span class="number">6</span>)  <span class="comment"># 抛出 ValueError 异常，因为元素 6 不存在于列表中</span></span><br></pre></td></tr></table></figure></li><li><p><code>del</code> ：Python的关键字，用于删除列表中指定位置的元素。它可以删除单个元素，也可以删除切片。如果删除的是切片，则删除的是切片中的所有元素</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line"><span class="keyword">del</span> lst[<span class="number">2</span>]   <span class="comment"># 从列表中删除索引为 2 的元素，即元素 3</span></span><br><span class="line"><span class="built_in">print</span>(lst)   <span class="comment"># [1, 2, 4, 5]</span></span><br><span class="line"><span class="keyword">del</span> lst[<span class="number">10</span>]  <span class="comment"># 抛出 IndexError 异常，因为索引 10 超出了列表的长度</span></span><br></pre></td></tr></table></figure></li><li><p><code>pop</code> ：列表的内置函数，用于删除列表中指定位置的元素并返回该元素。如果没有指定位置，则默认删除最后一个元素。如果要删除的位置不存在，则会引发IndexError异常</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">lst = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">x = lst.pop(<span class="number">2</span>)  <span class="comment"># 删除索引为 2 的元素，即元素 3，并将其赋值给变量 x</span></span><br><span class="line"><span class="built_in">print</span>(x)        <span class="comment"># 3</span></span><br><span class="line"><span class="built_in">print</span>(lst)      <span class="comment"># [1, 2, 4, 5]</span></span><br><span class="line">x = lst.pop()   <span class="comment"># 删除最后一个元素，即元素 5，并将其赋值给变量 x</span></span><br><span class="line"><span class="built_in">print</span>(x)        <span class="comment"># 5</span></span><br><span class="line"><span class="built_in">print</span>(lst)      <span class="comment"># [1, 2, 4]</span></span><br></pre></td></tr></table></figure></li></ol><p><strong>注意：</strong>如果需要删除列表中所有元素，可以使用 <code>lst.clear()</code> 方法</p><h4 id="17-Python中-x3D-x3D-和is的区别"><a href="#17-Python中-x3D-x3D-和is的区别" class="headerlink" title="17. Python中&#x3D;&#x3D;和is的区别"></a><font color=DarkOrange>17. Python中&#x3D;&#x3D;和is的区别</font></h4><ol><li><code>==</code> 运算符用于比较两个对象的值是否相等，它会比较对象的内容而不是它们的身份标识（内存地址）</li><li><code>is</code> 运算符用于比较两个对象的内存地址是否相等，也就是它们是否指向内存中的同一块地址</li></ol><h4 id="18-Python中-x3D-和is-not的区别"><a href="#18-Python中-x3D-和is-not的区别" class="headerlink" title="18. Python中!&#x3D;和is not的区别"></a><font color=DarkOrange>18. Python中!&#x3D;和is not的区别</font></h4><ol><li><code>!=</code> 运算符用于比较两个对象的值是否不相等，它与 <code>==</code> 运算符的作用相反</li><li><code>is not</code> 运算符用于比较两个对象的内存地址是否不相等，它与 <code>is</code> 运算符的作用相反</li></ol><h4 id="19-Python中iterables和iterators的区别"><a href="#19-Python中iterables和iterators的区别" class="headerlink" title="19. Python中iterables和iterators的区别"></a><font color=DarkOrange>19. Python中iterables和iterators的区别</font></h4><ol><li>Iterables（可迭代对象）是指那些可以被迭代的对象，例如列表、元组、字典等。这些对象可以通过 <code>for</code> 循环进行迭代，或者使用 <code>iter()</code> 函数将其转换为一个迭代器对象。</li><li>Iterators（迭代器）是指那些实现了 <code>__iter__()</code> 和 <code>__next__()</code> 方法的对象。<code>__iter__()</code> 方法返回迭代器对象自身，而 <code>__next__()</code> 方法返回下一个迭代值。迭代器可以用于访问集合中的元素，并且只能向前移动，一旦到达末尾就不能再次迭代</li></ol><p>因此，iterables 是一类对象，它们可以被迭代；而 iterators 是一类对象，它们是可迭代对象的具体实现，可以用于遍历可迭代对象中的元素。可以使用 <code>iter()</code> 函数将 iterables 转换为 iterators</p><p><strong>注意：</strong>只有实现了 <code>__iter__()</code> 方法的对象才是可迭代对象，而实现了 <code>__next__()</code> 方法的对象才是迭代器。如果一个对象既可以通过 <code>iter()</code> 函数转换为迭代器，又可以通过 <code>__iter__()</code> 方法返回迭代器对象自身，那么它就是一个迭代器</p><h4 id="20-Python解释器种类以及特点"><a href="#20-Python解释器种类以及特点" class="headerlink" title="20. Python解释器种类以及特点"></a><font color=DarkOrange>20. Python解释器种类以及特点</font></h4><ol><li>CPython：CPython 是 Python 官方实现，使用 C 语言编写。它是最常用的 Python 解释器，也是默认的解释器。CPython 的特点是运行速度较快，支持多种操作系统和平台，可以调用 C&#x2F;C++ 库，但占用资源较多。</li><li>Jython：Jython 是一种基于 Java 平台的 Python 解释器，它将 Python 代码转换为 Java 字节码执行。Jython 的特点是具有与 Java 平台相关的优点，例如垃圾回收、多线程等，但速度较慢，不支持一些 Python 特性和 C&#x2F;C++ 库。</li><li>IronPython：IronPython 是一种基于 .NET 平台的 Python 解释器，它将 Python 代码转换为 .NET 代码执行。IronPython 的特点是具有与 .NET 平台相关的优点，例如可重用性、可扩展性等，但速度较慢，不支持一些 Python 特性和 C&#x2F;C++ 库</li><li>PyPy：PyPy 是一种基于 Python 实现的解释器，它使用了即时编译技术，可以使 Python 代码的执行速度比 CPython 快 5-10 倍。PyPy 的特点是速度快，支持多种操作系统和平台，但不支持一些 Python 特性和 C&#x2F;C++ 库。</li><li>MicroPython：MicroPython 是一种专为嵌入式系统开发的 Python 解释器，它可以在资源受限的系统中运行 Python 代码。MicroPython 的特点是占用资源少、运行速度较快、支持硬件编程和网络编程等</li></ol><h4 id="21-Python面向对象三大特性"><a href="#21-Python面向对象三大特性" class="headerlink" title="21. Python面向对象三大特性"></a><font color=DarkOrange>21. Python面向对象三大特性</font></h4><ol><li><p>封装：封装是将数据和行为封装在一个单元中，通过接口来控制外部对内部的访问。Python 中的封装通过类的定义实现，将数据和方法定义在类中，并通过访问控制符号（public、private、protected）来控制访问权限</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, name, age</span>):</span><br><span class="line">        self.name = name</span><br><span class="line">        self.__age = age  <span class="comment"># 私有属性，外部无法直接访问</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">speak</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;My name is &#123;0&#125;, and I&#x27;m &#123;1&#125; years old.&quot;</span>.<span class="built_in">format</span>(self.name, self.__age))</span><br><span class="line"></span><br><span class="line">p = Person(<span class="string">&quot;Tom&quot;</span>, <span class="number">20</span>)</span><br><span class="line"><span class="built_in">print</span>(p.name)  <span class="comment"># 可以访问公有属性 name</span></span><br><span class="line"><span class="built_in">print</span>(p.__age)  <span class="comment"># 无法直接访问私有属性 __age，会抛出 AttributeError 异常</span></span><br></pre></td></tr></table></figure></li><li><p>继承：继承是指一个类可以从另一个类中继承属性和方法，从而实现代码的复用和扩展。Python 中的继承通过在类定义中指定父类实现，子类可以继承父类的属性和方法，并可以在此基础上添加自己的属性和方法</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, name</span>):</span><br><span class="line">        self.name = name</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">speak</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span>(<span class="title class_ inherited__">Animal</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">speak</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Woof!&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Cat</span>(<span class="title class_ inherited__">Animal</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">speak</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Meow!&quot;</span>)</span><br><span class="line"></span><br><span class="line">dog = Dog(<span class="string">&quot;Rufus&quot;</span>)</span><br><span class="line">cat = Cat(<span class="string">&quot;Fluffy&quot;</span>)</span><br><span class="line">dog.speak()  <span class="comment"># 输出 &quot;Woof!&quot;</span></span><br><span class="line">cat.speak()  <span class="comment"># 输出 &quot;Meow!&quot;</span></span><br></pre></td></tr></table></figure></li><li><p>多态：多态是指同一种操作或函数可以有多种不同的实现方式，提高了代码的灵活性和可扩展性。Python 中的多态通过继承和方法重写实现，子类可以重写父类的方法，从而实现不同的行为</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Shape</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">draw</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Circle</span>(<span class="title class_ inherited__">Shape</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">draw</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Draw a circle.&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Square</span>(<span class="title class_ inherited__">Shape</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">draw</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Draw a square.&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Triangle</span>(<span class="title class_ inherited__">Shape</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">draw</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Draw a triangle.&quot;</span>)</span><br><span class="line"></span><br><span class="line">shapes = [Circle(), Square(), Triangle()]</span><br><span class="line"><span class="keyword">for</span> shape <span class="keyword">in</span> shapes:</span><br><span class="line">    shape.draw()  <span class="comment"># 多态，根据不同的对象调用不同的实现方式</span></span><br></pre></td></tr></table></figure></li></ol><h4 id="22-Python多重继承"><a href="#22-Python多重继承" class="headerlink" title="22. Python多重继承"></a><font color=DarkOrange>22. Python多重继承</font></h4><p>Python多重继承是指一个类可以同时继承多个父类的特性。在Python中，多重继承可以通过在类定义时在括号内列出多个父类来实现</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">A</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">method_a</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;A&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">B</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">method_b</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;B&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">C</span>(A, B):  <span class="comment"># 多重继承</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">method_c</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;C&quot;</span>)</span><br><span class="line"></span><br><span class="line">c = C()</span><br><span class="line">c.method_a()  <span class="comment"># 输出 &quot;A&quot;</span></span><br><span class="line">c.method_b()  <span class="comment"># 输出 &quot;B&quot;</span></span><br><span class="line">c.method_c()  <span class="comment"># 输出 &quot;C&quot;</span></span><br></pre></td></tr></table></figure><ol><li>方法解析顺序（MRO）：当一个类继承多个父类时，Python会按照一定的顺序来查找方法，这个顺序被称为方法解析顺序（MRO），MRO的计算方式是通过C3算法来实现的</li><li>调用父类方法：当一个类继承多个父类时，如果这些父类中有同名的方法，Python会按照MRO的顺序来调用这些方法。如果需要调用指定父类的方法，可以使用super()函数来实现。</li><li>Diamond继承问题：当一个类继承多个父类时，如果这些父类之间存在继承关系，就会出现Diamond继承问题，这个问题可以通过使用抽象基类（ABC）来解决</li></ol><p><strong>注意：</strong>多重继承也可能会导致一些问题，例如父类中有同名方法或属性时，可能会产生歧义；还可能会增加代码的复杂性和维护难度。因此，在使用多重继承时，需要谨慎设计和管理类的层次结构</p><h4 id="23-Python变量、函数、类的命名规则"><a href="#23-Python变量、函数、类的命名规则" class="headerlink" title="23. Python变量、函数、类的命名规则"></a><font color=DarkOrange>23. Python变量、函数、类的命名规则</font></h4><ol><li>只能包含字母、数字和下划线，不能以数字开头；</li><li>不允许使用 Python 的关键字和保留字，如 if、while、class、def 等</li><li>变量和函数名使用小写字母，多个单词用下划线连接，如 my_var、my_function</li><li>类名使用大写字母开头，多个单词使用驼峰命名法，如 MyClass、MyClassExample；</li><li>前导下划线表示私有属性或方法，双前导下划线表示强制私有，后续加上类名的前导下划线表示受保护的属性或方法，如 my_var、my_var、MyClass_my_var</li></ol><h4 id="24-Python中迭代器和生成器"><a href="#24-Python中迭代器和生成器" class="headerlink" title="24. Python中迭代器和生成器"></a><font color=DarkOrange>24. Python中迭代器和生成器</font></h4><ol><li><p>迭代器：是一种访问集合元素的方式，迭代器对象从集合的第一个元素开始访问，直到所有元素被访问完毕。迭代器只能往前不会后退，而且在迭代过程中无法修改集合元素</p><p>Python中的迭代器有两个基本的方法：iter() 和 next()</p><ul><li>iter(object[, sentinel]) 函数用来生成迭代器，object 是可迭代对象，sentinel 是可选的，如果传递了第二个参数，则参数 object 必须是一个可调用的对象（如函数），此时，iter 创建了一个迭代器对象，每次调用这个迭代器对象的 <code>__next__()</code> 方法时，都会调用 object</li><li>next(iterator[, default]) 函数用来获取迭代器的下一个元素，如果迭代器已经到了最后一个元素，再次调用 next() 函数会抛出 StopIteration 异常，default 是可选的，如果迭代器已经到了最后一个元素，返回 default 值</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 迭代器示例</span></span><br><span class="line">my_list = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">my_iterator = <span class="built_in">iter</span>(my_list)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">next</span>(my_iterator))  <span class="comment"># 输出 1</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">next</span>(my_iterator))  <span class="comment"># 输出 2</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">next</span>(my_iterator))  <span class="comment"># 输出 3</span></span><br></pre></td></tr></table></figure></li><li><p>生成器：是一种特殊的迭代器，它是通过函数来实现的，生成器函数在执行时会生成一个生成器对象，生成器对象是一个可迭代对象，每次调用生成器对象的 <code>__next__()</code> 方法时，都会执行生成器函数中的代码，直到遇到 yield 语句，yield 语句会返回一个值，并暂停生成器函数的执行，下次调用 <code>__next__()</code> 方法时，生成器函数会从 yield 语句暂停的位置继续执行</p><p>Python中的生成器有两种实现方式：生成器函数和生成器表达式</p><p>生成器函数是通过 def 关键字定义的函数，函数中包含 yield 语句，生成器函数在执行时会生成一个生成器对象</p><p>生成器可以帮助我们节省内存，因为生成器每次只会返回一个值，而不会一次性将所有值都存储在内存中。另外，生成器还可以用于实现协程等高级特性，提高代码的灵活性和可维护性</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 生成器示例</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">my_generator</span>():</span><br><span class="line">    <span class="keyword">yield</span> <span class="number">1</span></span><br><span class="line">    <span class="keyword">yield</span> <span class="number">2</span></span><br><span class="line">    <span class="keyword">yield</span> <span class="number">3</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> value <span class="keyword">in</span> my_generator():</span><br><span class="line">    <span class="built_in">print</span>(value)  <span class="comment"># 输出 1, 2, 3</span></span><br></pre></td></tr></table></figure></li></ol><h4 id="25-Python中猴子补丁是什么"><a href="#25-Python中猴子补丁是什么" class="headerlink" title="25. Python中猴子补丁是什么"></a><font color=DarkOrange>25. Python中猴子补丁是什么</font></h4><p>猴子补丁是指在运行时动态修改类或模块的行为的技术。它允许在程序运行时更改代码，而不需要修改原始源代码。这种技术通常用于在测试或调试期间临时修改代码，或者在第三方库中添加或修改功能。使用猴子补丁时需要注意，它可能会导致代码的不稳定性和难以维护性，因此应该谨慎使用</p><h4 id="26-Python中的垃圾回收机制"><a href="#26-Python中的垃圾回收机制" class="headerlink" title="26. Python中的垃圾回收机制"></a><font color=DarkOrange>26. Python中的垃圾回收机制</font></h4><p>Python中的垃圾回收机制使用引用计数技术和垃圾回收器两种技术来实现。引用计数是一种轻量级的内存管理机制，当一个对象的引用计数变为0时，Python会立即回收它的内存。垃圾回收器是一种更高级别的机制，它会跟踪对象之间的引用，并回收不再使用的对象</p><p>Python中的垃圾回收器有两种实现方式：分代垃圾回收和循环垃圾回收。分代垃圾回收机制将对象根据其生命周期分成三代：0代、1代和2代。当一个对象经历了多次垃圾回收，其代数就会逐渐增加。Python垃圾回收器会根据代数来选择合适的回收策略</p><p>循环垃圾回收机制则会跟踪对象之间的引用关系，找到不再使用的对象，并将它们回收。这种机制需要更多的计算资源，因此只在必要时才会使用</p><h4 id="27-Python中的lambda表达式"><a href="#27-Python中的lambda表达式" class="headerlink" title="27. Python中的lambda表达式"></a><font color=DarkOrange>27. Python中的lambda表达式</font></h4><p>Lambda表达式是一种匿名函数，它可以在Python中快速定义简单的函数。它通常由一个单独的表达式组成，该表达式在调用时返回结果。Lambda表达式的语法如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">lambda</span> arguments: expression</span><br></pre></td></tr></table></figure><p>其中，arguments是函数的参数，可以是任意数量的参数，用逗号分隔。expression是函数的返回值，通常是一个简单的表达式。</p><p>Lambda表达式通常用于需要一个简单函数的地方，例如在map()、filter()和reduce()等函数中。它们也可以用于定义回调函数和排序函数等</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 定义一个lambda表达式</span></span><br><span class="line">lambda_func = <span class="keyword">lambda</span> x, y: x + y</span><br><span class="line"></span><br><span class="line"><span class="comment"># 调用lambda函数</span></span><br><span class="line">result = lambda_func(<span class="number">3</span>, <span class="number">4</span>)</span><br><span class="line"><span class="built_in">print</span>(result)  <span class="comment"># 输出 7</span></span><br></pre></td></tr></table></figure><p><strong>注意：</strong>虽然lambda表达式可以用来定义小型函数，但是如果函数体过于复杂，建议使用普通的函数定义语法，以提高代码可读性和可维护性</p><h4 id="28-Python中的反射"><a href="#28-Python中的反射" class="headerlink" title="28. Python中的反射"></a><font color=DarkOrange>28. Python中的反射</font></h4><p>Python中的反射是一种动态访问和修改对象属性和方法的机制，可以通过字符串的方式来访问对象的属性和方法。在Python中，每个对象都有一些基本的属性和方法，而反射机制可以通过这些属性和方法来实现动态访问和修改。</p><p>反射机制主要通过内置函数<code>getattr()</code>、<code>setattr()</code>、<code>hasattr()</code>和<code>delattr()</code>来实现。具体来说，这些函数的作用如下：</p><ul><li><code>getattr(object, name[, default])</code>: 获取对象的属性值。如果属性不存在，则会抛出AttributeError异常，或者返回default参数指定的默认值（如果提供了该参数）。</li><li><code>setattr(object, name, value)</code>: 设置对象的属性值。如果属性不存在，则会创建一个新属性</li><li><code>hasattr(object, name)</code>: 检查对象是否有指定的属性。如果对象有该属性，返回True，否则返回False。</li><li><code>delattr(object, name)</code>: 删除对象的指定属性。</li></ul><p>通过这些函数，可以实现访问、修改、创建和删除对象的属性和方法</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        self.x = <span class="number">10</span></span><br><span class="line">        self.y = <span class="number">20</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">self, a, b</span>):</span><br><span class="line">        <span class="keyword">return</span> a + b</span><br><span class="line"></span><br><span class="line">obj = MyClass()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用getattr获取对象属性</span></span><br><span class="line">x = <span class="built_in">getattr</span>(obj, <span class="string">&#x27;x&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(x)  <span class="comment"># 输出10</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用setattr设置对象属性</span></span><br><span class="line"><span class="built_in">setattr</span>(obj, <span class="string">&#x27;y&#x27;</span>, <span class="number">30</span>)</span><br><span class="line"><span class="built_in">print</span>(obj.y)  <span class="comment"># 输出30</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用hasattr检查对象属性是否存在</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hasattr</span>(obj, <span class="string">&#x27;z&#x27;</span>))  <span class="comment"># 输出False</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用delattr删除对象属性</span></span><br><span class="line"><span class="built_in">delattr</span>(obj, <span class="string">&#x27;x&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(obj.__dict__)  <span class="comment"># 输出 &#123;&#x27;y&#x27;: 30&#125;</span></span><br></pre></td></tr></table></figure><p><strong>注意：</strong>反射机制可以让代码更加灵活，但同时也会增加代码的复杂性和运行开销，因此在实际使用中需要谨慎使用</p><h4 id="29-Python中的-new-和-init-的区别"><a href="#29-Python中的-new-和-init-的区别" class="headerlink" title="29. Python中的__new__和__init__的区别"></a><font color=DarkOrange>29. Python中的<code>__new__</code>和<code>__init__</code>的区别</font></h4><p>在Python中，每个类都有两个特殊方法<code>__new__()</code>和<code>__init__()</code>。这两个方法都是用来创建类实例的，但是它们的作用不同。</p><p><code>__new__()</code>方法是一个类方法，用于创建并返回一个新的类实例。它通常被用来控制对象的创建过程，可以在对象实例化之前做一些自定义的操作，比如修改对象的属性、改变对象的类型等。<code>__new__()</code>方法的返回值是一个对象实例，这个实例会传递给<code>__init__()</code>方法作为第一个参数self。</p><p><code>__init__()</code>方法是一个实例方法，用于初始化一个已经存在的对象实例。它通常被用来对对象的属性进行初始化和赋值。<code>__init__()</code>方法没有返回值，它只是对self进行修改，因为self已经被创建了并传递给这个方法了。</p><p>需要注意的是，<code>__new__()</code>方法是在<code>__init__()</code>方法之前调用的，所以在<code>__init__()</code>方法中可以使用<code>self</code>对象已经存在的属性，但是不能修改这些属性</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyClass</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__new__</span>(<span class="params">cls, *args, **kwargs</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;__new__ called&#x27;</span>)</span><br><span class="line">        instance = <span class="built_in">super</span>().__new__(cls)</span><br><span class="line">        instance.name = <span class="string">&#x27;MyClass&#x27;</span></span><br><span class="line">        <span class="keyword">return</span> instance</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, age</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;__init__ called&#x27;</span>)</span><br><span class="line">        self.age = age</span><br><span class="line"></span><br><span class="line">obj = MyClass(<span class="number">18</span>)</span><br><span class="line"><span class="built_in">print</span>(obj.name)  <span class="comment"># 输出 MyClass</span></span><br><span class="line"><span class="built_in">print</span>(obj.age)  <span class="comment"># 输出 18</span></span><br></pre></td></tr></table></figure><p>在上面的例子中，<code>__new__()</code>方法被重写，创建了一个新的对象实例，并将<code>name</code>属性设置为<code>MyClass</code>，最后将实例返回给<code>__init__()</code>方法。<code>__init__()</code>方法接收到这个实例之后，对它进行了初始化，将<code>age</code>属性赋值为传入的参数18</p><h4 id="30-Python闭包"><a href="#30-Python闭包" class="headerlink" title="30. Python闭包"></a><font color=DarkOrange>30. Python闭包</font></h4><p>Python闭包是指在函数内部定义的函数，该函数可以访问外部函数的变量和参数，并且可以在外部函数返回后继续访问这些变量和参数。闭包可以用来实现一些高级的编程技巧，例如装饰器和函数工厂</p><p>在Python中，闭包是通过函数对象和函数属性来实现的。当一个函数定义在另一个函数内部时，它就可以访问外部函数的变量和参数。这些变量和参数被称为自由变量和自由参数。当外部函数返回时，闭包函数仍然可以访问这些自由变量和自由参数，因为它们被保存在闭包函数的函数对象中。这使得闭包函数可以在外部函数返回后继续执行，并且可以访问外部函数的状态</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">outer_func</span>(<span class="params">x</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">inner_func</span>(<span class="params">y</span>):</span><br><span class="line">        <span class="keyword">return</span> x + y</span><br><span class="line">    <span class="keyword">return</span> inner_func</span><br><span class="line"></span><br><span class="line">closure = outer_func(<span class="number">10</span>)</span><br><span class="line"><span class="built_in">print</span>(closure(<span class="number">5</span>))  <span class="comment"># 输出 15</span></span><br><span class="line"><span class="built_in">print</span>(closure(<span class="number">10</span>))  <span class="comment"># 输出 20</span></span><br></pre></td></tr></table></figure><h4 id="31-Python元类"><a href="#31-Python元类" class="headerlink" title="31. Python元类"></a><font color=DarkOrange>31. Python元类</font></h4><p>Python中的元类是用于创建类的类。元类允许我们控制类的创建过程，可以在类被创建之前或之后修改类。元类是一种高级的Python编程技巧，通常用于框架和库的开发中，比如Django、Flask、Tornado等。</p><p>元类可以用来实现单例模式、注册表、插件系统等功能。在Python中，所有的类都是由type类创建的，因此type类是Python中的默认元类</p><h4 id="32-Python中的GIL"><a href="#32-Python中的GIL" class="headerlink" title="32. Python中的GIL"></a><font color=DarkOrange>32. Python中的GIL</font></h4><p>GIL（Global Interpreter Lock）是Python解释器中的一个特性，它是一种锁机制，用于保证在同一时刻只有一个线程可以执行Python字节码。这个锁是解释器级别的锁，也称为全局锁。在多线程环境下，GIL会导致线程无法真正并行执行，因为只有一个线程可以拥有GIL</p><p>GIL的存在是因为CPython解释器的内存管理不是线程安全的，当多个线程同时访问和修改Python对象的引用计数时，可能会出现竞争条件和数据一致性问题。因此，为了避免这些问题，CPython引入了GIL来限制同一时刻只有一个线程可以执行Python字节码。</p><p>GIL的存在会影响Python多线程程序的性能，因为多线程程序无法真正利用多核CPU的性能优势。在CPU密集型任务中，GIL会成为瓶颈，导致多线程程序的运行时间比单线程程序更长。但在I&#x2F;O密集型任务中，GIL的影响较小，因为线程在等待I&#x2F;O操作完成时，GIL会被释放，其他线程就可以执行Python字节码。</p><p>为了避免GIL的影响，可以使用多进程代替多线程，因为多个进程之间是相互独立的，各自拥有自己的解释器和GIL，可以真正并行执行。也可以使用其他语言编写CPU密集型任务的模块，然后在Python程序中调用这些模块，避免GIL的影响。另外，Python还提供了一些并发编程库和工具，如multiprocessing、concurrent.futures、asyncio等，可以在一定程度上缓解GIL的影响</p><h4 id="33-Python类和对象的区别"><a href="#33-Python类和对象的区别" class="headerlink" title="33. Python类和对象的区别"></a><font color=DarkOrange>33. Python类和对象的区别</font></h4><p>在Python中，类是一种数据类型，用于定义对象的属性和方法。对象是类的实例，也就是类的具体化。类是对象的抽象，而对象是类的具体实现。类是一种模板或者蓝图，用于创建对象。</p><p>具体来说，Python中的类是由属性和方法组成的，属性是类的变量，用于存储对象的状态，方法是类的函数，用于定义对象的行为。类可以看作是一种特殊的字典，类的属性和方法都保存在类的命名空间中。类属性是所有实例共享的，而实例属性是每个实例独有的。</p><p>对象是类的实例，是根据类创建的具体实体，每个对象都有自己的状态和行为。对象包含属性和方法，属性是对象的变量，用于存储对象的状态，方法是对象的函数，用于定义对象的行为。对象是在程序运行时创建的，每个对象都是独立的，有自己的属性和方法</p><p>在Python中，类和对象的关系可以用以下表格来描述：</p><table><thead><tr><th>类</th><th>对象</th></tr></thead><tbody><tr><td>模板</td><td>具体实体</td></tr><tr><td>定义</td><td>创建</td></tr><tr><td>属性和方法</td><td>属性和方法</td></tr><tr><td>类变量</td><td>实例变量</td></tr><tr><td>类方法</td><td>实例方法</td></tr><tr><td>类属性</td><td>实例属性</td></tr><tr><td>继承</td><td>实例化</td></tr></tbody></table><p><strong>总的来说，类是一种抽象的概念，对象是类的实例化，是具体的实体。类描述了对象的属性和方法，而对象则是类的具体实现</strong></p><h4 id="34-Python中的self的作用"><a href="#34-Python中的self的作用" class="headerlink" title="34. Python中的self的作用"></a><font color=DarkOrange>34. Python中的self的作用</font></h4><p>在Python中，self是一个约定俗成的命名方式，用于表示类实例对象本身。self作为第一个参数出现在类的方法中，它表示对类实例对象本身的引用。</p><p>当一个类的方法被调用时，它会自动传入类实例对象本身作为第一个参数，通常使用self作为参数名。这样，在方法内部就可以使用self来引用对象本身，从而访问对象的属性和调用对象的方法</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, name, age</span>):</span><br><span class="line">        self.name = name</span><br><span class="line">        self.age = age</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">say_hello</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Hello, my name is&quot;</span>, self.name, <span class="string">&quot;and I am&quot;</span>, self.age, <span class="string">&quot;years old.&quot;</span>)</span><br><span class="line"></span><br><span class="line">p = Person(<span class="string">&quot;John&quot;</span>, <span class="number">30</span>)</span><br><span class="line">p.say_hello()  <span class="comment"># 输出：Hello, my name is John and I am 30 years old.</span></span><br></pre></td></tr></table></figure><p>在上面的示例中，<code>__init__</code>方法和<code>say_hello</code>方法都有一个<code>self</code>参数，它们用于引用类实例对象本身。在<code>__init__</code>方法中，使用<code>self</code>来初始化类实例对象的属性；在<code>say_hello</code>方法中，使用<code>self</code>来引用对象的属性和方法，从而输出对象的信息</p><p><strong>注意：</strong><code>self</code>不是Python的关键字，可以使用其他名称代替，但是约定俗成的做法是使用<code>self</code>。另外，<code>self</code>只在类的方法中出现，而在类的其他地方，如属性和方法的定义中，不需要使用<code>self</code></p><h4 id="35-Python2和Python3的区别"><a href="#35-Python2和Python3的区别" class="headerlink" title="35. Python2和Python3的区别"></a><font color=DarkOrange>35. Python2和Python3的区别</font></h4><ol><li>语法：Python3对语言的语法进行了一些改进，如print函数变成了print()函数，除法运算符变成了真正的浮点除法符号<code>/</code>，新增了非本地变量声明<code>nonlocal</code>等</li><li>编码：Python3默认采用UTF-8编码，而Python2采用的是ASCII编码。</li><li>兼容性：Python3不兼容Python2的代码，而Python2中的大多数代码可以在Python3中运行，但是需要进行一些修改</li><li>标准库：Python3的标准库中增加了一些新模块，如asyncio、enum、ipaddress等，同时还更新了一些模块，如pickle、tkinter等。</li><li>Unicode字符串：在Python3中，字符串是默认采用Unicode编码，而在Python2中，字符串采用的是ASCII编码。</li><li>整数除法：在Python2中，两个整数相除得到的是整数结果，而在Python3中，两个整数相除得到的是浮点数结果</li><li>range函数：在Python2中，range函数返回的是一个列表，而在Python3中，range函数返回的是一个可迭代对象</li><li>异常处理：在Python3中，异常处理语句需要使用as关键字来接收异常对象。</li><li>print函数：在Python2中，print语句可以不用括号，而在Python3中，print函数必须要用括号。</li></ol><h4 id="36-Python如何提高运行效率"><a href="#36-Python如何提高运行效率" class="headerlink" title="36. Python如何提高运行效率"></a><font color=DarkOrange>36. Python如何提高运行效率</font></h4><ol><li>使用算法和数据结构：在编写Python代码时，使用高效的算法和数据结构可以大大提高代码的运行效率。例如，在需要对大量数据进行排序时，使用快速排序算法比使用冒泡排序算法更加高效。</li><li>使用生成器：生成器是Python中的一种特殊类型的函数，可以逐个生成值，而不是一次生成所有值。使用生成器可以避免在内存中生成大量数据，从而提高运行效率。</li><li>使用列表推导式和生成器表达式：列表推导式和生成器表达式可以在一行代码中生成列表或生成器。它们通常比使用循环和条件语句生成列表或生成器更加高效</li><li>使用Cython或Numba等工具：Cython是一种将Python代码转换为C代码的工具，可以提高Python代码的运行效率。Numba是一种Python库，可以使用JIT（即时编译）技术将Python代码转换为机器码，从而提高代码的运行速度。</li><li>使用并行编程：Python提供了一些模块，如multiprocessing和concurrent.futures等，可以使用多进程或多线程并行执行代码，从而提高运行效率。</li><li>避免使用循环：在Python中，循环的执行效率较低，应尽量避免使用循环。可以使用NumPy等库中的矩阵运算等高效操作来替代循环</li><li>避免使用全局变量：在Python中，全局变量的访问速度较慢，应尽量避免使用全局变量，而使用局部变量来代替。</li></ol><h4 id="37-Python异常处理"><a href="#37-Python异常处理" class="headerlink" title="37. Python异常处理"></a><font color=DarkOrange>37. Python异常处理</font></h4><ol><li><p>异常处理是什么？<br>异常处理是指在程序运行过程中，当出现错误或异常时，程序能够捕获并处理这些异常，从而保证程序的正常运行。</p></li><li><p>Python中的异常类型有哪些？<br>Python中有很多内置的异常类型，比如NameError、TypeError、ValueError等等，还可以自定义异常类型。</p></li><li><p>如何捕获异常？<br>在Python中，可以使用try-except语句来捕获异常。try语句块中放置可能会出现异常的代码，如果出现异常，则会跳转到except语句块中进行处理</p></li><li><p>如何处理异常？<br>在except语句块中可以对异常进行处理，比如输出错误信息、记录日志、重新抛出异常等等。</p></li><li><p>finally语句的作用是什么？<br>finally语句块中的代码无论是否出现异常都会被执行，通常用于释放资源等操作。</p></li></ol><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="comment"># 可能会出现异常的代码块</span></span><br><span class="line"><span class="keyword">except</span> ExceptionType:</span><br><span class="line">    <span class="comment"># 处理异常的代码块</span></span><br><span class="line"><span class="keyword">finally</span>:</span><br><span class="line">    <span class="comment"># 最终执行的代码块</span></span><br></pre></td></tr></table></figure><ul><li><code>try</code>：表示要执行的代码块，这里是可能会出现异常的代码块</li><li><code>except</code>：表示当try语句块中出现指定类型的异常时，执行该语句块；</li><li><code>ExceptionType</code>：指定要处理的异常类型；</li><li><code>finally</code>：不管try语句块中是否有异常都会执行的代码块</li></ul><p>除了使用<code>except</code>语句来处理异常，还可以使用<code>else</code>语句块，当没有异常出现时，执行<code>else</code>语句块中的代码</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="comment"># 可能会出现异常的代码块</span></span><br><span class="line"><span class="keyword">except</span> ExceptionType:</span><br><span class="line">    <span class="comment"># 处理异常的代码块</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    <span class="comment"># 没有异常时执行的代码块</span></span><br><span class="line"><span class="keyword">finally</span>:</span><br><span class="line">    <span class="comment"># 最终执行的代码块</span></span><br></pre></td></tr></table></figure><h4 id="38-Python中的标准异常类"><a href="#38-Python中的标准异常类" class="headerlink" title="38. Python中的标准异常类"></a><font color=DarkOrange>38. Python中的标准异常类</font></h4><table><thead><tr><th>异常类</th><th>描述</th></tr></thead><tbody><tr><td><code>Exception</code></td><td>所有标准异常类的基类</td></tr><tr><td><code>AssertionError</code></td><td>断言语句失败时引发</td></tr><tr><td><code>AttributeError</code></td><td>对象没有这个属性</td></tr><tr><td><code>EOFError</code></td><td>没有输入，输入流结束</td></tr><tr><td><code>FileNotFoundError</code></td><td>请求的文件或目录未找到</td></tr><tr><td><code>ImportError</code></td><td>导入模块或包失败</td></tr><tr><td><code>IndexError</code></td><td>序列中没有此索引（index）</td></tr><tr><td><code>KeyError</code></td><td>映射中没有这个键</td></tr><tr><td><code>KeyboardInterrupt</code></td><td>用户中断执行（通常是输入^C）</td></tr><tr><td><code>MemoryError</code></td><td>操作耗尽内存</td></tr><tr><td><code>NameError</code></td><td>未声明&#x2F;初始化对象（没有属性）</td></tr><tr><td><code>NotImplementedError</code></td><td>尚未实现的方法或函数</td></tr><tr><td><code>OSError</code></td><td>操作系统错误</td></tr><tr><td><code>OverflowError</code></td><td>数字运算超出最大限制</td></tr><tr><td><code>RecursionError</code></td><td>递归调用超出最大限制</td></tr><tr><td><code>RuntimeError</code></td><td>一般的运行时错误</td></tr><tr><td><code>StopIteration</code></td><td>迭代器没有更多的值</td></tr><tr><td><code>SyntaxError</code></td><td>Python 语法错误</td></tr><tr><td><code>IndentationError</code></td><td>缩进错误</td></tr><tr><td><code>TabError</code></td><td>Tab和空格混用</td></tr><tr><td><code>SystemError</code></td><td>一般的解释器系统错误</td></tr><tr><td><code>SystemExit</code></td><td>Python 解释器请求退出</td></tr><tr><td><code>TypeError</code></td><td>对类型无效的操作</td></tr><tr><td><code>UnboundLocalError</code></td><td>访问未初始化的本地变量</td></tr><tr><td><code>UnicodeError</code></td><td>Unicode 相关的错误</td></tr><tr><td><code>ValueError</code></td><td>传递给函数的参数类型不正确，或者值不合法</td></tr><tr><td><code>ZeroDivisionError</code></td><td>除数为零</td></tr></tbody></table><hr>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Python常见面试题分享，涵盖了常见的Python面试八股文&lt;/p&gt;
&lt;h4 id=&quot;Python语言特点&quot;&gt;&lt;a href=&quot;#Python语言特点&quot; class=&quot;headerlink&quot; title=&quot;Python语言特点&quot;&gt;&lt;/a&gt;&lt;font color=DarkO</summary>
      
    
    
    
    <category term="面试" scheme="https://huajun-chen.github.io/categories/%E9%9D%A2%E8%AF%95/"/>
    
    
    <category term="Python" scheme="https://huajun-chen.github.io/tags/Python/"/>
    
  </entry>
  
  <entry>
    <title>Go语言使用Validator进行参数校验</title>
    <link href="https://huajun-chen.github.io/2022/12/08/Go%E8%AF%AD%E8%A8%80%E4%BD%BF%E7%94%A8Validator%E8%BF%9B%E8%A1%8C%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C/"/>
    <id>https://huajun-chen.github.io/2022/12/08/Go%E8%AF%AD%E8%A8%80%E4%BD%BF%E7%94%A8Validator%E8%BF%9B%E8%A1%8C%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C/</id>
    <published>2022-12-08T09:43:18.000Z</published>
    <updated>2022-12-09T11:16:44.420Z</updated>
    
    <content type="html"><![CDATA[<p>Validator包是一个用于验证数据的库。它可以帮助您确保输入数据符合您的预期格式，以避免在应用程序中出现错误。它可以验证数据类型、字符串格式、数字范围等内容。例如，您可以使用它来验证用户提供的电子邮件地址是否有效，或者确保输入的年龄在合法范围内</p><p>Validator包地址：<a href="https://pkg.go.dev/github.com/go-playground/validator/v10">点击跳转</a></p><h4 id="1-安装使用"><a href="#1-安装使用" class="headerlink" title="1. 安装使用"></a><font color=DarkOrange>1. 安装使用</font></h4><p>首先，需要安装Validator包。可以使用以下命令安装：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">go</span> get -u gopkg.in/<span class="keyword">go</span>-playground/validator.v10</span><br></pre></td></tr></table></figure><p>安装完成后，在代码中引入validator包：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&quot;gopkg.in/go-playground/validator.v10&quot;</span></span><br></pre></td></tr></table></figure><h4 id="2-简单示例"><a href="#2-简单示例" class="headerlink" title="2. 简单示例"></a><font color=DarkOrange>2. 简单示例</font></h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line">  <span class="string">&quot;gopkg.in/go-playground/validator.v10&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> User <span class="keyword">struct</span> &#123;</span><br><span class="line">Name  <span class="type">string</span> <span class="string">`validate:&quot;required&quot;`</span></span><br><span class="line">Age   <span class="type">int</span>    <span class="string">`validate:&quot;gte=0,lte=130&quot;`</span></span><br><span class="line">Email <span class="type">string</span> <span class="string">`validate:&quot;required,email&quot;`</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">user := &amp;User&#123;</span><br><span class="line">Name:  <span class="string">&quot;John Doe&quot;</span>,</span><br><span class="line">Age:   <span class="number">40</span>,</span><br><span class="line">Email: <span class="string">&quot;john.doe@example.com&quot;</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">validate := validator.New()</span><br><span class="line"></span><br><span class="line">err := validate.Struct(user)</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="comment">// 参数校验失败，输出错误信息</span></span><br><span class="line">fmt.Println(err)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在上面的例子中，我们定义了一个User结构体，用于表示用户信息。结构体字段上使用了validate标签，用于指定字段的约束条件。在上面的例子中，Name字段被设置为必填，Age字段的值必须大于等于0且小于等于130，Email字段的值必须是一个有效的邮件地址</p><p>在主函数中，我们实例化了一个User对象，并将其传入Validator的Struct方法中。Validator会对结构体中的每个字段进行校验，如果某个字段不符合约束条件，则会返回错误信息</p><p>除了使用结构体的方式进行校验之外，Validator还提供了各种其他验证函数，可以用来验证单个字段。例如，下面是一个验证字符串长度的示例：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> err := validate.Var(user.Name, <span class="string">&quot;required,min=3,max=100&quot;</span>); err != <span class="literal">nil</span> &#123;</span><br><span class="line">    <span class="comment">// 字符串长度不符合要求</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="3-操作符"><a href="#3-操作符" class="headerlink" title="3. 操作符"></a><font color=DarkOrange>3. 操作符</font></h4><table><thead><tr><th>标记</th><th>标记说明</th></tr></thead><tbody><tr><td>,</td><td>分割多个操作符，多个操作符之间使用,进行分割</td></tr><tr><td>|</td><td>或操作；使用多个约束，只需要满足其中一个，例如：rgb|rgba</td></tr><tr><td>-</td><td>跳过该字段验证，不检验</td></tr></tbody></table><h4 id="4-常用标记"><a href="#4-常用标记" class="headerlink" title="4. 常用标记"></a><font color=DarkOrange>4. 常用标记</font></h4><p><strong>在定义结构体时使用<code>binding</code>或<code>validate</code>标识相关校验规则</strong></p><table><thead><tr><th>标记</th><th>标记说明</th><th>示例</th></tr></thead><tbody><tr><td>required</td><td>必填</td><td>Field或Struct <code>validate:&quot;required&quot;</code></td></tr><tr><td>omitempty</td><td>空时忽略</td><td>Field或Struct <code>validate:&quot;omitempty&quot;</code></td></tr><tr><td>len</td><td>长度</td><td>Field <code>validate:&quot;len=0&quot;</code></td></tr><tr><td>eq</td><td>等于</td><td>Field <code>validate:&quot;eq=0&quot;</code></td></tr><tr><td>gt</td><td>大于</td><td>Field <code>validate:&quot;gt=0&quot;</code></td></tr><tr><td>gte</td><td>大于等于</td><td>Field <code>validate:&quot;gte=0&quot;</code></td></tr><tr><td>lt</td><td>小于</td><td>Field <code>validate:&quot;lt=0&quot;</code></td></tr><tr><td>lte</td><td>小于等于</td><td>Field <code>validate:&quot;lte=0&quot;</code></td></tr><tr><td>eqfield</td><td>同一结构体字段相等</td><td>Field <code>validate:&quot;eqfield=Field2&quot;</code></td></tr><tr><td>nefield</td><td>同一结构体字段不相等</td><td>Field <code>validate:&quot;nefield=Field2&quot;</code></td></tr><tr><td>gtfield</td><td>大于同一结构体字段</td><td>Field <code>validate:&quot;gtfield=Field2&quot;</code></td></tr><tr><td>gtefield</td><td>大于等于同一结构体字段</td><td>Field <code>validate:&quot;gtefield=Field2&quot;</code></td></tr><tr><td>ltfield</td><td>小于同一结构体字段</td><td>Field <code>validate:&quot;ltfield=Field2&quot;</code></td></tr><tr><td>ltefield</td><td>小于等于同一结构体字段</td><td>Field <code>validate:&quot;ltefield=Field2&quot;</code></td></tr><tr><td>eqcsfield</td><td>跨不同结构体字段相等</td><td>Struct1.Field <code>validate:&quot;eqcsfield=Struct2.Field2&quot;</code></td></tr><tr><td>necsfield</td><td>跨不同结构体字段不相等</td><td>Struct1.Field <code>validate:&quot;necsfield=Struct2.Field2&quot;</code></td></tr><tr><td>gtcsfield</td><td>大于跨不同结构体字段</td><td>Struct1.Field <code>validate:&quot;gtcsfield=Struct2.Field2&quot;</code></td></tr><tr><td>gtecsfield</td><td>大于等于跨不同结构体字段</td><td>Struct1.Field <code>validate:&quot;gtecsfield=Struct2.Field2&quot;</code></td></tr><tr><td>ltcsfield</td><td>小于跨不同结构体字段</td><td>Struct1.Field <code>validate:&quot;ltcsfield=Struct2.Field2&quot;</code></td></tr><tr><td>ltecsfield</td><td>小于等于跨不同结构体字段</td><td>Struct1.Field <code>validate:&quot;ltecsfield=Struct2.Field2&quot;</code></td></tr><tr><td>min</td><td>最大值</td><td>Field <code>validate:&quot;min=1&quot;</code></td></tr><tr><td>max</td><td>最小值</td><td>Field <code>validate:&quot;max=2&quot;</code></td></tr><tr><td>structonly</td><td>仅验证结构体，不验证任何结构体字段</td><td>Struct <code>validate:&quot;structonly&quot;</code></td></tr><tr><td>nostructlevel</td><td>不运行任何结构级别的验证</td><td>Struct <code>validate:&quot;nostructlevel&quot;</code></td></tr><tr><td>dive</td><td>向下延伸验证，多层向下需要多个dive标记</td><td>[][]string <code>validate:&quot;gt=0,dive,len=1,dive,required&quot;</code></td></tr><tr><td>dive Keys &amp; EndKeys</td><td>与dive同时使用，用于对map对象的键的和值的验证，keys为键，endkeys为值</td><td>map[string]string <code>validate:&quot;gt=0,dive,keys,eq=1|eq=2,endkeys,required&quot;</code></td></tr><tr><td>required_with</td><td>其他字段其中一个不为空且当前字段不为空</td><td>Field <code>validate:&quot;required_with=Field1 Field2&quot;</code></td></tr><tr><td>required_with_all</td><td>其他所有字段不为空且当前字段不为空</td><td>Field <code>validate:&quot;required_with_all=Field1 Field2&quot;</code></td></tr><tr><td>required_without</td><td>其他字段其中一个为空且当前字段不为空</td><td>Field &#96;validate:”required_without&#x3D;Field1 Field2”</td></tr><tr><td>required_without_all</td><td>其他所有字段为空且当前字段不为空</td><td>Field <code>validate:&quot;required_without_all=Field1 Field2&quot;</code></td></tr><tr><td>isdefault</td><td>是默认值</td><td>Field <code>validate:&quot;isdefault=0&quot;</code></td></tr><tr><td>oneof</td><td>其中之一</td><td>Field <code>validate:&quot;oneof=5 7 9&quot;</code></td></tr><tr><td>containsfield</td><td>字段包含另一个字段</td><td>Field <code>validate:&quot;containsfield=Field2&quot;</code></td></tr><tr><td>excludesfield</td><td>字段不包含另一个字段</td><td>Field <code>validate:&quot;excludesfield=Field2&quot;</code></td></tr><tr><td>unique</td><td>是否唯一，通常用于切片或结构体</td><td>Field <code>validate:&quot;unique&quot;</code></td></tr><tr><td>alphanum</td><td>字符串值是否只包含 ASCII 字母数字字符</td><td>Field <code>validate:&quot;alphanum&quot;</code></td></tr><tr><td>alphaunicode</td><td>字符串值是否只包含 unicode 字符</td><td>Field <code>validate:&quot;alphaunicode&quot;</code></td></tr><tr><td>alphanumunicode</td><td>字符串值是否只包含 unicode 字母数字字符</td><td>Field <code>validate:&quot;alphanumunicode&quot;</code></td></tr><tr><td>numeric</td><td>字符串值是否包含基本的数值</td><td>Field <code>validate:&quot;numeric&quot;</code></td></tr><tr><td>hexadecimal</td><td>字符串值是否包含有效的十六进制</td><td>Field <code>validate:&quot;hexadecimal&quot;</code></td></tr><tr><td>hexcolor</td><td>字符串值是否包含有效的十六进制颜色</td><td>Field <code>validate:&quot;hexcolor&quot;</code></td></tr><tr><td>lowercase</td><td>符串值是否只包含小写字符</td><td>Field <code>validate:&quot;lowercase&quot;</code></td></tr><tr><td>uppercase</td><td>符串值是否只包含大写字符</td><td>Field <code>validate:&quot;uppercase&quot;</code></td></tr><tr><td>email</td><td>字符串值包含一个有效的电子邮件</td><td>Field <code>validate:&quot;email&quot;</code></td></tr><tr><td>json</td><td>字符串值是否为有效的 JSON</td><td>Field <code>validate:&quot;json&quot;</code></td></tr><tr><td>file</td><td>符串值是否包含有效的文件路径，以及该文件是否存在于计算机上</td><td>Field <code>validate:&quot;file&quot;</code></td></tr><tr><td>url</td><td>符串值是否包含有效的 url</td><td>Field <code>validate:&quot;url&quot;</code></td></tr><tr><td>uri</td><td>符串值是否包含有效的 uri</td><td>Field <code>validate:&quot;uri&quot;</code></td></tr><tr><td>base64</td><td>字符串值是否包含有效的 base64值</td><td>Field <code>validate:&quot;base64&quot;</code></td></tr><tr><td>contains</td><td>字符串值包含子字符串值</td><td>Field <code>validate:&quot;contains=@&quot;</code></td></tr><tr><td>containsany</td><td>字符串值包含子字符串值中的任何字符</td><td>Field <code>validate:&quot;containsany=abc&quot;</code></td></tr><tr><td>containsrune</td><td>字符串值包含提供的特殊符号值</td><td>Field <code>validate:&quot;containsrune=☢&quot;</code></td></tr><tr><td>excludes</td><td>字符串值不包含子字符串值</td><td>Field <code>validate:&quot;excludes=@&quot;</code></td></tr><tr><td>excludesall</td><td>字符串值不包含任何子字符串值</td><td>Field <code>validate:&quot;excludesall=abc&quot;</code></td></tr><tr><td>excludesrune</td><td>字符串值不包含提供的特殊符号值</td><td>Field <code>validate:&quot;containsrune=☢&quot;</code></td></tr><tr><td>startswith</td><td>字符串以提供的字符串值开始</td><td>Field <code>validate:&quot;startswith=abc&quot;</code></td></tr><tr><td>endswith</td><td>字符串以提供的字符串值结束</td><td>Field <code>validate:&quot;endswith=abc&quot;</code></td></tr><tr><td>ip</td><td>字符串值是否包含有效的 IP 地址</td><td>Field <code>validate:&quot;ip&quot;</code></td></tr><tr><td>ipv4</td><td>字符串值是否包含有效的 ipv4地址</td><td>Field <code>validate:&quot;ipv4&quot;</code></td></tr><tr><td>datetime</td><td>字符串值是否包含有效的 日期</td><td>Field <code>validate:&quot;datetime&quot;</code></td></tr></tbody></table><h4 id="5-使用注意"><a href="#5-使用注意" class="headerlink" title="5. 使用注意"></a><font color=DarkOrange>5. 使用注意</font></h4><p>当搜索条件与特殊标记冲突时,如：逗号（,），或操作（|），中横线（-）等则需要使用 UTF-8十六进制表示形式</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Test <span class="keyword">struct</span> &#123;</span><br><span class="line">Field1 <span class="type">string</span> <span class="string">`validate:&quot;excludesall=|&quot;`</span>    <span class="comment">// 错误</span></span><br><span class="line">Field2 <span class="type">string</span> <span class="string">`validate:&quot;excludesall=0x7C&quot;`</span> <span class="comment">// 正确</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Validator包是一个用于验证数据的库。它可以帮助您确保输入数据符合您的预期格式，以避免在应用程序中出现错误。它可以验证数据类型、字符串格式、数字范围等内容。例如，您可以使用它来验证用户提供的电子邮件地址是否有效，或者确保输入的年龄在合法范围内&lt;/p&gt;
&lt;p&gt;Valid</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="Go" scheme="https://huajun-chen.github.io/tags/Go/"/>
    
  </entry>
  
  <entry>
    <title>GitHub + Go + Gin创建RESTful风格的项目</title>
    <link href="https://huajun-chen.github.io/2022/12/03/GitHub%E5%88%9B%E5%BB%BAGo-Gin-RESTful%E9%A3%8E%E6%A0%BC%E9%A1%B9%E7%9B%AE/"/>
    <id>https://huajun-chen.github.io/2022/12/03/GitHub%E5%88%9B%E5%BB%BAGo-Gin-RESTful%E9%A3%8E%E6%A0%BC%E9%A1%B9%E7%9B%AE/</id>
    <published>2022-12-03T05:40:30.000Z</published>
    <updated>2022-12-09T09:49:22.385Z</updated>
    
    <content type="html"><![CDATA[<p>通过GitHub + Go + Gin创建RESTful风格的项目，搭建一个基础的脚手架</p><p>完整项目GitHub地址：<a href="https://github.com/huajun-chen/GinRESTful">点击跳转</a></p><h4 id="1-GutHub-New"><a href="#1-GutHub-New" class="headerlink" title="1. GutHub New"></a><font color=DarkOrange>1. GutHub New</font></h4><p>打开GitHub，进入首页，点击<code>New</code>开始创建新项目</p><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qkp3xulaj328016g4qp.jpg" alt="image.png"></p><h4 id="2-创建项目"><a href="#2-创建项目" class="headerlink" title="2. 创建项目"></a><font color=DarkOrange>2. 创建项目</font></h4><p>点击<code>New</code>之后，填写项目名、项目描述，填写完项目名之后，后面会显示此项目名是否可用，绿钩为可用，红叉为不可用，其他选项默认即可，然后点击<code>Create repository</code>按钮创建项目</p><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qky746qaj3280160ndf.jpg" alt="image.png"></p><h4 id="3-创建成功"><a href="#3-创建成功" class="headerlink" title="3. 创建成功"></a><font color=DarkOrange>3. 创建成功</font></h4><p>创建项目成功之后页面会跳转，在此页面复制项目地址</p><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8ql0g1krlj328016gauw.jpg" alt="image.png"></p><h4 id="4-克隆项目"><a href="#4-克隆项目" class="headerlink" title="4. 克隆项目"></a><font color=DarkOrange>4. 克隆项目</font></h4><p>在本地电脑，进行需要存放项目的目录下，将项目克隆到本地，并且在本地新建<code>dev</code>开发分支</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> 项目地址 // 克隆项目</span><br><span class="line"><span class="built_in">cd</span> 项目名 // 进行项目目录</span><br><span class="line">git checkout -b 分支名 // 新建分支并切换到此分支</span><br></pre></td></tr></table></figure><div align="center"><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8ql7fxamdj30ua0v2qlc.jpg" alt="image.png" style="zoom:50%;" /></div><h4 id="5-打开项目"><a href="#5-打开项目" class="headerlink" title="5. 打开项目"></a><font color=DarkOrange>5. 打开项目</font></h4><p>使用本地<code>IDE</code>打开项目（这里以<code>Goland IDE</code>演示），在项目里添加<code>GOPROXY</code></p><p>路径：<code>Goland</code>-&gt;<code>Preferences...</code>-&gt;<code>Go</code>-&gt;<code>Go Modules</code></p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GOPROXY=https://goproxy.cn</span><br></pre></td></tr></table></figure><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qlextrflj31ik13kwnl.jpg" alt="image.png"></p><h4 id="6-创建go-mod"><a href="#6-创建go-mod" class="headerlink" title="6. 创建go mod"></a><font color=DarkOrange>6. 创建go mod</font></h4><p>在编译器里，打开终端，在终端通过命令的方式创建<code>go mod</code></p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go mod init 项目名</span><br></pre></td></tr></table></figure><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qlkroqh3j32801cgn9j.jpg" alt="image.png"></p><h4 id="7-安装Gin"><a href="#7-安装Gin" class="headerlink" title="7. 安装Gin"></a><font color=DarkOrange>7. 安装Gin</font></h4><p>在终端通过命令的方式下载并安装<code>Gin</code>包</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go get -u github.com/gin-gonic/gin</span><br></pre></td></tr></table></figure><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qlpgvihqj32801cg1kx.jpg" alt="image.png"></p><h4 id="8-main程序"><a href="#8-main程序" class="headerlink" title="8. main程序"></a><font color=DarkOrange>8. main程序</font></h4><p>新建<code>main.go</code>文件，在<code>main</code>文件里编写第一个<code>Gin</code>示例</p><p>在<code>main</code>文件所在的目录下执行<code>go run main.go</code>运行<code>main</code>函数</p><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qly589jgj32801ce1f4.jpg" alt="image.png"></p><h4 id="9-浏览器访问"><a href="#9-浏览器访问" class="headerlink" title="9. 浏览器访问"></a><font color=DarkOrange>9. 浏览器访问</font></h4><p>在浏览器通过访问<code>localhost:8080/ping</code>或<code>127.0.0.1:8080/ping</code>的方式访问服务</p><div align="center"><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qlxcsj7bj30pc09040d.jpg" alt="image.png" style="zoom:67%;" /></div><h4 id="10-添加文件"><a href="#10-添加文件" class="headerlink" title="10. 添加文件"></a><font color=DarkOrange>10. 添加文件</font></h4><p>在项目里添加<code>.gitignore</code>和<code>README.md</code>文件</p><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qm74jjgtj31880sw791.jpg" alt="image.png"></p><h4 id="11-提交代码"><a href="#11-提交代码" class="headerlink" title="11. 提交代码"></a><font color=DarkOrange>11. 提交代码</font></h4><p>编写代码之后，在本地进行代码提交</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">git add 文件名</span><br><span class="line">git commit -m <span class="string">&quot;本次提交描述&quot;</span></span><br><span class="line">git push origin dev</span><br></pre></td></tr></table></figure><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qmdi8artj32801cih82.jpg" alt="image.png"></p><h4 id="12-合并代码"><a href="#12-合并代码" class="headerlink" title="12. 合并代码"></a><font color=DarkOrange>12. 合并代码</font></h4><p>代码从本地提交到远程仓库之后，需要在远程仓库对代码进行合并</p><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qn4b53z1j328016gdy4.jpg" alt="image.png"></p><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qn5bc2u0j328016g7ma.jpg" alt="image.png"></p><p><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h8qn67pkhaj328016i1ew.jpg" alt="image.png"></p><p>此项目会继续更新，敬请期待…</p><hr>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;通过GitHub + Go + Gin创建RESTful风格的项目，搭建一个基础的脚手架&lt;/p&gt;
&lt;p&gt;完整项目GitHub地址：&lt;a href=&quot;https://github.com/huajun-chen/GinRESTful&quot;&gt;点击跳转&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="Go" scheme="https://huajun-chen.github.io/tags/Go/"/>
    
  </entry>
  
  <entry>
    <title>Docker、k8s、etcd面试题</title>
    <link href="https://huajun-chen.github.io/2022/11/24/Docker%E3%80%81k8s%E9%9D%A2%E8%AF%95%E9%A2%98/"/>
    <id>https://huajun-chen.github.io/2022/11/24/Docker%E3%80%81k8s%E9%9D%A2%E8%AF%95%E9%A2%98/</id>
    <published>2022-11-24T10:10:56.000Z</published>
    <updated>2023-03-21T16:12:42.961Z</updated>
    
    <content type="html"><![CDATA[<p>常见Docker、K8S、etcd面试题整理</p><hr><h4 id="1-什么是Docker"><a href="#1-什么是Docker" class="headerlink" title="1. 什么是Docker"></a><font color=DarkOrange>1. 什么是Docker</font></h4><ol><li>Docker是一种开源的容器化平台</li><li>它允许开发者在容器中打包、部署和运行应用程序</li><li>Docker容器是一种轻量级、可移植的虚拟化技术</li><li>Docker平台的优点是它可以将应用程序及其所有依赖项打包成一个轻量级的容器</li><li>这些容器可以在任何地方运行，无需对底层系统进行修改</li><li>Docker容器提供了一种更加简单和高效的方式来管理应用程序的生命周期，从开发、测试到部署和运行</li></ol><h4 id="2-Docker镜像和容器之间有什么区别"><a href="#2-Docker镜像和容器之间有什么区别" class="headerlink" title="2. Docker镜像和容器之间有什么区别"></a><font color=DarkOrange>2. Docker镜像和容器之间有什么区别</font></h4><ol><li>镜像是一个文件，它包含了应用程序和运行时所需要的依赖库、环境变量、配置文件等，它是只读的。容器则是在镜像的基础上创建的一个可运行的实例，它可以被启动、停止、删除，容器中的数据可以进行修改和存储</li><li>镜像可以看作是容器的模板，容器的创建需要基于某个镜像。一个镜像可以创建多个容器，这些容器都是基于同一个镜像创建的，但它们可以有不同的配置和数据</li><li>镜像是静态的，一旦创建后就不会发生变化，如果需要更新镜像，需要重新构建一个新的镜像。容器则是动态的，可以随时启动、停止、删除、修改</li></ol><p><strong>注意：</strong>镜像是一个静态的文件，而容器是一个动态的实例。通过使用Docker镜像和容器，可以方便地部署和管理应用程序，使应用程序的开发和部署更加快速、可靠、灵活</p><h4 id="3-Docker的优势是什么"><a href="#3-Docker的优势是什么" class="headerlink" title="3. Docker的优势是什么"></a><font color=DarkOrange>3. Docker的优势是什么</font></h4><ol><li>简化开发流程：Docker 可以将应用程序及其依赖项打包成一个容器，使得开发人员可以在任何环境中运行相同的应用程序，避免了因开发和生产环境差异导致的应用程序运行异常</li><li>快速部署和扩展：使用 Docker 部署应用程序非常快速和简便，只需要在主机上运行 Docker 容器即可。此外，可以根据需要快速地扩展应用程序的容量，而无需更改代码或重新配置服务器</li><li>节省资源：Docker 可以在同一台主机上运行多个容器，每个容器都是相互隔离的，不会相互干扰，因此可以更有效地利用服务器的资源，提高服务器的利用率</li><li>更好的可移植性：Docker 容器可以在任何支持 Docker 的系统中运行，使得应用程序更容易地在不同的平台上进行部署和迁移</li><li>更好的安全性：Docker 容器可以提供更好的安全性，容器之间相互隔离，可以避免应用程序和操作系统之间的相互干扰，同时也可以更好地控制应用程序的运行环境和访问权限</li></ol><h4 id="4-Docker的工作原理是什么"><a href="#4-Docker的工作原理是什么" class="headerlink" title="4. Docker的工作原理是什么"></a><font color=DarkOrange>4. Docker的工作原理是什么</font></h4><p>Docker 的工作原理是将应用程序及其依赖项打包成一个容器，并在主机上运行这个容器，从而实现应用程序的部署和管理。同时，Docker 容器之间相互隔离，使得容器之间不会相互干扰，从而提高了应用程序的安全性和稳定性</p><ol><li>创建 Docker 镜像：将应用程序和其依赖项打包成一个 Docker 镜像文件，Docker 镜像是只读的，可以被用来创建多个容器</li><li>运行 Docker 容器：使用 Docker 镜像创建一个容器，容器是 Docker 镜像的一个运行实例，容器是可读写的，并可以被启动、停止、删除</li><li>容器与主机系统的通信：Docker 容器与主机系统之间可以进行通信，容器可以访问主机系统上的文件系统和网络资源，而主机系统也可以访问容器的文件系统和网络资源</li><li>容器之间的隔离：Docker 容器之间是相互隔离的，每个容器都有自己的文件系统、网络和进程空间，避免了容器之间的相互干扰</li><li>Docker 仓库：Docker 仓库是用于存储和分享 Docker 镜像的地方，用户可以将自己创建的 Docker 镜像上传到 Docker 仓库，也可以从 Docker 仓库中下载别人创建的 Docker 镜像</li></ol><h4 id="5-如何在Docker中创建镜像"><a href="#5-如何在Docker中创建镜像" class="headerlink" title="5. 如何在Docker中创建镜像"></a><font color=DarkOrange>5. 如何在Docker中创建镜像</font></h4><ol><li>创建 Dockerfile：Dockerfile 是一个文本文件，用于描述如何构建 Docker 镜像。它包括基础镜像、应用程序代码、依赖项和配置等信息</li><li>编写 Dockerfile：在 Dockerfile 中，可以使用各种 Docker 指令来构建镜像，例如 FROM、RUN、COPY、EXPOSE、CMD 等。FROM 指令指定基础镜像，RUN 指令用于执行命令，COPY 指令用于复制文件，EXPOSE 指令用于声明容器将监听哪些端口，CMD 指令用于定义容器启动后要执行的命令</li><li>构建 Docker 镜像：使用 docker build 命令来构建 Docker 镜像，需要指定 Dockerfile 的路径和镜像名称及版本号。例如，docker build -t myimage:v1.0</li><li>测试和上传 Docker 镜像：构建完成后，可以使用 docker run 命令来启动容器测试镜像。如果测试通过，可以使用 docker push 命令将镜像上传到 Docker Hub 或其他 Docker 仓库中，以供其他人使用</li></ol><h4 id="6-Docker有哪些常用命令"><a href="#6-Docker有哪些常用命令" class="headerlink" title="6. Docker有哪些常用命令"></a><font color=DarkOrange>6. Docker有哪些常用命令</font></h4><table><thead><tr><th>命令</th><th>描述</th></tr></thead><tbody><tr><td><code>docker run</code></td><td>运行一个容器</td></tr><tr><td><code>docker stop</code></td><td>停止一个或多个容器</td></tr><tr><td><code>docker ps</code></td><td>列出运行中的容器</td></tr><tr><td><code>docker images</code></td><td>列出本地镜像</td></tr><tr><td><code>docker build</code></td><td>根据 Dockerfile 创建镜像</td></tr><tr><td><code>docker pull</code></td><td>从 Docker 镜像仓库中拉取镜像</td></tr><tr><td><code>docker push</code></td><td>将本地镜像推送到 Docker 镜像仓库</td></tr><tr><td><code>docker exec</code></td><td>在运行中的容器中执行命令</td></tr><tr><td><code>docker rm</code></td><td>删除一个或多个容器</td></tr><tr><td><code>docker rmi</code></td><td>删除一个或多个镜像</td></tr><tr><td><code>docker inspect</code></td><td>显示容器或镜像的详细信息</td></tr><tr><td><code>docker logs</code></td><td>查看容器的日志输出</td></tr><tr><td><code>docker network</code></td><td>管理 Docker 网络</td></tr><tr><td><code>docker-compose</code></td><td>使用 Compose 定义和运行多容器应用程序</td></tr><tr><td><code>docker attach</code></td><td>连接到正在运行的容器的 STDIN、STDOUT 和 STDERR</td></tr></tbody></table><h4 id="7-如何在Docker容器内执行命令"><a href="#7-如何在Docker容器内执行命令" class="headerlink" title="7. 如何在Docker容器内执行命令"></a><font color=DarkOrange>7. 如何在Docker容器内执行命令</font></h4><p>可以使用<code>docker exec</code>命令在Docker容器内部执行命令</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> [OPTIONS] CONTAINER COMMAND [ARG...]</span><br></pre></td></tr></table></figure><p>其中，<code>OPTIONS</code>表示执行命令的一些选项，例如：</p><ul><li><code>-i</code>：表示使用交互模式（stdin）</li><li><code>-t</code>：表示使用终端模式（tty）</li></ul><p><code>CONTAINER</code>表示要执行命令的容器的名称或ID</p><p><code>COMMAND</code>表示要在容器中执行的命令</p><p><code>ARG</code>表示命令的参数</p><p>例如，要在名为<code>my-container</code>的容器中执行<code>ls -l</code>命令，可以使用以下命令：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> -it my-container <span class="built_in">ls</span> -l</span><br></pre></td></tr></table></figure><h4 id="8-如何在Docker容器之间进行通信"><a href="#8-如何在Docker容器之间进行通信" class="headerlink" title="8. 如何在Docker容器之间进行通信"></a><font color=DarkOrange>8. 如何在Docker容器之间进行通信</font></h4><p>Docker会自动创建一个默认的 bridge 网络来为容器提供网络服务，也可以通过创建自定义网络来实现容器之间的通信</p><ol><li>使用容器 IP 地址进行通信：每个容器都有一个唯一的 IP 地址，可以通过这个地址来实现容器之间的通信。例如，可以在一个容器中使用另一个容器的 IP 地址来进行网络通信</li><li>使用容器名称进行通信：Docker 容器可以使用 <code>--name</code> 参数指定容器名称，可以在容器之间使用名称来进行通信。例如，可以在一个容器中使用 <code>ping</code> 命令来测试另一个容器的可达性</li><li>使用容器端口进行通信：容器可以通过暴露端口来与外部网络进行通信，也可以通过容器之间的端口映射来实现容器之间的通信。例如，可以在一个容器中使用另一个容器的暴露端口来进行网络通信</li><li>使用 Docker 网络进行通信：Docker 提供了多种网络驱动程序来支持容器之间的通信，可以使用 <code>docker network create</code> 命令来创建自定义网络，并使用 <code>--network</code> 参数指定容器所属的网络。例如，可以在一个容器中使用另一个容器的 IP 地址或容器名称来进行网络通信</li></ol><p><strong>注意：</strong>如果容器之间需要进行通信，需要在启动容器时使用 <code>--link</code> 参数或在创建自定义网络时进行相关配置，以便容器能够互相发现和访问</p><h4 id="9-Docker容器的生命周期是什么"><a href="#9-Docker容器的生命周期是什么" class="headerlink" title="9. Docker容器的生命周期是什么"></a><font color=DarkOrange>9. Docker容器的生命周期是什么</font></h4><ol><li>创建阶段：通过 <code>docker run</code> 命令创建一个容器，Docker 会从镜像中创建容器，并分配唯一的容器 ID。在创建容器时，可以设置容器的名称、网络配置、端口映射等参数</li><li>运行阶段：在容器创建后，可以使用 <code>docker start</code> 命令来启动容器。一旦容器启动，Docker 就会在容器中执行指定的命令或应用程序。在运行阶段，可以使用 <code>docker stop</code> 命令停止容器，或使用 <code>docker restart</code> 命令重新启动容器</li><li>暂停阶段：在容器运行中，可以使用 <code>docker pause</code> 命令将容器暂停，此时容器中的所有进程都会被挂起。可以使用 <code>docker unpause</code> 命令恢复容器运行</li><li>终止阶段：当容器不再需要时，可以使用 <code>docker rm</code> 命令删除容器。在删除容器之前，需要先停止容器。可以使用 <code>docker kill</code> 命令强制停止容器</li><li>导出和导入阶段：在容器运行中，可以使用 <code>docker export</code> 命令将容器打包为一个 tar 文件，然后可以将这个文件拷贝到另一个 Docker 主机上进行导入，使用 <code>docker import</code> 命令导入镜像</li></ol><h4 id="10-如何在Docker中进行数据管理"><a href="#10-如何在Docker中进行数据管理" class="headerlink" title="10. 如何在Docker中进行数据管理"></a><font color=DarkOrange>10. 如何在Docker中进行数据管理</font></h4><ol><li>数据卷（Volume）：数据卷是一种持久化存储的方式，可以将宿主机上的目录或文件夹挂载到容器中，从而实现在容器中对数据进行持久化存储的目的。使用数据卷可以将数据独立于容器进行管理，使容器的生命周期与数据的生命周期分离。可以使用 <code>docker volume</code> 命令创建和管理数据卷</li><li>绑定挂载（Bind Mount）：绑定挂载是一种将宿主机上的文件或目录直接挂载到容器中的方式，可以将宿主机上的文件直接暴露给容器，从而实现容器与宿主机之间的数据共享。使用绑定挂载可以方便地在容器和宿主机之间进行数据传输。可以使用 <code>docker run</code> 命令的 <code>-v</code> 参数指定绑定挂载</li><li>共享存储（Shared Storage）：共享存储是一种将数据存储在独立的存储系统中，并将存储系统挂载到多个容器中的方式，可以实现多个容器之间的数据共享。使用共享存储可以避免数据重复存储，节省存储空间，同时也能够提高数据的可靠性和可用性。常见的共享存储包括 NFS、GlusterFS、Ceph 等</li><li>Docker Compose：Docker Compose 是一种用于定义和运行多个 Docker 容器的工具，可以通过编写 YAML 文件来定义容器的运行方式、数据卷、网络、环境变量等属性，从而实现对多个容器的统一管理和协调。通过 Docker Compose，可以方便地进行数据管理，实现容器之间的数据共享和传输</li></ol><h4 id="11-Docker和虚拟机的区别是什么"><a href="#11-Docker和虚拟机的区别是什么" class="headerlink" title="11. Docker和虚拟机的区别是什么"></a><font color=DarkOrange>11. Docker和虚拟机的区别是什么</font></h4><ol><li>架构差异：虚拟机是基于硬件的虚拟化技术，通过在物理主机上安装虚拟机监控器（Hypervisor）来模拟硬件，从而实现在虚拟机中运行多个操作系统。而 Docker 则是基于容器的虚拟化技术，利用 Linux 内核的容器特性，在单个物理主机上运行多个容器，每个容器都是相互隔离的运行环境</li><li>资源占用：由于虚拟机需要模拟硬件环境，因此每个虚拟机都需要独立的操作系统和硬件资源，包括 CPU、内存、硬盘等，相对于 Docker 耗费更多的资源。而 Docker 则是共享物理主机的资源，容器之间共享操作系统和内核，不需要额外的资源占用</li><li>启动速度：由于虚拟机需要启动一个完整的操作系统和硬件环境，因此启动时间较长，一般需要几分钟的时间。而 Docker 则可以在几秒钟内启动一个容器，由于容器是共享物理主机的操作系统和内核，因此启动速度相对较快</li><li>部署与管理：虚拟机通常需要进行全量部署和管理，包括操作系统、应用程序和依赖库等，相对较为复杂。而 Docker 则可以将应用程序及其依赖库打包成一个容器镜像，可以快速部署和管理，避免了应用程序的依赖问题</li></ol><p>Docker和虚拟机的区别主要在于架构、资源占用、启动速度和部署与管理等方面。相对于虚拟机，Docker 更加轻量级，启动速度更快，部署和管理更加方便，更适合于微服务架构和容器化部署</p><h4 id="12-如何进行Docker的日志管理"><a href="#12-如何进行Docker的日志管理" class="headerlink" title="12. 如何进行Docker的日志管理"></a><font color=DarkOrange>12. 如何进行Docker的日志管理</font></h4><ol><li><p>使用 Docker logs 命令：可以使用 Docker logs 命令查看容器的日志</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker logs &lt;container_name or container_id&gt;</span><br></pre></td></tr></table></figure><p>此命令可以查看容器的标准输出和标准错误输出。默认情况下，容器的日志会输出到控制台。可以使用 –tail 参数指定输出日志的行数，使用 -f 参数实时跟踪容器日志</p></li><li><p>挂载日志目录：可以通过挂载容器的日志目录到本地主机，实现容器日志的持久化存储和管理。可以使用 -v 参数将主机目录挂载到容器中</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name my_container -v /path/to/logs:/logs my_image</span><br></pre></td></tr></table></figure><p>此命令将本地主机上的 &#x2F;path&#x2F;to&#x2F;logs 目录挂载到容器中的 &#x2F;logs 目录。容器中的日志将会保存到本地主机的 &#x2F;path&#x2F;to&#x2F;logs 目录下</p></li><li><p>使用第三方日志收集工具：可以使用第三方日志收集工具，如 Fluentd、Logstash、Graylog 等，实现容器日志的集中管理和分析。这些工具可以将容器日志收集到统一的地方，并提供日志搜索、过滤、分析和可视化等功能</p></li></ol><h4 id="13-Docker的网络模式有哪些"><a href="#13-Docker的网络模式有哪些" class="headerlink" title="13. Docker的网络模式有哪些"></a><font color=DarkOrange>13. Docker的网络模式有哪些</font></h4><ol><li>桥接模式（Bridge）：Docker 默认采用桥接模式，每个容器都分配一个 IP 地址，并可以通过容器名称进行互相访问。桥接模式适用于单机多容器的情况</li><li>主机模式（Host）：容器与主机共享网络栈，使用主机的 IP 地址，适用于需要最大网络性能和最小网络延迟的情况</li><li>网络模式（Network）：容器可以通过连接到同一个网络来进行通信。可以使用 Docker 自带的 bridge 网络或者用户自定义网络</li><li>空网络模式（None）：容器没有网络接口，适用于不需要网络访问的容器</li><li>Overlay 网络模式：适用于跨多个 Docker 宿主机的容器网络通信，可以在 Docker Swarm 中使用</li></ol><h4 id="14-如何在Docker中使用环境变量"><a href="#14-如何在Docker中使用环境变量" class="headerlink" title="14. 如何在Docker中使用环境变量"></a><font color=DarkOrange>14. 如何在Docker中使用环境变量</font></h4><p>在 Docker 中，可以使用环境变量来传递配置信息，例如数据库连接地址、端口号、用户名、密码等敏感信息。在容器启动时，可以将环境变量传递给容器，并在容器中使用这些环境变量</p><p>Docker 支持两种方式来设置环境变量：</p><ol><li><p>Dockerfile 中使用 ENV 指令：在 Dockerfile 中可以使用 ENV 指令来设置环境变量</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:latest</span><br><span class="line"><span class="keyword">ENV</span> DB_HOST=localhost \</span><br><span class="line">    DB_PORT=<span class="number">3306</span> \</span><br><span class="line">    DB_USER=root \</span><br><span class="line">    DB_PASS=<span class="number">123456</span></span><br></pre></td></tr></table></figure></li><li><p>在容器启动时使用 -e 参数：可以在启动容器时使用 -e 参数来设置环境变量</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name my_container -e DB_HOST=localhost -e DB_PORT=3306 my_image</span><br></pre></td></tr></table></figure></li></ol><h4 id="15-如何在Docker中使用卷"><a href="#15-如何在Docker中使用卷" class="headerlink" title="15. 如何在Docker中使用卷"></a><font color=DarkOrange>15. 如何在Docker中使用卷</font></h4><p>在 Docker 中，可以使用卷（Volume）来管理容器中的数据，卷可以将主机文件系统或其他容器的文件系统挂载到容器中，从而实现容器中数据的持久化和共享</p><p>Docker 支持三种类型的卷：</p><ol><li><p>绑定挂载（Bind Mount）：将主机文件系统中的目录或文件挂载到容器中，可以通过 -v 参数来实现</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -v /path/on/host:/path/on/container my_image</span><br></pre></td></tr></table></figure><p>这个命令将会将主机文件系统中的 &#x2F;path&#x2F;on&#x2F;host 目录挂载到容器中的 &#x2F;path&#x2F;on&#x2F;container 目录。</p></li><li><p>匿名卷（Anonymous Volume）：Docker 会自动为容器创建一个匿名卷，可以使用 -v 参数来实现</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -v /path/on/container my_image</span><br></pre></td></tr></table></figure><p>这个命令将会为容器创建一个匿名卷，并将其挂载到容器中的 &#x2F;path&#x2F;on&#x2F;container 目录</p></li><li><p>命名卷（Named Volume）：可以为容器创建一个命名卷，并将其挂载到容器中，可以使用 -v 参数来实现，例如：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -v my_volume:/path/on/container my_image</span><br></pre></td></tr></table></figure><p>这个命令将会创建一个名为 my_volume 的命名卷，并将其挂载到容器中的 &#x2F;path&#x2F;on&#x2F;container 目录</p></li></ol><p>在容器中使用卷时，可以像使用普通目录一样使用，数据将会持久化到卷中，即使容器被删除也不会丢失。可以使用<code>docker volume ls</code>命令来查看当前主机上的卷列表，使用<code>docker volume rm</code>命令来删除不需要的卷</p><h4 id="16-如何在Docker中进行多容器管理"><a href="#16-如何在Docker中进行多容器管理" class="headerlink" title="16. 如何在Docker中进行多容器管理"></a><font color=DarkOrange>16. 如何在Docker中进行多容器管理</font></h4><p>使用Docker Compose来进行多容器管理。Docker Compose是一个命令行工具，可用于定义和运行多容器Docker应用程序</p><ol><li><p>创建Docker Compose文件：使用YAML格式定义多容器应用程序的服务、网络和卷等元素</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">web:</span></span><br><span class="line">    <span class="attr">build:</span> <span class="string">.</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;8000:8000&quot;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">.:/code</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">db</span></span><br><span class="line">  <span class="attr">db:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">postgres</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">POSTGRES_PASSWORD:</span> <span class="string">example</span></span><br></pre></td></tr></table></figure><p>在此示例中，定义了两个服务：web和db。Web服务构建了一个本地Dockerfile，将端口8000映射到主机上，并将当前目录挂载到容器中的&#x2F;code目录。它还依赖于db服务。db服务使用PostgreSQL映像，并设置一个环境变量来设置数据库密码</p></li><li><p>启动多容器应用程序：使用Docker Compose启动应用程序</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up</span><br></pre></td></tr></table></figure><p>此命令将启动定义在Docker Compose文件中的所有服务</p></li><li><p>关闭多容器应用程序：使用Docker Compose停止应用程序</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose down</span><br></pre></td></tr></table></figure><p>此命令将停止所有正在运行的容器，并删除它们</p></li></ol><h4 id="17-如何进行Docker的安全管理"><a href="#17-如何进行Docker的安全管理" class="headerlink" title="17. 如何进行Docker的安全管理"></a><font color=DarkOrange>17. 如何进行Docker的安全管理</font></h4><ol><li>更新Docker版本：保持Docker版本最新可以避免已知的漏洞和安全问题</li><li>安全的镜像源：使用官方的Docker Hub镜像源，避免使用未知的镜像源</li><li>配置安全的Docker daemon：Docker daemon是Docker的后台进程，需要进行安全配置，包括限制网络访问和授权用户权限等</li><li>配置容器的安全性：可以通过限制容器的资源使用和网络访问等方式提高容器的安全性</li><li>使用安全的应用程序：选择安全的应用程序和镜像，并配置适当的安全策略</li><li>实施适当的访问控制：限制Docker daemon和容器的访问权限，并限制用户的权限</li><li>监控和日志：实时监控Docker daemon和容器，并记录日志以便跟踪和审计</li></ol><h4 id="18-Docker-Compose是什么"><a href="#18-Docker-Compose是什么" class="headerlink" title="18. Docker Compose是什么"></a><font color=DarkOrange>18. Docker Compose是什么</font></h4><p>Docker Compose是Docker的一个工具，用于定义和运行多个Docker容器的应用程序。它允许开发人员在单个配置文件中定义一个应用程序的多个服务，以便可以方便地启动、停止和管理整个应用程序。Docker Compose的主要目的是简化多个容器的应用程序的部署和管理过程</p><p>使用Docker Compose，开发人员可以使用一个YAML文件来定义整个应用程序的服务、网络和卷等元素。在该文件中，开发人员可以定义每个服务的容器镜像、容器名称、容器端口、环境变量、容器间网络连接等等。Docker Compose还可以自动启动容器并将它们连接在一起，从而创建一个完整的应用程序</p><p>Docker Compose还支持覆盖（override）和扩展（extend），这使得在不同的环境中部署应用程序变得更加灵活和便捷。例如，可以在开发环境中覆盖一些配置，以适应生产环境中的需求，或者可以在多个部署环境中共享基本配置，以简化部署流程</p><h4 id="19-如何在Docker中使用多阶段构建"><a href="#19-如何在Docker中使用多阶段构建" class="headerlink" title="19. 如何在Docker中使用多阶段构建"></a><font color=DarkOrange>19. 如何在Docker中使用多阶段构建</font></h4><p>多阶段构建（multi-stage build）是一种技术，它可以将一个Dockerfile分为多个阶段，每个阶段都可以使用不同的基础镜像，并可以共享文件系统。使用多阶段构建，可以将一个大型应用程序的构建过程分解成多个步骤，从而优化构建过程的速度和容器大小</p><ol><li><p>在Dockerfile中定义多个阶段，并为每个阶段选择不同的基础镜像</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">FROM</span> <span class="string">node:10-alpine</span> <span class="string">AS</span> <span class="string">builder</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 定义第一个阶段</span></span><br><span class="line"><span class="string">RUN</span> <span class="string">...</span></span><br><span class="line"></span><br><span class="line"><span class="string">FROM</span> <span class="string">nginx:alpine</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 定义第二个阶段</span></span><br><span class="line"><span class="string">RUN</span> <span class="string">...</span></span><br></pre></td></tr></table></figure></li><li><p>在每个阶段中执行相应的构建命令，并将结果保存到容器中</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">FROM</span> <span class="string">node:10-alpine</span> <span class="string">AS</span> <span class="string">builder</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 构建应用程序</span></span><br><span class="line"><span class="string">RUN</span> <span class="string">npm</span> <span class="string">install</span> <span class="string">&amp;&amp;</span> <span class="string">npm</span> <span class="string">build</span></span><br><span class="line"></span><br><span class="line"><span class="string">FROM</span> <span class="string">nginx:alpine</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 复制应用程序到nginx镜像中</span></span><br><span class="line"><span class="string">COPY</span> <span class="string">--from=builder</span> <span class="string">/app/dist</span> <span class="string">/usr/share/nginx/html</span></span><br></pre></td></tr></table></figure></li><li><p>在最终的容器中只包含必要的文件和组件，以减少容器的大小</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">FROM</span> <span class="string">nginx:alpine</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 只复制必要的文件</span></span><br><span class="line"><span class="string">COPY</span> <span class="string">--from=builder</span> <span class="string">/app/dist</span> <span class="string">/usr/share/nginx/html</span></span><br></pre></td></tr></table></figure></li></ol><p>使用多阶段构建可以有效地减少Docker镜像的大小，并加快应用程序的构建过程。同时，由于每个阶段都可以使用不同的基础镜像，可以选择最适合特定用途的镜像，从而提高应用程序的性能和安全性</p><h4 id="20-如何在Docker中进行负载均衡"><a href="#20-如何在Docker中进行负载均衡" class="headerlink" title="20. 如何在Docker中进行负载均衡"></a><font color=DarkOrange>20. 如何在Docker中进行负载均衡</font></h4><ol><li><p>使用Docker Swarm模式</p><p>Docker Swarm是Docker官方提供的容器编排工具，它可以管理多个Docker容器并将它们分布在多个节点上。在Docker Swarm模式下，可以使用内置的负载均衡机制进行服务发现和路由，从而实现负载均衡</p><p>首先，需要创建一个Docker Swarm集群，然后在集群中创建服务并指定多个副本。Swarm会自动将服务副本分布在不同的节点上，并使用内置的负载均衡机制将请求路由到适当的服务副本</p></li><li><p>使用第三方负载均衡器</p><p>除了使用Docker Swarm内置的负载均衡机制外，还可以使用第三方负载均衡器进行负载均衡。常用的负载均衡器包括Nginx、HAProxy、Traefik等</p><p>使用第三方负载均衡器需要将负载均衡器部署在Docker集群的外部，并将请求路由到集群内的Docker容器。为了实现这一点，可以使用Docker的服务发现机制和网络机制</p><p>具体地，需要在Docker容器中定义一个共享的网络，并将每个服务都加入到这个网络中。然后，使用负载均衡器将请求路由到网络中的容器。可以使用Docker的DNS解析服务来查找容器的IP地址</p></li></ol><hr><hr><h4 id="21-什么是K8S"><a href="#21-什么是K8S" class="headerlink" title="21. 什么是K8S"></a><font color=DarkOrange>21. 什么是K8S</font></h4><p>Kubernetes（通常简称为“K8s”）是一个开源的容器编排和管理平台，它最初由Google开发，并于2014年发布为开源软件。Kubernetes可以自动化地部署、扩展和管理容器化的应用程序，提供了诸如负载均衡、自动伸缩、容器间通信、存储管理等功能，使得应用程序更加易于部署、管理和扩展</p><p>Kubernetes提供了一组API和工具，可以管理由多个Docker容器组成的应用程序，这些容器可以在多个节点上运行，并可以自动扩展和收缩以满足负载要求。Kubernetes支持多种容器运行时，包括Docker、containerd、CRI-O等</p><p>Kubernetes的核心概念包括：</p><ul><li>Pod：Kubernetes中最小的调度单元，由一个或多个紧密相关的容器组成，可以共享网络和存储。</li><li>Service：为一组Pod提供稳定的网络端口和DNS名称，使得应用程序可以轻松地与其他组件进行通信</li><li>ReplicaSet：用于控制一组Pod的副本数量，确保应用程序具有所需的可用性和性能</li><li>Deployment：用于管理Pod和ReplicaSet的更新，支持滚动更新和回滚操作</li><li>ConfigMap和Secret：用于管理应用程序的配置和敏感信息</li><li>Volume：提供可插拔的存储插件，用于管理应用程序的数据持久化</li></ul><p>Kubernetes是一个强大而灵活的容器编排平台，它可以简化容器化应用程序的部署、管理和扩展，并提供了丰富的功能和API，支持在多云环境中无缝运行</p><h4 id="22-K8S的核心概念有哪些"><a href="#22-K8S的核心概念有哪些" class="headerlink" title="22. K8S的核心概念有哪些"></a><font color=DarkOrange>22. K8S的核心概念有哪些</font></h4><ol><li>Pod：Kubernetes中最小的调度单元，由一个或多个紧密相关的容器组成，可以共享网络和存储。Pod是Kubernetes中最基本的部署单元，是一个可以运行容器的环境</li><li>Service：为一组Pod提供稳定的网络端口和DNS名称，使得应用程序可以轻松地与其他组件进行通信。Service是Pod的抽象，是一组Pod的逻辑分组，可以在Kubernetes集群内提供稳定的服务发现和负载均衡</li><li>ReplicaSet：用于控制一组Pod的副本数量，确保应用程序具有所需的可用性和性能。ReplicaSet是一种控制器，它可以根据用户定义的期望状态来管理Pod的副本数量</li><li>Deployment：用于管理Pod和ReplicaSet的更新，支持滚动更新和回滚操作。Deployment是一种高级控制器，可以管理多个ReplicaSet，支持无宕机更新和自动回滚操作</li><li>ConfigMap和Secret：用于管理应用程序的配置和敏感信息。ConfigMap用于存储应用程序的配置信息，Secret用于存储敏感信息，如密码和证书</li><li>Volume：提供可插拔的存储插件，用于管理应用程序的数据持久化。Volume是一种抽象，它可以将物理存储和应用程序的文件系统抽象为一个逻辑卷</li><li>Namespace：用于隔离和管理Kubernetes集群内的资源，可以将一个集群划分为多个虚拟集群。Namespace提供了一种逻辑隔离的机制，使得不同的用户或应用程序可以共享同一个Kubernetes集群而不会相互干扰</li></ol><h4 id="23-K8S的工作原理是什么"><a href="#23-K8S的工作原理是什么" class="headerlink" title="23. K8S的工作原理是什么"></a><font color=DarkOrange>23. K8S的工作原理是什么</font></h4><p><strong>工作原理：</strong></p><ol><li>Master组件：Kubernetes集群的控制中心，主要由以下组件组成：</li></ol><ul><li>API Server：提供REST API，用于接收和处理集群内的各种请求</li><li>etcd：分布式键值存储，用于存储Kubernetes集群的配置信息和状态</li><li>Controller Manager：用于管理集群内的各种控制器，如ReplicaSet、Deployment等</li><li>Scheduler：用于调度Pod到合适的Node上运行</li></ul><ol start="2"><li>Node组件：运行应用程序容器的主机，主要由以下组件组成：</li></ol><ul><li>kubelet：运行在每个Node上的代理程序，负责管理Node上的容器</li><li>kube-proxy：负责为Service提供网络代理和负载均衡功能</li><li>容器运行时：负责运行应用程序容器，如Docker、rkt等</li></ul><ol start="3"><li>Pod：Kubernetes中最小的调度单元，由一个或多个紧密相关的容器组成，可以共享网络和存储</li><li>Service：为一组Pod提供稳定的网络端口和DNS名称，使得应用程序可以轻松地与其他组件进行通信</li></ol><p><strong>工作流程：</strong></p><ol><li>用户通过kubectl或其他工具向Kubernetes集群发送请求，请求可能是创建、更新、删除Pod、Service等对象</li><li>API Server接收并处理请求，将对象的配置信息和状态信息存储到etcd中</li><li>Controller Manager通过监听etcd的变化，发现有新的或修改的对象时，会相应地更新集群内的控制器（如ReplicaSet、Deployment等）</li><li>Scheduler根据集群内的资源情况和Pod的需求，将Pod调度到合适的Node上运行</li><li>kubelet在Node上创建和管理Pod，并与API Server保持联系，汇报Pod的状态和健康情况</li><li>kube-proxy为Service提供网络代理和负载均衡功能，使得应用程序可以通过Service访问到集群内的其他组件</li></ol><h4 id="24-如何在K8S中创建Pod"><a href="#24-如何在K8S中创建Pod" class="headerlink" title="24. 如何在K8S中创建Pod"></a><font color=DarkOrange>24. 如何在K8S中创建Pod</font></h4><p>在Kubernetes中创建Pod需要编写一个Pod描述文件，其中包括Pod的名称、容器镜像、容器端口等信息。然后使用kubectl工具或其他工具将该描述文件提交给Kubernetes集群即可</p><p>下面是一个简单的Pod描述文件示例：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-pod</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">my-container</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx:latest</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><p>该描述文件中定义了一个名为<code>my-pod</code>的Pod，其中包含一个名为<code>my-container</code>的容器，使用<code>nginx:latest</code>镜像，并将容器的端口映射到80端口</p><p>要将该描述文件提交给Kubernetes集群，可以使用以下命令：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl create -f my-pod.yaml</span><br></pre></td></tr></table></figure><p>该命令将读取<code>my-pod.yaml</code>文件中的Pod描述信息，并创建该Pod</p><p>除了使用描述文件创建Pod外，还可以使用kubectl命令直接创建Pod。例如，以下命令将创建一个名为<code>my-pod</code>的Pod，并使用<code>nginx:latest</code>镜像：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl run my-pod --image=nginx:latest</span><br></pre></td></tr></table></figure><p>无论使用描述文件还是kubectl命令创建Pod，Kubernetes都会将该Pod的定义信息存储在etcd中，并使用调度器将其调度到集群中的某个Node上运行</p><h4 id="25-如何在K8S中扩展集群"><a href="#25-如何在K8S中扩展集群" class="headerlink" title="25. 如何在K8S中扩展集群"></a><font color=DarkOrange>25. 如何在K8S中扩展集群</font></h4><p>在Kubernetes中，可以通过添加更多的Node节点来扩展集群。Kubernetes集群的Node节点是运行容器和Pod的主机，因此增加Node节点可以增加集群的容量和计算资源</p><p>以下是在Kubernetes中扩展集群的一般步骤：</p><ol><li>获取新的Node节点：可以在公共云上购买新的虚拟机，或者在本地环境中添加新的物理机器</li><li>配置新的Node节点：需要在新的Node节点上安装Docker、kubelet和kubectl等必要的软件组件，并配置它们与Kubernetes集群通信。可以使用kubeadm等工具来简化这个过程</li><li>将新的Node节点添加到Kubernetes集群：可以使用kubeadm工具或其他工具将新的Node节点加入到Kubernetes集群中。在加入集群之前，需要将新的Node节点与Kubernetes集群中的其他节点进行身份验证和授权</li><li>部署Pod和服务：当新的Node节点加入到Kubernetes集群中后，可以使用Kubernetes API和kubectl命令来部署新的Pod和服务，并将它们调度到新的Node节点上运行</li></ol><p><strong>注意：</strong>当集群规模变大时，需要考虑集群管理的自动化和标准化。可以使用Kubernetes Operator、自动扩缩容等工具来简化集群管理的流程，并确保集群的稳定性和高可用性</p><h4 id="26-如何在K8S中进行滚动升级"><a href="#26-如何在K8S中进行滚动升级" class="headerlink" title="26. 如何在K8S中进行滚动升级"></a><font color=DarkOrange>26. 如何在K8S中进行滚动升级</font></h4><p>在Kubernetes中进行滚动升级需要更新应用程序的镜像或配置等内容，并将其逐步应用到集群中的Pod中，从而实现无缝的升级</p><p>以下是在Kubernetes中进行滚动升级的一般步骤：</p><ol><li>编写新的镜像或配置：需要先准备新的镜像或配置文件，这些内容将会被用于更新集群中的Pod</li><li>创建新的Deployment：可以使用kubectl命令或编写yaml文件来创建一个新的Deployment，其中指定新的镜像或配置文件。该Deployment将创建一个新的副本集（ReplicaSet），并将逐步替换旧的Pod</li><li>执行滚动升级：可以使用kubectl命令或编辑yaml文件来执行滚动升级。具体来说，需要将新的Deployment的副本数逐渐增加，同时将旧的Deployment的副本数逐渐减少。Kubernetes将自动在新旧Deployment之间进行流量切换，并确保每个Pod的生命周期在切换期间不受影响</li><li>检查升级结果：可以使用kubectl命令或Kubernetes Dashboard等工具来检查升级结果。需要确保新的Pod已经启动，并且应用程序的功能和性能没有受到影响</li></ol><p><strong>注意：</strong>滚动升级的速度可以根据实际情况进行调整。如果升级速度过快，可能会导致过多的资源消耗和应用程序的不可用。如果升级速度过慢，可能会导致应用程序的版本不一致和不必要的停机时间。可以使用kubectl命令或Kubernetes Dashboard等工具来监控升级过程，以确保升级速度的合适和应用程序的稳定性</p><h4 id="27-如何在K8S中进行水平扩展"><a href="#27-如何在K8S中进行水平扩展" class="headerlink" title="27. 如何在K8S中进行水平扩展"></a><font color=DarkOrange>27. 如何在K8S中进行水平扩展</font></h4><p>在Kubernetes中，可以通过水平扩展来增加应用程序的容量和性能，从而满足不断增长的业务需求。水平扩展是指增加应用程序的实例数，以平衡负载和提高容错能力</p><p>以下是在Kubernetes中进行水平扩展的一般步骤：</p><ol><li>编写Deployment或StatefulSet配置：需要在Deployment或StatefulSet的配置文件中指定应用程序的副本数。可以使用kubectl命令或编辑yaml文件来进行配置</li><li>执行水平扩展：可以使用kubectl命令或编辑yaml文件来执行水平扩展。具体来说，需要将Deployment或StatefulSet的副本数逐渐增加，从而增加应用程序的实例数。Kubernetes将自动将负载分配给不同的Pod，以平衡负载</li><li>监控扩展结果：可以使用kubectl命令或Kubernetes Dashboard等工具来监控扩展结果。需要确保新的Pod已经启动，并且应用程序的功能和性能没有受到影响</li></ol><p><strong>注意：</strong>水平扩展可能会导致过多的资源消耗和应用程序的不可用。可以使用Kubernetes的自动扩展功能来自动增加和减少应用程序的实例数，以满足变化的负载需求。可以使用kubectl命令或Kubernetes Dashboard等工具来监控自动扩展功能的状态和效果</p><h4 id="28-K8S中的Service是什么"><a href="#28-K8S中的Service是什么" class="headerlink" title="28. K8S中的Service是什么"></a><font color=DarkOrange>28. K8S中的Service是什么</font></h4><p>在Kubernetes中，Service是一种抽象概念，用于定义一组Pod的访问方式和网络策略。Service为一组Pod提供了一个稳定的IP地址和DNS名称，以便其他应用程序可以使用这些标识符来访问这组Pod</p><p>具体来说，Kubernetes中的Service可以将多个Pod组合成一个逻辑单元，并为这些Pod提供一个单独的入口点，从而隐藏了底层的复杂性和细节。通过定义Service，您可以轻松地让其他应用程序访问这些Pod，而无需了解这些Pod的具体细节和位置</p><p>Service还可以通过定义不同的负载均衡策略来平衡流量，以确保各个Pod之间的负载均衡。此外，Service还可以配置相关的网络策略，例如访问控制和安全策略，以确保您的应用程序网络安全</p><h4 id="29-如何在K8S中进行资源配额管理"><a href="#29-如何在K8S中进行资源配额管理" class="headerlink" title="29. 如何在K8S中进行资源配额管理"></a><font color=DarkOrange>29. 如何在K8S中进行资源配额管理</font></h4><p>使用资源配额（Resource Quotas）来限制每个命名空间（Namespace）中的资源使用量。资源配额可以限制 Pod、Deployment、ReplicaSet、Service 等资源的数量，还可以限制 CPU 和内存等资源的使用量</p><ol><li><p>创建一个命名空间（如果没有现成的命名空间）：<code>kubectl create namespace &lt;namespace-name&gt;</code></p></li><li><p>创建一个资源配额定义文件。示例如下：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">ResourceQuota</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">quota-example</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">&lt;namespace-name&gt;</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">hard:</span></span><br><span class="line">    <span class="attr">pods:</span> <span class="string">&quot;10&quot;</span></span><br><span class="line">    <span class="attr">requests.cpu:</span> <span class="string">&quot;2&quot;</span></span><br><span class="line">    <span class="attr">requests.memory:</span> <span class="string">2Gi</span></span><br><span class="line">    <span class="attr">limits.cpu:</span> <span class="string">&quot;4&quot;</span></span><br><span class="line">    <span class="attr">limits.memory:</span> <span class="string">4Gi</span></span><br></pre></td></tr></table></figure><p>在这个示例中，我们定义了一个名为 <code>quota-example</code> 的资源配额，限制了该命名空间中的 Pod 数量为 10，requests.cpu 的总计算能力为 2 CPU，requests.memory 的总内存为 2GB，limits.cpu 的总计算能力为 4 CPU，limits.memory 的总内存为 4GB</p></li><li><p>应用资源配额：<code>kubectl apply -f &lt;filename.yaml&gt;</code></p></li><li><p>检查资源配额：<code>kubectl describe quota quota-example -n &lt;namespace-name&gt;</code></p></li></ol><p>如果命名空间中的任何资源超过了资源配额中定义的限制，那么 Kubernetes 会拒绝创建新资源，直到该命名空间中的某些资源被删除或限制得到了放宽</p><h4 id="30-如何在K8S中进行多集群管理"><a href="#30-如何在K8S中进行多集群管理" class="headerlink" title="30. 如何在K8S中进行多集群管理"></a><font color=DarkOrange>30. 如何在K8S中进行多集群管理</font></h4><ol><li>使用 Kubernetes 多集群管理工具：Kubernetes 多集群管理工具（例如 kubeadm，kubespray 或 Rancher）可以帮助您在多个 Kubernetes 集群之间进行资源管理。这些工具提供了一个控制面板，可以帮助您轻松地管理和监控多个 Kubernetes 集群</li><li>使用 Kubernetes API Server：Kubernetes API Server 允许您在不同的 Kubernetes 集群之间共享资源和管理多个集群。通过配置不同集群的 API Server，您可以轻松地将资源从一个集群复制到另一个集群</li><li>使用 Istio：Istio 是一个流量管理和安全控制平台，可以帮助您在多个 Kubernetes 集群之间进行服务发现和负载均衡。使用 Istio，您可以轻松地将服务从一个集群路由到另一个集群</li><li>使用 Kubernetes 的自定义资源定义（CRD）：使用 Kubernetes 的自定义资源定义，您可以定义和扩展 Kubernetes 中的资源类型。通过使用 CRD，您可以在多个 Kubernetes 集群之间共享自定义资源类型和资源</li><li>使用 Kubernetes 跨集群服务（Kubernetes Cross-Cluster Services，KCCS）：KCCS 是 Kubernetes 的一项实验性功能，可以将服务暴露给多个集群，从而实现跨集群服务发现和负载均衡</li></ol><h4 id="31-如何在K8S中使用ConfigMap"><a href="#31-如何在K8S中使用ConfigMap" class="headerlink" title="31. 如何在K8S中使用ConfigMap"></a><font color=DarkOrange>31. 如何在K8S中使用ConfigMap</font></h4><p>在 Kubernetes 中，ConfigMap 是一种存储配置信息的资源对象。ConfigMap 可以存储一些配置文件、命令行参数、环境变量等，然后将这些配置信息注入到容器中，使得容器可以获取到正确的配置信息</p><ol><li><p>创建一个 ConfigMap 对象，可以通过以下命令创建：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl create configmap my-config --from-file=config-file.yaml</span><br></pre></td></tr></table></figure><p>该命令会创建一个名为 <code>my-config</code> 的 ConfigMap 对象，并将 <code>config-file.yaml</code> 文件中的内容存储在该对象中</p></li><li><p>在 Pod 的 YAML 文件中添加 ConfigMap 的引用，例如：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-pod</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">my-container</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">my-image</span></span><br><span class="line">    <span class="attr">env:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">MY_CONFIG</span></span><br><span class="line">      <span class="attr">valueFrom:</span></span><br><span class="line">        <span class="attr">configMapKeyRef:</span></span><br><span class="line">          <span class="attr">name:</span> <span class="string">my-config</span></span><br><span class="line">          <span class="attr">key:</span> <span class="string">config-file.yaml</span></span><br></pre></td></tr></table></figure><p>在该 YAML 文件中，我们在容器的环境变量中定义了一个名为 <code>MY_CONFIG</code> 的变量，并且使用 <code>configMapKeyRef</code> 引用了 <code>my-config</code> 中的 <code>config-file.yaml</code> 文件中的内容</p></li><li><p>使用 <code>kubectl apply</code> 命令创建 Pod 对象</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f my-pod.yaml</span><br></pre></td></tr></table></figure></li><li><p>可以使用 <code>kubectl get configmaps</code> 命令来查看 ConfigMap 对象的信息，例如：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get configmaps</span><br></pre></td></tr></table></figure><p>可以使用 <code>kubectl describe configmap</code> 命令来查看 ConfigMap 对象的详细信息，例如：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl describe configmap my-config</span><br></pre></td></tr></table></figure></li></ol><p><strong>注意：</strong>如果 ConfigMap 中存储的配置信息发生了变化，需要重新创建 Pod 对象才能使新的配置信息生效</p><h4 id="32-如何在K8S中使用Secret"><a href="#32-如何在K8S中使用Secret" class="headerlink" title="32. 如何在K8S中使用Secret"></a><font color=DarkOrange>32. 如何在K8S中使用Secret</font></h4><p>在 Kubernetes 中，Secret 是一种用于存储敏感数据的资源对象，如密码、API 密钥等，Secret 可以保证敏感数据的安全性，不被泄露</p><ol><li><p>创建一个 Secret 对象，可以通过以下命令创建：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl create secret generic my-secret --from-literal=password=xxx</span><br></pre></td></tr></table></figure><p>该命令会创建一个名为 <code>my-secret</code> 的 Secret 对象，并将 <code>password</code> 值设置为 <code>xxx</code></p></li><li><p>在 Pod 的 YAML 文件中添加 Secret 的引用，例如：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Pod</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">my-pod</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">my-container</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">my-image</span></span><br><span class="line">    <span class="attr">env:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">MY_PASSWORD</span></span><br><span class="line">      <span class="attr">valueFrom:</span></span><br><span class="line">        <span class="attr">secretKeyRef:</span></span><br><span class="line">          <span class="attr">name:</span> <span class="string">my-secret</span></span><br><span class="line">          <span class="attr">key:</span> <span class="string">password</span></span><br></pre></td></tr></table></figure><p>在该 YAML 文件中，我们在容器的环境变量中定义了一个名为 <code>MY_PASSWORD</code> 的变量，并且使用 <code>secretKeyRef</code> 引用了 <code>my-secret</code> 中的 <code>password</code> 值</p></li><li><p>使用 <code>kubectl apply</code> 命令创建 Pod 对象</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f my-pod.yaml</span><br></pre></td></tr></table></figure></li><li><p>可以使用 <code>kubectl get secrets</code> 命令来查看 Secret 对象的信息，例如：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get secrets</span><br></pre></td></tr></table></figure><p>可以使用 <code>kubectl describe secret</code> 命令来查看 Secret 对象的详细信息，例如：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl describe secret my-secret</span><br></pre></td></tr></table></figure></li></ol><p><strong>注意：</strong>Secret 对象的数据会以 base64 编码的形式存储在 etcd 中，因此需要确保敏感数据在存储和传输过程中的安全性</p><h4 id="33-如何在K8S中管理存储卷"><a href="#33-如何在K8S中管理存储卷" class="headerlink" title="33. 如何在K8S中管理存储卷"></a><font color=DarkOrange>33. 如何在K8S中管理存储卷</font></h4><ol><li>创建存储卷：您可以使用 Kubernetes 中的 PersistentVolume（PV）和 PersistentVolumeClaim（PVC）对象来创建存储卷。PV 是集群级别的资源，而 PVC 是应用程序级别的资源。您可以创建 PV，然后在应用程序中使用 PVC 来引用它</li><li>选择存储类型：Kubernetes 支持多种存储类型，包括本地存储、网络附加存储和云存储。您需要根据应用程序的要求选择适合的存储类型</li><li>配置存储卷访问模式：您可以为存储卷设置不同的访问模式，包括 ReadWriteOnce、ReadOnlyMany 和 ReadWriteMany。这些访问模式决定了存储卷可以被多少个容器同时访问以及它们可以读写的次数</li><li>部署 Pod 并挂载存储卷：您可以使用 Kubernetes 中的 Pod 对象来部署应用程序，并使用 volume 属性将存储卷挂载到容器中。您需要确保在部署应用程序之前，存储卷已经被创建并配置正确</li><li>监控和维护存储卷：一旦应用程序部署成功，您需要监控存储卷并确保它们正常运行。您可以使用 Kubernetes 的监控工具来监视存储卷，例如 Prometheus 和 Grafana</li></ol><h4 id="34-K8S中的控制器-Controller-是什么"><a href="#34-K8S中的控制器-Controller-是什么" class="headerlink" title="34. K8S中的控制器(Controller)是什么"></a><font color=DarkOrange>34. K8S中的控制器(Controller)是什么</font></h4><p>在 Kubernetes 中，Controller 是一种控制器模式，它用于管理和操作应用程序中的多个副本。Controller 负责确保在任何时候应用程序的副本数都符合定义的期望状态，同时可以自动修复应用程序中出现的故障</p><p>Controller 可以基于不同的策略来管理应用程序的副本，其中最常见的包括以下几种：</p><ol><li>ReplicationController：用于管理 Pod 的数量，确保在任何时候都有指定数量的 Pod 在运行</li><li>ReplicaSet：与 ReplicationController 类似，但它提供了更灵活的选择器机制，以便更好地匹配 Pod</li><li>Deployment：建立在 ReplicaSet 之上，提供了对应用程序的版本控制和回滚支持</li><li>StatefulSet：用于管理有状态应用程序的副本，例如数据库和缓存应用程序</li><li>DaemonSet：用于在每个节点上运行一个副本，例如网络代理和日志收集器</li><li>Job 和 CronJob：用于管理短期和定期任务，例如批处理作业和定时任务</li></ol><p>控制器通过监视 Kubernetes API 中的对象状态来工作，例如 Pod 和 ReplicaSet。它们会检查这些对象的状态并根据定义的策略执行必要的操作，例如创建、删除或替换对象。控制器还提供了一些高级功能，例如自动伸缩、滚动升级和故障转移</p><h4 id="35-如何进行K8S中的升级和回滚操作"><a href="#35-如何进行K8S中的升级和回滚操作" class="headerlink" title="35. 如何进行K8S中的升级和回滚操作"></a><font color=DarkOrange>35. 如何进行K8S中的升级和回滚操作</font></h4><p>在 Kubernetes 中进行应用程序升级和回滚操作是非常常见的任务。下面是一些常用的方法：</p><p><strong>升级：</strong></p><ol><li>创建新版本：首先，您需要为应用程序创建一个新版本，并将其部署到 Kubernetes 集群中。您可以使用 Kubernetes 中的 Deployment 对象来管理应用程序的版本，该对象可以自动管理副本集并提供回滚支持</li><li>部署新版本：一旦您创建了新版本，您可以使用 kubectl apply 命令将其部署到集群中。这将触发 Kubernetes 进行滚动更新，并将新版本逐步应用到所有副本中。在此过程中，您可以使用 kubectl rollout status 命令来监视更新的进度</li><li>验证新版本：一旦新版本已经部署成功，您需要验证它是否正常运行，并且没有引入新的问题或故障。您可以使用 Kubernetes 中的服务对象来公开新版本，并使用端口转发或负载均衡器将流量路由到新版本</li></ol><p><strong>回滚：</strong></p><ol><li>确定回滚版本：如果您需要回滚应用程序的版本，首先需要确定要回滚到哪个版本。您可以使用 kubectl rollout history 命令查看历史版本，并选择要回滚的版本</li><li>执行回滚：一旦您确定了回滚版本，您可以使用 kubectl rollout undo 命令来回滚应用程序。该命令将删除当前版本，并将所有副本回滚到先前的版本</li><li>验证回滚：一旦回滚完成，您需要验证应用程序是否已成功回滚，并且没有引入新的问题或故障。您可以使用 Kubernetes 中的服务对象来公开回滚版本，并使用端口转发或负载均衡器将流量路由到回滚版本</li></ol><p><strong>注意：</strong>Kubernetes 中的升级和回滚操作需要谨慎处理，需要确保新版本能够正常运行，并且在回滚时不会引入新的问题或故障。通过使用 Kubernetes 提供的 Deployment 对象和相关命令，您可以轻松地进行升级和回滚操作，并保持应用程序的可用性和稳定性</p><h4 id="36-如何在K8S中进行自动伸缩操作"><a href="#36-如何在K8S中进行自动伸缩操作" class="headerlink" title="36. 如何在K8S中进行自动伸缩操作"></a><font color=DarkOrange>36. 如何在K8S中进行自动伸缩操作</font></h4><ol><li>水平自动伸缩：在 Kubernetes 中，您可以使用 Horizontal Pod Autoscaler (HPA) 对象来自动伸缩应用程序的副本数。 HPA 监视与指定标签匹配的 Pod 集合，根据 CPU 使用率或自定义指标进行扩展或收缩 Pod 的数量</li><li>基于流量的自动伸缩：除了水平自动伸缩之外，Kubernetes 还提供了基于流量的自动伸缩，可以根据流量负载自动调整应用程序的副本数。您可以使用 Kubernetes 中的 Service 对象来实现基于流量的自动伸缩，将流量路由到多个 Pod 上，并使用 Kubernetes 中的负载均衡器来自动调整 Pod 的数量</li><li>垂直自动伸缩：除了水平自动伸缩之外，Kubernetes 还提供了垂直自动伸缩，可以根据应用程序的内存或其他资源使用情况自动调整容器的 CPU 和内存限制</li></ol><h4 id="37-如何在K8S中进行容器间的通信"><a href="#37-如何在K8S中进行容器间的通信" class="headerlink" title="37. 如何在K8S中进行容器间的通信"></a><font color=DarkOrange>37. 如何在K8S中进行容器间的通信</font></h4><ol><li>使用 Kubernetes 中的 Service：Kubernetes 中的 Service 是一种抽象，用于公开应用程序内部的一组 Pod，可以将流量路由到该组 Pod 中的任何一个。您可以将多个容器包含在同一个 Pod 中，并在 Kubernetes 中创建一个 Service 来公开这些容器，使它们能够通过 Service 名称和端口相互通信</li><li>使用 Kubernetes 中的 DNS：Kubernetes 中的 DNS 服务为集群中的容器提供了可靠的域名解析服务。您可以使用 DNS 来解析 Service 名称，以便容器可以相互通信</li><li>使用 Kubernetes 中的 Network Policy：Kubernetes 中的 Network Policy 可以定义网络规则，以允许或拒绝 Pod 之间的流量。通过定义 Network Policy，您可以控制容器之间的通信，并保护您的应用程序免受潜在的网络攻击</li><li>使用 Kubernetes 中的容器间通信插件：Kubernetes 中有许多容器间通信插件可供选择，如 Flannel、Calico 等。这些插件可以帮助容器在不同节点之间进行通信，并提供额外的网络功能，如网络隔离、负载均衡和安全性</li></ol><h4 id="38-什么是Liveness和Readiness探针"><a href="#38-什么是Liveness和Readiness探针" class="headerlink" title="38. 什么是Liveness和Readiness探针"></a><font color=DarkOrange>38. 什么是Liveness和Readiness探针</font></h4><p>Liveness 和 Readiness 探针是 Kubernetes 中的两种不同类型的探测机制，用于确保容器在运行期间保持健康，并且可以接收流量。它们的主要区别在于它们检查的方面和作用时间</p><ol><li>Liveness 探针：Liveness 探针用于检查容器是否仍在运行。如果 Liveness 探针探测到容器已停止工作，则 Kubernetes 会尝试重启该容器。例如，您可以配置 Liveness 探针来检查容器的关键进程或应用程序状态，以确保容器在运行期间保持健康</li><li>Readiness 探针：Readiness 探针用于检查容器是否准备好接收流量。如果一个容器没有就绪，Kubernetes 将不会将流量发送到该容器，直到它就绪为止。例如，您可以配置 Readiness 探针来检查容器是否已完成启动过程，并已成功地连接到所需的后端服务或数据库</li></ol><p>这两种探针都使用相同的机制：它们会定期向容器发送请求，并根据响应结果来确定容器的状态。如果容器返回成功的响应，探针将标记容器为就绪或活着，否则将标记为未就绪或死亡</p><h4 id="39-如何在K8S中实现容器的亲和性和反亲和性"><a href="#39-如何在K8S中实现容器的亲和性和反亲和性" class="headerlink" title="39. 如何在K8S中实现容器的亲和性和反亲和性"></a><font color=DarkOrange>39. 如何在K8S中实现容器的亲和性和反亲和性</font></h4><p>在 Kubernetes 中，亲和性（Affinity）和反亲和性（Anti-Affinity）是两种常用的机制，用于控制 Pod 和 Node 之间的互动。亲和性用于控制 Pod 如何选择一个节点进行调度，而反亲和性用于防止在同一节点上调度相似的 Pod。下面是一些实现容器亲和性和反亲和性的方法：</p><ol><li>使用亲和性和反亲和性规则：在 Kubernetes 中，您可以使用亲和性和反亲和性规则，以控制 Pod 如何选择一个节点进行调度。例如，您可以使用 nodeSelector，podAffinity 和 podAntiAffinity 等规则来控制 Pod 和节点之间的关系</li><li>使用 Kubernetes 调度器的拓扑感知特性：Kubernetes 调度器支持拓扑感知特性，该特性可以根据节点之间的拓扑关系进行 Pod 调度。您可以使用 topologyKey 和 topologySpreadConstraints 来控制 Pod 和节点之间的亲和性和反亲和性</li><li>使用 Kubernetes 的自定义调度器：Kubernetes 还支持自定义调度器，该调度器可以根据您的特定需求调度 Pod。通过自定义调度器，您可以更加灵活地控制 Pod 的调度，并实现容器亲和性和反亲和性</li></ol><p>在 Kubernetes 中实现容器的亲和性和反亲和性需要使用一些特定的工具和机制，例如亲和性和反亲和性规则、拓扑感知特性和自定义调度器。通过使用这些工具和机制，您可以更好地控制 Pod 和节点之间的互动，从而实现容器的高效调度和部署</p><h4 id="40-如何在K8S中进行日志管理"><a href="#40-如何在K8S中进行日志管理" class="headerlink" title="40. 如何在K8S中进行日志管理"></a><font color=DarkOrange>40. 如何在K8S中进行日志管理</font></h4><ol><li>使用 Kubernetes API 打印日志：Kubernetes API 提供了一个 &#x2F;api&#x2F;v1&#x2F;namespaces&#x2F;{namespace}&#x2F;pods&#x2F;{podName}&#x2F;log API，通过该 API 可以打印容器的日志。您可以使用该 API 通过 kubectl 命令行工具或 API 访问端点来打印容器的日志</li><li>使用集中式日志记录工具：Kubernetes 中支持使用集中式日志记录工具，例如 Elasticsearch、Fluentd 和 Kibana（EFK）等。通过将这些工具部署到 Kubernetes 中，您可以将日志收集到一个中心位置，以便更容易地搜索和分析它们</li><li>使用容器日志驱动程序：Kubernetes 支持使用容器日志驱动程序，例如 json-file、syslog、journald 等。这些驱动程序可以配置容器日志的格式和位置。您可以使用 kubectl logs 命令行工具来访问容器日志</li><li>使用第三方日志管理工具：除了使用 Kubernetes 提供的日志管理功能外，您还可以使用第三方日志管理工具，例如 Logstash、Prometheus 和 Grafana 等。这些工具提供了更高级的日志管理和监控功能，可以帮助您更好地了解您的应用程序的运行状况</li></ol><hr><hr><h4 id="41-你对etcd的了解是什么"><a href="#41-你对etcd的了解是什么" class="headerlink" title="41. 你对etcd的了解是什么"></a><font color=DarkOrange>41. 你对etcd的了解是什么</font></h4><p>Etcd是一个分布式的键值存储系统，它被广泛应用于构建分布式系统和容器编排平台中。它使用Raft算法实现了高可用性，确保数据的一致性和可靠性</p><p>Etcd的主要功能是提供分布式的键值存储服务，可以用于存储配置数据、服务注册、服务发现等。它具有以下特点：</p><ol><li>分布式：Etcd使用Raft算法来保证分布式系统的可用性和数据一致性</li><li>高可用性：Etcd使用Raft算法来实现多节点之间的数据同步和决策，从而保证了系统的高可用性和数据的可靠性</li><li>快速：Etcd使用基于内存的存储引擎，可以提供高速的读写性能</li><li>安全：Etcd支持SSL&#x2F;TLS加密，可以保证数据的安全性</li><li>简单：Etcd提供了简单易用的API，可以快速地存储和检索键值对</li></ol><p><strong>总结：</strong>Etcd是一个可靠、高效、安全、简单的分布式键值存储系统，适用于构建大规模分布式系统和容器编排平台</p><h4 id="42-请讲解一下etcd的数据模型是什么样子的"><a href="#42-请讲解一下etcd的数据模型是什么样子的" class="headerlink" title="42. 请讲解一下etcd的数据模型是什么样子的"></a><font color=DarkOrange>42. 请讲解一下etcd的数据模型是什么样子的</font></h4><p>Etcd的数据模型可以被看作一个分层的键值存储系统，其中键和值都是字符串类型</p><p>在Etcd中，数据被组织成一个树形结构，每个节点都可以是一个键值对。一个节点可以拥有多个子节点，每个子节点都有一个唯一的名称（即键），而每个节点的值可以是一个字符串</p><p>Etcd中的每个键都必须唯一，并且可以包含任意数量的目录和子目录。因此，可以将Etcd看作一个类似于文件系统的结构</p><p>除了键值对之外，Etcd还支持将一个键下的所有子键作为一个目录或命名空间进行管理。这可以通过在键的末尾添加一个斜杠（&#x2F;）来实现，例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/foo/      <span class="comment"># 表示一个名为 foo 的目录</span></span><br><span class="line">/foo/bar   <span class="comment"># 表示一个名为 bar 的键，它是 /foo/ 目录下的子键</span></span><br></pre></td></tr></table></figure><p>Etcd还支持事务操作，它可以将多个读写操作作为一个原子操作进行提交或回滚。这些操作可以是写入、更新、删除或者获取数据等</p><h4 id="43-在etcd集群中如何实现高可用性"><a href="#43-在etcd集群中如何实现高可用性" class="headerlink" title="43. 在etcd集群中如何实现高可用性"></a><font color=DarkOrange>43. 在etcd集群中如何实现高可用性</font></h4><p>Etcd使用Raft协议实现高可用性，该协议是一种分布式一致性算法，可以保证在节点出现故障时，集群仍然可以继续工作并保持数据的一致性</p><p>具体来说，Etcd将节点划分为三个角色：Leader、Follower和Candidate。Leader节点是负责处理客户端请求的节点，Follower节点是通过复制Leader的日志来保持与Leader同步的节点，Candidate节点是在选举过程中处于“投票状态”的节点</p><p>Etcd中的选举过程如下：</p><ol><li>每个节点都是一个Follower，一旦节点发现Leader失联，就会进入“选举状态”，发出一个选举请求</li><li>其他节点收到请求后，如果没有投过票，就会把票投给请求者，并将自己的状态设为Candidate</li><li>当一个Candidate获得多数投票时，就成为新的Leader，其他节点成为Follower并开始复制新Leader的日志</li><li>如果没有Candidate获得多数投票，则进行新一轮选举，直到某个节点成为Leader</li></ol><p>通过这样的选举过程，Etcd可以保证在出现节点故障的情况下，集群可以继续工作并保持数据的一致性。同时，Etcd还支持动态添加或删除节点，从而实现了集群的动态扩容和缩容</p><h4 id="44-etcd支持哪些数据存储后端？如何选择适合自己的存储后端"><a href="#44-etcd支持哪些数据存储后端？如何选择适合自己的存储后端" class="headerlink" title="44. etcd支持哪些数据存储后端？如何选择适合自己的存储后端"></a><font color=DarkOrange>44. etcd支持哪些数据存储后端？如何选择适合自己的存储后端</font></h4><p>Etcd支持多种数据存储后端，包括内存、磁盘和云存储等。其中，内存存储后端提供了最快的读写速度，但是在节点重启或者宕机时会导致数据的丢失；磁盘存储后端则可以持久化数据，但是读写速度相对较慢；云存储后端可以将数据存储在云平台的对象存储服务中，具有高可用性和可扩展性</p><p>在选择存储后端时，应该根据实际需求来选择适合自己的方案。如果需要高速读写和对数据可靠性要求不高，可以选择内存存储后端；如果对数据可靠性要求比较高，可以选择磁盘存储后端；如果需要高可用性和可扩展性，可以选择云存储后端</p><p>此外，还需要考虑存储后端的成本和复杂性。内存存储后端成本较低，但是数据丢失的风险较高，需要备份和恢复机制；磁盘存储后端成本适中，但是需要进行备份和数据清理，以防止数据堆积和损坏；云存储后端成本较高，但是具有高可用性和可扩展性，可以实现自动备份和恢复</p><p>综上所述，选择合适的存储后端需要根据实际需求来进行评估和比较</p><h4 id="45-如何通过etcd实现分布式锁"><a href="#45-如何通过etcd实现分布式锁" class="headerlink" title="45. 如何通过etcd实现分布式锁"></a><font color=DarkOrange>45. 如何通过etcd实现分布式锁</font></h4><ol><li>创建一个etcd客户端实例并连接到etcd服务器</li><li>使用etcd的事务API创建一个键，并将其值设置为唯一的标识符，例如UUID。这个键将用于表示锁定状态</li><li>使用etcd的事务API将此键设置为有租期（TTL）。租期是在etcd中维护的一段时间，在此期间键将保持活动状态。如果租期过期，etcd将自动删除该键。通过设置租期，您可以避免出现死锁的情况</li><li>如果设置键的操作成功，则表示客户端已获得锁。如果操作失败，则表示另一个客户端已经持有该锁。在这种情况下，客户端可以使用etcd的Watcher API等待另一个客户端释放锁</li><li>当客户端完成工作并释放锁时，使用etcd的事务API删除该键</li></ol><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1. 导入etcd相关包</span></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">&quot;context&quot;</span></span><br><span class="line">    <span class="string">&quot;go.etcd.io/etcd/clientv3&quot;</span></span><br><span class="line">    <span class="string">&quot;go.etcd.io/etcd/clientv3/concurrency&quot;</span></span><br><span class="line">    <span class="string">&quot;log&quot;</span></span><br><span class="line">    <span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. 定义etcd客户端</span></span><br><span class="line"><span class="keyword">var</span> etcdClient *clientv3.Client</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3. 初始化etcd客户端</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">initEtcd</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="keyword">var</span> err <span class="type">error</span></span><br><span class="line">    etcdClient, err = clientv3.New(clientv3.Config&#123;</span><br><span class="line">        Endpoints:   []<span class="type">string</span>&#123;<span class="string">&quot;localhost:2379&quot;</span>&#125;, <span class="comment">// etcd集群地址</span></span><br><span class="line">        DialTimeout: <span class="number">5</span> * time.Second,            <span class="comment">// 连接超时时间</span></span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        log.Fatal(err)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 4. 获取etcd分布式锁</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getEtcdLock</span><span class="params">(key <span class="type">string</span>)</span></span> (*concurrency.Mutex, <span class="type">error</span>) &#123;</span><br><span class="line">    <span class="comment">// 创建etcd分布式锁</span></span><br><span class="line">    session, err := concurrency.NewSession(etcdClient)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nil</span>, err</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> concurrency.NewMutex(session, key), <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 5. 使用etcd分布式锁</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">useEtcdLock</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="comment">// 获取etcd分布式锁</span></span><br><span class="line">    lock, err := getEtcdLock(<span class="string">&quot;my-lock&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        log.Fatal(err)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 加锁</span></span><br><span class="line">    err = lock.Lock(context.Background())</span><br><span class="line">    <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">        log.Fatal(err)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 释放锁</span></span><br><span class="line">    <span class="keyword">defer</span> lock.Unlock(context.Background())</span><br><span class="line">    <span class="comment">// 执行业务逻辑</span></span><br><span class="line">    log.Println(<span class="string">&quot;do something with etcd lock&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 6. 主函数</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="comment">// 初始化etcd客户端</span></span><br><span class="line">    initEtcd()</span><br><span class="line">    <span class="comment">// 使用etcd分布式锁</span></span><br><span class="line">    useEtcdLock()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="46-请讲解一下etcd的watch机制是如何实现的"><a href="#46-请讲解一下etcd的watch机制是如何实现的" class="headerlink" title="46. 请讲解一下etcd的watch机制是如何实现的"></a><font color=DarkOrange>46. 请讲解一下etcd的watch机制是如何实现的</font></h4><p>Etcd的watch机制是一种客户端订阅数据更改的方式，可以让客户端在发生变化时及时收到通知，从而避免了客户端频繁轮询的开销。实现watch机制的核心是利用etcd的watch接口</p><p>Etcd的watch机制包括以下几个步骤：</p><ol><li>客户端通过etcd API向etcd服务器注册一个watcher对象，并指定需要监听的键值</li><li>当etcd服务器上被监听的键值发生变化时，etcd会将变化通知给所有对应的watcher对象</li><li>watcher对象在收到通知后，将变化的内容返回给客户端</li><li>客户端收到变化的内容后，可以根据需要进行相应的处理</li></ol><p>在实现watch机制时，etcd利用了其内部的事件循环机制。当客户端注册watcher对象时，etcd会将其加入到内部的事件循环队列中。当etcd服务器上的数据发生变化时，etcd会将变化事件加入到事件循环队列中，然后依次处理队列中的事件，并将变化通知给相应的watcher对象</p><p><strong>注意：</strong>etcd的watch机制并不是完全实时的，因为etcd需要处理多个客户端的watch请求，因此存在一定的延迟。同时，etcd还会使用心跳机制来保证watcher对象的健康状态，如果watcher对象出现故障，etcd会将其从事件循环队列中移除，避免对etcd服务器的性能造成影响</p><h4 id="47-如何通过etcd实现配置中心"><a href="#47-如何通过etcd实现配置中心" class="headerlink" title="47. 如何通过etcd实现配置中心"></a><font color=DarkOrange>47. 如何通过etcd实现配置中心</font></h4><ol><li>使用etcd的watch机制 etcd提供了watch机制，可以监控etcd中某个key的变化。可以将配置信息存储在etcd中的某个key下，然后通过watch机制来监控该key的变化</li><li>使用etcd的租约机制 etcd提供了租约机制，可以为某个key设置一个过期时间。可以将配置信息存储在etcd中的某个key下，并为该key设置一个较短的过期时间，然后在应用程序中定时从etcd中读取该key的值</li><li>使用etcd的分布式锁机制 etcd提供了分布式锁机制，可以保证在分布式环境下的互斥访问。可以将配置信息存储在etcd中的某个key下，并使用etcd的分布式锁机制来保证在多个应用程序同时访问该key时的互斥性</li><li>使用etcd的事务机制 etcd提供了事务机制，可以保证多个操作的原子性。可以将配置信息存储在etcd中的多个key下，并使用etcd的事务机制来保证多个操作的原子性</li><li>使用etcd的目录机制 etcd提供了目录机制，可以将多个key组织成一个目录。可以将配置信息存储在etcd中的某个目录下，并使用etcd的目录机制来组织这些key</li></ol><h4 id="48-etcd在网络分区情况下会发生什么"><a href="#48-etcd在网络分区情况下会发生什么" class="headerlink" title="48. etcd在网络分区情况下会发生什么"></a><font color=DarkOrange>48. etcd在网络分区情况下会发生什么</font></h4><p>在网络分区情况下，即网络被切割成两个或多个部分时，etcd 集群可能会发生以下情况：</p><ol><li><p>分裂脑</p><p>如果网络分区不被处理，etcd 集群中可能会出现“分裂脑”现象，即两个或多个集群成为相互独立的子集群，各自进行操作，可能导致数据不一致、冲突等问题。</p></li><li><p>选举失败</p><p>etcd 使用 Raft 算法进行主节点选举。在网络分区情况下，如果多个节点同时发起选举，可能会导致选举失败，无法确定主节点，从而导致 etcd 集群无法正常工作</p></li><li><p>数据不一致</p><p>如果网络分区期间 etcd 集群中的某些节点更新了数据，而其他节点无法获取到最新数据，则可能导致数据不一致问题</p></li></ol><p>为了解决以上问题，可以采取以下措施：</p><ol><li>使用 etcd 集群自带的分区处理机制，比如“Split-Brain Prevention”（SBP）和“Majority-Based Partition Tolerance”（MBPT），来避免“分裂脑”问题</li><li>在网络分区情况下，禁止数据的写入操作，只允许读取操作，以避免数据不一致问题</li><li>当网络分区恢复后，etcd 集群需要进行数据同步和节点选举等操作，以确保集群正常工作</li></ol><h4 id="49-如何在K8S中使用etcd"><a href="#49-如何在K8S中使用etcd" class="headerlink" title="49. 如何在K8S中使用etcd"></a><font color=DarkOrange>49. 如何在K8S中使用etcd</font></h4><ol><li>使用etcd作为Kubernetes的后端存储 Kubernetes使用etcd作为其后端存储，存储了Kubernetes集群的所有状态信息。在Kubernetes集群中，每个节点都运行一个etcd实例，这些etcd实例组成了一个etcd集群，用于存储Kubernetes集群的状态信息</li><li>使用etcd作为Kubernetes的配置中心 Kubernetes中的许多组件都需要配置信息，可以使用etcd作为Kubernetes的配置中心，将配置信息存储在etcd中，并通过etcd的watch机制来监控配置信息的变化，从而实现动态配置</li><li>使用etcd作为Kubernetes的服务发现 Kubernetes中的服务发现功能可以使用etcd来实现。可以将服务的地址信息存储在etcd中，并使用etcd的watch机制来监控服务地址信息的变化，从而实现动态服务发现</li><li>使用etcd作为Kubernetes的分布式锁 Kubernetes中的许多组件需要在分布式环境下保证互斥访问，可以使用etcd的分布式锁机制来实现分布式锁。可以将锁信息存储在etcd中，并使用etcd的分布式锁机制来保证在多个组件同时访问锁时的互斥性</li><li>使用etcd作为Kubernetes的租约机制 Kubernetes中的许多组件需要在一定时间内完成某个任务，可以使用etcd的租约机制来实现任务的超时控制。可以将任务信息存储在etcd中，并为该任务设置一个较短的过期时间，然后在组件中定时从etcd中读取该任务的状态，从而实现任务的超时控制</li></ol><h4 id="50-如何保证etcd集群的安全性"><a href="#50-如何保证etcd集群的安全性" class="headerlink" title="50. 如何保证etcd集群的安全性"></a><font color=DarkOrange>50. 如何保证etcd集群的安全性</font></h4><ol><li>使用TLS加密etcd通信 在etcd集群中，所有节点之间的通信都是通过网络进行的，因此需要使用TLS来加密etcd通信。可以通过在etcd配置文件中设置TLS证书和密钥来实现TLS加密。具体可以参考etcd官方文档中的相关内容</li><li>使用客户端证书认证 为了保证etcd集群的安全性，可以使用客户端证书认证来限制etcd集群的访问。可以通过在etcd配置文件中设置客户端证书和密钥来实现客户端证书认证。具体可以参考etcd官方文档中的相关内容</li><li>使用访问控制列表（ACL） etcd支持使用访问控制列表（ACL）来限制etcd集群的访问。可以通过在etcd配置文件中设置ACL规则来实现ACL。具体可以参考etcd官方文档中的相关内容</li><li>使用网络隔离 为了保证etcd集群的安全性，可以使用网络隔离来限制etcd集群的访问。可以通过在etcd集群所在的网络中设置网络隔离规则来实现网络隔离。具体可以参考网络隔离相关的文档</li><li>定期备份etcd数据 为了保证etcd集群的安全性，需要定期备份etcd数据。可以使用etcdctl命令行工具来备份etcd数据。具体可以参考etcd官方文档中的相关内容</li></ol><hr><p>阿里云开发者社区docker、k8s面试总结链接：<a href="https://developer.aliyun.com/article/873550">点击跳转</a></p><hr>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;常见Docker、K8S、etcd面试题整理&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;1-什么是Docker&quot;&gt;&lt;a href=&quot;#1-什么是Docker&quot; class=&quot;headerlink&quot; title=&quot;1. 什么是Docker&quot;&gt;&lt;/a&gt;&lt;font color=DarkO</summary>
      
    
    
    
    <category term="面试" scheme="https://huajun-chen.github.io/categories/%E9%9D%A2%E8%AF%95/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>Go-设计模式</title>
    <link href="https://huajun-chen.github.io/2022/11/24/Go-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    <id>https://huajun-chen.github.io/2022/11/24/Go-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</id>
    <published>2022-11-24T08:44:39.000Z</published>
    <updated>2022-11-24T14:55:50.445Z</updated>
    
    <content type="html"><![CDATA[<p>设计模式是软件工程中各种常见问题的经典解决方案，设计模式不只是代码，而是组织代码的方式。假设一行行的代码是砖，设计模式就是蓝图</p><table><thead><tr><th><div style="width: 32pt">类型</div></th><th><div style="width: 63pt">设计模式</div></th><th>简述</th><th><div style="width: 25pt">常用</div></th></tr></thead><tbody><tr><td>创建型</td><td>工厂模式</td><td>定义一个创建对象的接口，让其子类自己决定范例化哪一个工厂类，是最常用的设计模式之一</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>抽象工厂模式</td><td>为访问类提供一个创建一组相关或相互依赖对象的接口，且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>建造者模式</td><td>将一个复杂对象的构造与它的表示分离，使同样的构建过程可以创建不同的表示。它是将一个复杂的对象分解为多个简单的对象，然后一步一步构建而成</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>原型模式</td><td>用一个已经创建的范例作为原型，通过复制该原型对象来创建一个和原型相同或相似的新对象</td><td><font color=Red>no</font></td></tr><tr><td></td><td>单例模式</td><td>保证一个类仅有一个范例，并提供一个访问它的全局访问点单例模式只涉及到一个类，该类负责创建自己的对象，而且确保只有单个对象被创建</td><td><font color=Forestgreen>yes</font></td></tr><tr><td>结构型</td><td>适配器模式</td><td>将一个类的接口转换成客户希望的另外一个接口，使得原本由于接口不兼容而不能一起工作的那些类能一起工作</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>桥接模式</td><td>将抽象与实现分离，使两者可以独立变化。它是用组合关系代替继承关系来实现，从而降低了抽象和实现这两个可变维度的耦合度</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>组合模式</td><td><strong>对象树模式&#x2F;整体-部分模式</strong>。将对象组合成树状的层次结构的模式，用来表示“整体-部分”的关系，使用户对单个对象和组合对象具有一致的访问性</td><td><font color=Red>no</font></td></tr><tr><td></td><td>装饰器模式</td><td>动态地给一个对象添加一些额外的职责。允许向一个现有的对象添加新的功能，同时又不改变其结构</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>外观模式</td><td>又称为门面模式，它为子系统中的接口提供一个一致的接口，来隐藏子系统内部的复杂性，使得子系统更加容易使用</td><td><font color=Red>no</font></td></tr><tr><td></td><td>享元模式</td><td>运用共享技术有效地支持大量细粒度的对象，减少对象的创建数量，以节省内存占用和提高性能</td><td><font color=Red>no</font></td></tr><tr><td></td><td>代理模式</td><td>由于某些原因需要为某对象提供一种代理以控制对该对象的访问当访问对象不适合或者不能直接引用目标对象的时候，可以通过代理对象作为访问对象和目标对象之间的中介</td><td><font color=Forestgreen>yes</font></td></tr><tr><td>行为型</td><td>责任链模式</td><td>为了避免请求发送者与多个请求处理者耦合在一起，于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链；当有请求发生时，可将请求沿着这条链传递，直到有对象处理它为止</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>命令模式</td><td>将一个请求封装为一个对象，从而使你可用不同的请求对客户进行参数化；对请求排队或者记录请求日志，以及支持可撤销的操作</td><td><font color=Red>no</font></td></tr><tr><td></td><td>迭代器模式</td><td>提供了一种方法顺序访问一个聚合对象中的所有元素，而又不暴露该聚合对象的内部表示用于顺序访问集合对象的元素，调用者无需知道集合对象的底层表示，从而实现调用者和聚合对象的解耦</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>中介者模式</td><td>用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类，该类通常处理不同类之间的通信，并支持松耦合，使代码易于维护</td><td><font color=Red>no</font></td></tr><tr><td></td><td>备忘录模式</td><td>保存一个对象的某个状态，以便在适当的时候恢复对象</td><td><font color=Red>no</font></td></tr><tr><td></td><td>观察者模式</td><td>定义了对象间的一种一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并自动刷新</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>状态模式</td><td>对有状态的对象，把复杂的“判断逻辑”提取到不同的状态对象中，允许状态对象在其内部状态发生改变时改变其行为</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>策略模式</td><td>通过定义了一系列算法，并将每个算法封装起来，使它们可以相互替换，且算法的变化不会影响使用算法的客户</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>模板方法模式</td><td>定义一个操作中的算法骨架，而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构,即可重定义该算法的某些特定步骤</td><td><font color=Forestgreen>yes</font></td></tr><tr><td></td><td>访问者模式</td><td>将作用于某种数据结构中的各元素的操作分离出来封装成独立的类，使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作，为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离，是行为类模式中最复杂的一种模式</td><td><font color=Red>no</font></td></tr></tbody></table><h4 id="1-工厂模式"><a href="#1-工厂模式" class="headerlink" title="1. 工厂模式"></a><font color=DarkOrange>1. 工厂模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="2-抽象工厂模式"><a href="#2-抽象工厂模式" class="headerlink" title="2. 抽象工厂模式"></a><font color=DarkOrange>2. 抽象工厂模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="3-建造者模式"><a href="#3-建造者模式" class="headerlink" title="3. 建造者模式"></a><font color=DarkOrange>3. 建造者模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="4-原型模式"><a href="#4-原型模式" class="headerlink" title="4. 原型模式"></a><font color=DarkOrange>4. 原型模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="5-单例模式"><a href="#5-单例模式" class="headerlink" title="5. 单例模式"></a><font color=DarkOrange>5. 单例模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="6-适配器模式"><a href="#6-适配器模式" class="headerlink" title="6. 适配器模式"></a><font color=DarkOrange>6. 适配器模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="7-桥接模式"><a href="#7-桥接模式" class="headerlink" title="7. 桥接模式"></a><font color=DarkOrange>7. 桥接模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="8-组合模式"><a href="#8-组合模式" class="headerlink" title="8. 组合模式"></a><font color=DarkOrange>8. 组合模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="9-装饰器模式"><a href="#9-装饰器模式" class="headerlink" title="9. 装饰器模式"></a><font color=DarkOrange>9. 装饰器模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="10-外观模式"><a href="#10-外观模式" class="headerlink" title="10. 外观模式"></a><font color=DarkOrange>10. 外观模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="11-享元模式"><a href="#11-享元模式" class="headerlink" title="11. 享元模式"></a><font color=DarkOrange>11. 享元模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="12-代理模式"><a href="#12-代理模式" class="headerlink" title="12. 代理模式"></a><font color=DarkOrange>12. 代理模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="13-责任链模式"><a href="#13-责任链模式" class="headerlink" title="13. 责任链模式"></a><font color=DarkOrange>13. 责任链模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="14-命令模式"><a href="#14-命令模式" class="headerlink" title="14. 命令模式"></a><font color=DarkOrange>14. 命令模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="15-迭代器模式"><a href="#15-迭代器模式" class="headerlink" title="15. 迭代器模式"></a><font color=DarkOrange>15. 迭代器模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="16-中介者模式"><a href="#16-中介者模式" class="headerlink" title="16. 中介者模式"></a><font color=DarkOrange>16. 中介者模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="17-备忘录模式"><a href="#17-备忘录模式" class="headerlink" title="17. 备忘录模式"></a><font color=DarkOrange>17. 备忘录模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="18-观察者模式"><a href="#18-观察者模式" class="headerlink" title="18. 观察者模式"></a><font color=DarkOrange>18. 观察者模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="19-状态模式"><a href="#19-状态模式" class="headerlink" title="19. 状态模式"></a><font color=DarkOrange>19. 状态模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="20-策略模式"><a href="#20-策略模式" class="headerlink" title="20. 策略模式"></a><font color=DarkOrange>20. 策略模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="21-模板方法模式"><a href="#21-模板方法模式" class="headerlink" title="21. 模板方法模式"></a><font color=DarkOrange>21. 模板方法模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="22-访问者模式"><a href="#22-访问者模式" class="headerlink" title="22. 访问者模式"></a><font color=DarkOrange>22. 访问者模式</font></h4><p><strong>问题</strong></p><p><strong>解决</strong></p><h4 id="23-设计模式的“道”"><a href="#23-设计模式的“道”" class="headerlink" title="23. 设计模式的“道”"></a><font color=DarkOrange>23. 设计模式的“道”</font></h4><p>设计模式分为“术”的部分和“道”的部分，上面那些设计模式就是“术”的部分，他们是一些围绕着设计模式核心思路的经典解决方案。换句话说，重要的是理解为什么要用那些设计模式，具体问题，具体分析，而不是把某种设计模式生搬硬套进代码</p><p>设计模式有6大原则，以上的设计模式目的就是为了使软件系统能达到这些原则：</p><ul><li>开闭原则<ul><li>软件应该对扩展开放，对修改关闭</li><li>对系统进行扩展，而无需修改现有的代码。这可以降低软件的维护成本，同时也增加可扩展性</li></ul></li><li>里氏替换原则<ul><li>任何基类可以出现的地方，子类一定可以出现</li><li>里氏替换原则是对开闭原则的补充，实现开闭原则的关键步骤就是抽象化，基类与子类的关系就是要尽可能的抽象化</li></ul></li><li>依赖倒置原则<ul><li>面向接口编程，抽象不应该依赖于具体类，具体类应当依赖于抽象</li><li>这是为了减少类间的耦合，使系统更适宜于扩展，也更便于维护</li></ul></li><li>单一职责原则<ul><li>一个类应该只有一个发生变化的原因</li><li>一个类承载的越多，耦合度就越高。如果类的职责单一，就可以降低出错的风险，也可以提高代码的可读性</li></ul></li><li>最少知道原则<ul><li>一个实体应当尽量少地与其他实体之间发生相互作用</li><li>还是为了降低耦合，一个类与其他类的关联越少，越易于扩展</li></ul></li><li>接口分离原则<ul><li>使用多个专门的接口，而不使用高耦合的单一接口</li><li>避免同一个接口占用过多的职责，更明确的划分，可以降低耦合。高耦合会导致程序不易扩展，提高出错的风险</li></ul></li></ul><hr><p>编程宝库链接：<a href="http://www.codebaoku.com/design-pattern/design-pattern-index.html">点击跳转</a></p><p>掘金链接：<a href="https://juejin.cn/post/7095581880200167432">点击跳转</a></p><p>华为云链接：<a href="https://bbs.huaweicloud.com/blogs/279505">点击跳转</a></p><hr>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;设计模式是软件工程中各种常见问题的经典解决方案，设计模式不只是代码，而是组织代码的方式。假设一行行的代码是砖，设计模式就是蓝图&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;div style=&quot;width: 32pt&quot;&gt;类型&lt;/div&gt;&lt;/th&gt;
&lt;th&gt;&lt;</summary>
      
    
    
    
    <category term="面试" scheme="https://huajun-chen.github.io/categories/%E9%9D%A2%E8%AF%95/"/>
    
    
    <category term="Go" scheme="https://huajun-chen.github.io/tags/Go/"/>
    
    <category term="设计模式" scheme="https://huajun-chen.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>CodeTop算法题</title>
    <link href="https://huajun-chen.github.io/2022/11/14/CodeTop%E7%AE%97%E6%B3%95%E9%A2%98/"/>
    <id>https://huajun-chen.github.io/2022/11/14/CodeTop%E7%AE%97%E6%B3%95%E9%A2%98/</id>
    <published>2022-11-14T03:29:50.000Z</published>
    <updated>2022-11-25T02:32:58.887Z</updated>
    
    <content type="html"><![CDATA[<p>面试LeetCode算法题整理，按照出现的频率依次递减排序，题目类型包含：简单、中等、困难</p><p>CodeTop地址：<a href="https://codetop.cc/home">点击跳转</a></p><p><strong>备注：</strong>出现的频率会随时间变化而变化，具体以CodeTop出现频率为准，每个题目整理出<strong>题目</strong>、<strong>思路</strong>、<strong>代码</strong>三部分</p><h4 id="1-无重复字符的最长子串-中等"><a href="#1-无重复字符的最长子串-中等" class="headerlink" title="1. 无重复字符的最长子串-中等"></a><font color=DarkOrange>1. 无重复字符的最长子串-中等</font></h4><p><strong>题目：</strong></p><p>给定一个字符串 <code>s</code> ，请你找出其中不含有重复字符的 <strong>最长子串</strong> 的长度</p><p><strong>思路：</strong></p><p>滑动窗口</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="2-反转链表-简单"><a href="#2-反转链表-简单" class="headerlink" title="2. 反转链表-简单"></a><font color=DarkOrange>2. 反转链表-简单</font></h4><p><strong>题目：</strong></p><p>给你单链表的头节点 <code>head</code> ，请你反转链表，并返回反转后的链表</p><p><strong>思路：</strong></p><p>方法一：迭代</p><p>方法二：递归</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="3-LRU缓存-中等"><a href="#3-LRU缓存-中等" class="headerlink" title="3. LRU缓存-中等"></a><font color=DarkOrange>3. LRU缓存-中等</font></h4><p><strong>题目：</strong></p><p>请你设计并实现一个满足LRU (最近最少使用) 缓存约束的数据结构</p><p>实现 <code>LRUCache</code> 类：</p><ul><li><code>LRUCache(int capacity)</code> 以 <strong>正整数</strong> 作为容量 <code>capacity</code> 初始化 LRU 缓存</li><li><code>int get(int key)</code> 如果关键字 <code>key</code> 存在于缓存中，则返回关键字的值，否则返回 <code>-1</code> </li><li>void put(int key, int value) 如果关键字 key 已经存在，则变更其数据值 value ；如果不存在，则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ，则应该 逐出 最久未使用的关键字</li></ul><p>函数 <code>get</code> 和 <code>put</code> 必须以 <code>O(1)</code> 的平均时间复杂度运行</p><p><strong>思路：</strong></p><p>哈希表 + 双向链表</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="4-数组中的第K个最大元素-中等"><a href="#4-数组中的第K个最大元素-中等" class="headerlink" title="4. 数组中的第K个最大元素-中等"></a><font color=DarkOrange>4. 数组中的第K个最大元素-中等</font></h4><p><strong>题目：</strong></p><p>给定整数数组 <code>nums</code> 和整数 <code>k</code>，请返回数组中第 <code>k</code> 个最大的元素</p><p>请注意，你需要找的是数组排序后的第 <code>k</code> 个最大的元素，而不是第 <code>k</code> 个不同的元素</p><p>你必须设计并实现时间复杂度为 <code>O(n)</code> 的算法解决此问题</p><p><strong>思路：</strong></p><p>方法一：基于快速排序的选择方法</p><p>方法二：基于堆排序的选择方法</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="5-K个一组翻转链表-困难"><a href="#5-K个一组翻转链表-困难" class="headerlink" title="5. K个一组翻转链表-困难"></a><font color=DarkOrange>5. K个一组翻转链表-困难</font></h4><p><strong>题目：</strong></p><p>给你链表的头节点 <code>head</code> ，每 <code>k</code> 个节点一组进行翻转，请你返回修改后的链表</p><p><code>k</code> 是一个正整数，它的值小于或等于链表的长度。如果节点总数不是 <code>k</code> 的整数倍，那么请将最后剩余的节点保持原有顺序</p><p>你不能只是单纯的改变节点内部的值，而是需要实际进行节点交换</p><p><strong>思路：</strong></p><p>模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="6-三数之和-中等"><a href="#6-三数之和-中等" class="headerlink" title="6. 三数之和-中等"></a><font color=DarkOrange>6. 三数之和-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组<code>nums</code> ，判断是否存在三元组<code>[nums[i], nums[j], nums[k]]</code>满足<code>i != j</code>、<code>i != k</code>且<code>j != k</code>，同时还满足<code>nums[i] + nums[j] + nums[k] == 0</code> </p><p>请你返回所有和为 <code>0</code> 且不重复的三元组</p><p><strong>注意：</strong>答案中不可以包含重复的三元组</p><p><strong>思路：</strong></p><p>排序 + 双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="7-最大子数组和-中等"><a href="#7-最大子数组和-中等" class="headerlink" title="7. 最大子数组和-中等"></a><font color=DarkOrange>7. 最大子数组和-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code> ，请你找出一个具有最大和的连续子数组（子数组最少包含一个元素），返回其最大和</p><p><strong>子数组</strong> 是数组中的一个连续部分</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：分治</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="8-排序数组-快排-中等"><a href="#8-排序数组-快排-中等" class="headerlink" title="8. 排序数组-快排-中等"></a><font color=DarkOrange>8. 排序数组-快排-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code>，请你将该数组升序排列</p><p><strong>思路：</strong></p><p>通过划分将待排序的序列分成前后两部分，其中前一部分的数据都比后一部分的数据要小，然后再递归调用函数对两部分的序列分别进行快速排序</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="9-合并两个有序链表-简单"><a href="#9-合并两个有序链表-简单" class="headerlink" title="9. 合并两个有序链表-简单"></a><font color=DarkOrange>9. 合并两个有序链表-简单</font></h4><p><strong>题目：</strong></p><p>将两个升序链表合并为一个新的 <strong>升序</strong> 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的</p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="10-两数之和-简单"><a href="#10-两数之和-简单" class="headerlink" title="10. 两数之和-简单"></a><font color=DarkOrange>10. 两数之和-简单</font></h4><p><strong>题目：</strong></p><p>给定一个整数数组 <code>nums</code> 和一个整数目标值 <code>target</code>，请你在该数组中找出 <strong>和为目标值</strong> <em><code>target</code></em> 的那 <strong>两个</strong> 整数，并返回它们的数组下标</p><p>你可以假设每种输入只会对应一个答案。但是，数组中同一个元素在答案里不能重复出现</p><p>你可以按任意顺序返回答案</p><p><strong>思路：</strong></p><p>方法一：暴力枚举</p><p>方法二：哈希表</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="11-二叉树的层序遍历-中等"><a href="#11-二叉树的层序遍历-中等" class="headerlink" title="11. 二叉树的层序遍历-中等"></a><font color=DarkOrange>11. 二叉树的层序遍历-中等</font></h4><p><strong>题目：</strong></p><p>给你二叉树的根节点 <code>root</code> ，返回其节点值的 <strong>层序遍历</strong> 。 （即逐层地，从左到右访问所有节点）</p><p><strong>思路：</strong></p><p>广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="12-搜索旋转排序数组-中等"><a href="#12-搜索旋转排序数组-中等" class="headerlink" title="12. 搜索旋转排序数组-中等"></a><font color=DarkOrange>12. 搜索旋转排序数组-中等</font></h4><p><strong>题目：</strong></p><p>整数数组 <code>nums</code> 按升序排列，数组中的值 <strong>互不相同</strong> </p><p>在传递给函数之前，<code>nums</code>在预先未知的某个下标 <code>k</code>（<code>0 &lt;= k &lt; nums.length</code>）上进行了 旋转，使数组变为<code>[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]</code>（下标 从 0 开始 计数）。例如，<code> [0,1,2,4,5,6,7]</code>在下标<code>3</code>处经旋转后可能变为<code>[4,5,6,7,0,1,2]</code> </p><p>给你 <strong>旋转后</strong> 的数组 <code>nums</code> 和一个整数 <code>target</code> ，如果 <code>nums</code> 中存在这个目标值 <code>target</code> ，则返回它的下标，否则返回 <code>-1</code> </p><p>你必须设计一个时间复杂度为 <code>O(log n)</code> 的算法解决此问题</p><p><strong>思路：</strong></p><p>二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="13-买卖股票的最佳时机-简单"><a href="#13-买卖股票的最佳时机-简单" class="headerlink" title="13. 买卖股票的最佳时机-简单"></a><font color=DarkOrange>13. 买卖股票的最佳时机-简单</font></h4><p><strong>题目：</strong></p><p>给定一个数组 <code>prices</code> ，它的第 <code>i</code> 个元素 <code>prices[i]</code> 表示一支给定股票第 <code>i</code> 天的价格</p><p>你只能选择 <strong>某一天</strong> 买入这只股票，并选择在 <strong>未来的某一个不同的日子</strong> 卖出该股票。设计一个算法来计算你所能获取的最大利润</p><p>返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润，返回 <code>0</code> </p><p><strong>思路：</strong></p><p>方法一：暴力法</p><p>方法二：一次遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="14-有效的括号-简单"><a href="#14-有效的括号-简单" class="headerlink" title="14. 有效的括号-简单"></a><font color=DarkOrange>14. 有效的括号-简单</font></h4><p><strong>题目：</strong></p><p>给定一个只包括 <code>&#39;(&#39;</code>，<code>&#39;)&#39;</code>，<code>&#39;&#123;&#39;</code>，<code>&#39;&#125;&#39;</code>，<code>&#39;[&#39;</code>，<code>&#39;]&#39;</code> 的字符串 <code>s</code> ，判断字符串是否有效</p><p>有效字符串需满足：</p><ol><li>左括号必须用相同类型的右括号闭合</li><li>左括号必须以正确的顺序闭合</li><li>每个右括号都有一个对应的相同类型的左括号</li></ol><p><strong>思路：</strong></p><p>栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="15-岛屿数量-中等"><a href="#15-岛屿数量-中等" class="headerlink" title="15. 岛屿数量-中等"></a><font color=DarkOrange>15. 岛屿数量-中等</font></h4><p><strong>题目：</strong></p><p>给你一个由 <code>&#39;1&#39;</code>（陆地）和 <code>&#39;0&#39;</code>（水）组成的的二维网格，请你计算网格中岛屿的数量</p><p>岛屿总是被水包围，并且每座岛屿只能由水平方向和&#x2F;或竖直方向上相邻的陆地连接形成</p><p>此外，你可以假设该网格的四条边均被水包围</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：广度优先搜索</p><p>方法三：并查集</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="16-环形链表-简单"><a href="#16-环形链表-简单" class="headerlink" title="16. 环形链表-简单"></a><font color=DarkOrange>16. 环形链表-简单</font></h4><p><strong>题目：</strong></p><p>给你一个链表的头节点 <code>head</code> ，判断链表中是否有环</p><p>如果链表中有某个节点，可以通过连续跟踪 <code>next</code> 指针再次到达，则链表中存在环。 为了表示给定链表中的环，评测系统内部使用整数 <code>pos</code> 来表示链表尾连接到链表中的位置（索引从 0 开始）。<strong>注意：<code>pos</code> 不作为参数进行传递</strong> 。仅仅是为了标识链表的实际情况</p><p><em>如果链表中存在环</em> ，则返回 <code>true</code> 。 否则，返回 <code>false</code> </p><p><strong>思路：</strong></p><p>方法一：哈希表</p><p>方法二：快慢指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="17-最长回文子串-中等"><a href="#17-最长回文子串-中等" class="headerlink" title="17. 最长回文子串-中等"></a><font color=DarkOrange>17. 最长回文子串-中等</font></h4><p><strong>题目：</strong></p><p>给你一个字符串 <code>s</code>，找到 <code>s</code> 中最长的回文子串</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：中心扩展算法</p><p>方法三：Manacher 算法</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="18-二叉树的锯齿形层序遍历-中等"><a href="#18-二叉树的锯齿形层序遍历-中等" class="headerlink" title="18. 二叉树的锯齿形层序遍历-中等"></a><font color=DarkOrange>18. 二叉树的锯齿形层序遍历-中等</font></h4><p><strong>题目：</strong></p><p>给你二叉树的根节点 <code>root</code> ，返回其节点值的 <strong>锯齿形层序遍历</strong> 。（即先从左往右，再从右往左进行下一层遍历，以此类推，层与层之间交替进行）</p><p><strong>思路：</strong></p><p>广度优先遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="19-合并两个有序数组-简单"><a href="#19-合并两个有序数组-简单" class="headerlink" title="19. 合并两个有序数组-简单"></a><font color=DarkOrange>19. 合并两个有序数组-简单</font></h4><p><strong>题目：</strong></p><p>给你两个按 <strong>非递减顺序</strong> 排列的整数数组 <code>nums1</code> 和 <code>nums2</code>，另有两个整数 <code>m</code> 和 <code>n</code> ，分别表示 <code>nums1</code> 和 <code>nums2</code> 中的元素数目</p><p>请你 <strong>合并</strong> <code>nums2</code> 到 <code>nums1</code> 中，使合并后的数组同样按 <strong>非递减顺序</strong> 排列</p><p><strong>注意：</strong>最终，合并后数组不应由函数返回，而是存储在数组 <code>nums1</code> 中。为了应对这种情况，<code>nums1</code> 的初始长度为 <code>m + n</code>，其中前 <code>m</code> 个元素表示应合并的元素，后 <code>n</code> 个元素为 <code>0</code> ，应忽略。<code>nums2</code> 的长度为 <code>n</code> </p><p><strong>思路：</strong></p><p>方法一：直接合并后排序</p><p>方法二：双指针</p><p>方法三：逆向双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="20-二叉树的最近公共祖先-中等"><a href="#20-二叉树的最近公共祖先-中等" class="headerlink" title="20. 二叉树的最近公共祖先-中等"></a><font color=DarkOrange>20. 二叉树的最近公共祖先-中等</font></h4><p><strong>题目：</strong></p><p>给定一个二叉树, 找到该树中两个指定节点的最近公共祖先</p><p>百度百科中最近公共祖先的定义为：“对于有根树 T 的两个节点 p、q，最近公共祖先表示为一个节点 x，满足 x 是 p、q 的祖先且x 的深度尽可能大（<strong>一个节点也可以是它自己的祖先</strong>）”</p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：存储父节点</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="21-全排列-中等"><a href="#21-全排列-中等" class="headerlink" title="21. 全排列-中等"></a><font color=DarkOrange>21. 全排列-中等</font></h4><p><strong>题目：</strong></p><p>给定一个不含重复数字的数组 <code>nums</code> ，返回其 <em>所有可能的全排列</em> 。你可以 <strong>按任意顺序</strong> 返回答案</p><p><strong>思路：</strong></p><p>回溯</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="22-相交链表-简单"><a href="#22-相交链表-简单" class="headerlink" title="22. 相交链表-简单"></a><font color=DarkOrange>22. 相交链表-简单</font></h4><p><strong>题目：</strong></p><div align="center"><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h87c37dsm4j311m0q40zb.jpg" alt="image.png" style="zoom:50%;" /></div><p><strong>思路：</strong></p><p>方法一：哈希集合</p><p>方法二：双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="23-螺旋矩阵-中等"><a href="#23-螺旋矩阵-中等" class="headerlink" title="23. 螺旋矩阵-中等"></a><font color=DarkOrange>23. 螺旋矩阵-中等</font></h4><p><strong>题目：</strong></p><p>给你一个 <code>m</code> 行 <code>n</code> 列的矩阵 <code>matrix</code> ，请按照 <strong>顺时针螺旋顺序</strong> ，返回矩阵中的所有元素</p><p><strong>思路：</strong></p><p>方法一：模拟</p><p>方法二：按层模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="24-合并K个升序链表-困难"><a href="#24-合并K个升序链表-困难" class="headerlink" title="24. 合并K个升序链表-困难"></a><font color=DarkOrange>24. 合并K个升序链表-困难</font></h4><p><strong>题目：</strong></p><p>给你一个链表数组，每个链表都已经按升序排列</p><p>请你将所有链表合并到一个升序链表中，返回合并后的链表</p><p><strong>思路：</strong></p><p>方法一：顺序合并</p><p>方法二：分治合并</p><p>方法三：使用优先队列合并</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="25-反转链表-II-中等"><a href="#25-反转链表-II-中等" class="headerlink" title="25. 反转链表 II-中等"></a><font color=DarkOrange>25. 反转链表 II-中等</font></h4><p><strong>题目：</strong></p><p>给你单链表的头指针 <code>head</code> 和两个整数 <code>left</code> 和 <code>right</code> ，其中 <code>left &lt;= right</code> 。请你反转从位置 <code>left</code> 到位置 <code>right</code>的链表节点，返回 <strong>反转后的链表</strong> </p><p><strong>思路：</strong></p><p>方法一：穿针引线</p><p>方法二：一次遍历「穿针引线」反转链表（头插法）</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="26-字符串相加-简单"><a href="#26-字符串相加-简单" class="headerlink" title="26. 字符串相加-简单"></a><font color=DarkOrange>26. 字符串相加-简单</font></h4><p><strong>题目：</strong></p><p>给定两个字符串形式的非负整数 <code>num1</code> 和<code>num2</code> ，计算它们的和并同样以字符串形式返回</p><p>你不能使用任何內建的用于处理大整数的库（比如 <code>BigInteger</code>）， 也不能直接将输入的字符串转换为整数形式</p><p><strong>思路：</strong></p><p>模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="27-环形链表-II-中等"><a href="#27-环形链表-II-中等" class="headerlink" title="27. 环形链表 II-中等"></a><font color=DarkOrange>27. 环形链表 II-中等</font></h4><p><strong>题目：</strong></p><p>给定一个链表的头节点  <code>head</code> ，返回链表开始入环的第一个节点。 *如果链表无环，则返回 <code>null</code></p><p>如果链表中有某个节点，可以通过连续跟踪 <code>next</code> 指针再次到达，则链表中存在环。 为了表示给定链表中的环，评测系统内部使用整数 <code>pos</code> 来表示链表尾连接到链表中的位置（<strong>索引从 0 开始</strong>）。如果 <code>pos</code> 是 <code>-1</code>，则在该链表中没有环。<strong>注意：<code>pos</code> 不作为参数进行传递</strong>，仅仅是为了标识链表的实际情况</p><p><strong>思路：</strong></p><p>方法一：哈希表</p><p>方法二：快慢指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="28-长递增子序列-中等"><a href="#28-长递增子序列-中等" class="headerlink" title="28. 长递增子序列-中等"></a><font color=DarkOrange>28. 长递增子序列-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code> ，找到其中最长严格递增子序列的长度</p><p><strong>子序列</strong> 是由数组派生而来的序列，删除（或不删除）数组中的元素而不改变其余元素的顺序。例如，<code>[3,6,2,7]</code> 是数组 <code>[0,3,1,6,2,2,7]</code> 的子序列</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：贪心 + 二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="29-接雨水-困难"><a href="#29-接雨水-困难" class="headerlink" title="29. 接雨水-困难"></a><font color=DarkOrange>29. 接雨水-困难</font></h4><p><strong>题目：</strong></p><p>给定 <code>n</code> 个非负整数表示每个宽度为 <code>1</code> 的柱子的高度图，计算按此排列的柱子，下雨之后能接多少雨水</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：单调栈</p><p>方法三：双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="30-二叉树中的最大路径和-困难"><a href="#30-二叉树中的最大路径和-困难" class="headerlink" title="30. 二叉树中的最大路径和-困难"></a><font color=DarkOrange>30. 二叉树中的最大路径和-困难</font></h4><p><strong>题目：</strong></p><p><strong>路径</strong> 被定义为一条从树中任意节点出发，沿父节点-子节点连接，达到任意节点的序列。同一个节点在一条路径序列中 <strong>至多出现一次</strong> 。该路径 <strong>至少包含一个</strong> 节点，且不一定经过根节点</p><p><strong>路径和</strong> 是路径中各节点值的总和</p><p>给你一个二叉树的根节点 <code>root</code> ，返回其 <strong>最大路径和</strong> </p><p><strong>思路：</strong></p><p>递归</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="31-重排链表-中等"><a href="#31-重排链表-中等" class="headerlink" title="31. 重排链表-中等"></a><font color=DarkOrange>31. 重排链表-中等</font></h4><p><strong>题目：</strong></p><p>给定一个单链表 <code>L</code> 的头节点 <code>head</code> ，单链表 <code>L</code> 表示为：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">L0 → L1 → … → Ln - 1 → Ln</span><br></pre></td></tr></table></figure><p>请将其重新排列后变为：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …</span><br></pre></td></tr></table></figure><p>不能只是单纯的改变节点内部的值，而是需要实际的进行节点交换</p><p><strong>思路：</strong></p><p>方法一：线性表</p><p>方法二：寻找链表中点 + 链表逆序 + 合并链表</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="32-二叉树的中序遍历-简单"><a href="#32-二叉树的中序遍历-简单" class="headerlink" title="32. 二叉树的中序遍历-简单"></a><font color=DarkOrange>32. 二叉树的中序遍历-简单</font></h4><p><strong>题目：</strong></p><p>给定一个二叉树的根节点 <code>root</code> ，返回 它的 <strong>中序</strong>遍历</p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p>方法三：Morris 中序遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="33-二分查找-简单"><a href="#33-二分查找-简单" class="headerlink" title="33. 二分查找-简单"></a><font color=DarkOrange>33. 二分查找-简单</font></h4><p><strong>题目：</strong></p><p>给定一个 <code>n</code> 个元素有序的（升序）整型数组 <code>nums</code> 和一个目标值 <code>target</code> ，写一个函数搜索 <code>nums</code> 中的 <code>target</code>，如果目标值存在返回下标，否则返回 <code>-1</code></p><p><strong>思路：</strong></p><p>二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="34-编辑距离-困难"><a href="#34-编辑距离-困难" class="headerlink" title="34. 编辑距离-困难"></a><font color=DarkOrange>34. 编辑距离-困难</font></h4><p><strong>题目：</strong></p><p>给你两个单词 <code>word1</code> 和 <code>word2</code>， 请返回将 <code>word1</code> 转换成 <code>word2</code> 所使用的最少操作数</p><p>你可以对一个单词进行如下三种操作：</p><ul><li>插入一个字符</li><li>删除一个字符</li><li>替换一个字符</li></ul><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="35-用栈实现队列-简单"><a href="#35-用栈实现队列-简单" class="headerlink" title="35. 用栈实现队列-简单"></a><font color=DarkOrange>35. 用栈实现队列-简单</font></h4><p><strong>题目：</strong></p><p>请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作（<code>push</code>、<code>pop</code>、<code>peek</code>、<code>empty</code>）：</p><p>实现 <code>MyQueue</code> 类：</p><ul><li><code>void push(int x)</code> 将元素 x 推到队列的末尾</li><li><code>int pop()</code> 从队列的开头移除并返回元素</li><li><code>int peek()</code> 返回队列开头的元素</li><li><code>boolean empty()</code> 如果队列为空，返回 <code>true</code> ；否则，返回 <code>false</code></li></ul><p>说明：</p><ul><li>你 <strong>只能</strong> 使用标准的栈操作 —— 也就是只有 <code>push to top</code>, <code>peek/pop from top</code>, <code>size</code>, 和 <code>is empty</code> 操作是合法的</li><li>你所使用的语言也许不支持栈。你可以使用 list 或者 deque（双端队列）来模拟一个栈，只要是标准的栈操作即可</li></ul><p><strong>思路：</strong></p><p>双栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="36-寻找两个正序数组的中位数-困难"><a href="#36-寻找两个正序数组的中位数-困难" class="headerlink" title="36. 寻找两个正序数组的中位数-困难"></a><font color=DarkOrange>36. 寻找两个正序数组的中位数-困难</font></h4><p><strong>题目：</strong></p><p>给定两个大小分别为 <code>m</code> 和 <code>n</code> 的正序（从小到大）数组 <code>nums1</code> 和 <code>nums2</code>。请你找出并返回这两个正序数组的 <strong>中位数</strong> </p><p>算法的时间复杂度应该为 <code>O(log (m+n))</code> </p><p><strong>思路：</strong></p><p>方法一：二分查找</p><p>方法二：划分数组</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="37-二叉树的右视图-中等"><a href="#37-二叉树的右视图-中等" class="headerlink" title="37. 二叉树的右视图-中等"></a><font color=DarkOrange>37. 二叉树的右视图-中等</font></h4><p><strong>题目：</strong></p><p>给定一个二叉树的 <strong>根节点</strong> <code>root</code>，想象自己站在它的右侧，按照从顶部到底部的顺序，返回从右侧所能看到的节点值</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="38-除链表的倒数第N个结点-中等"><a href="#38-除链表的倒数第N个结点-中等" class="headerlink" title="38. 除链表的倒数第N个结点-中等"></a><font color=DarkOrange>38. 除链表的倒数第N个结点-中等</font></h4><p><strong>题目：</strong></p><p>给你一个链表，删除链表的倒数第 <code>n</code> 个结点，并且返回链表的头结点</p><p><strong>思路：</strong></p><p>方法一：计算链表长度</p><p>方法二：栈</p><p>方法三：双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="39-爬楼梯-简单"><a href="#39-爬楼梯-简单" class="headerlink" title="39. 爬楼梯-简单"></a><font color=DarkOrange>39. 爬楼梯-简单</font></h4><p><strong>题目：</strong></p><p>假设你正在爬楼梯。需要 <code>n</code> 阶你才能到达楼顶</p><p>每次你可以爬 <code>1</code> 或 <code>2</code> 个台阶。你有多少种不同的方法可以爬到楼顶呢</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：矩阵快速幂</p><p>方法三：通项公式</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="40-合并区间-中等"><a href="#40-合并区间-中等" class="headerlink" title="40. 合并区间-中等"></a><font color=DarkOrange>40. 合并区间-中等</font></h4><p><strong>题目：</strong></p><p>以数组 <code>intervals</code> 表示若干个区间的集合，其中单个区间为 <code>intervals[i] = [starti, endi]</code> 。请你合并所有重叠的区间，并返回一个不重叠的区间数组，该数组需恰好覆盖输入中的所有区间</p><p><strong>思路：</strong></p><p>排序</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="41-排序链表-中等"><a href="#41-排序链表-中等" class="headerlink" title="41. 排序链表-中等"></a><font color=DarkOrange>41. 排序链表-中等</font></h4><p><strong>题目：</strong></p><p>给你链表的头结点 <code>head</code> ，请将其按 <strong>升序</strong> 排列并返回 <strong>排序后的链表</strong> </p><p><strong>思路：</strong></p><p>方法一：自顶向下归并排序</p><p>方法二：自底向上归并排序</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="42-删除排序链表中的重复元素-II-中等"><a href="#42-删除排序链表中的重复元素-II-中等" class="headerlink" title="42. 删除排序链表中的重复元素 II-中等"></a><font color=DarkOrange>42. 删除排序链表中的重复元素 II-中等</font></h4><p><strong>题目：</strong></p><p>给定一个已排序的链表的头<code>head</code>，删除原始链表中所有重复数字的节点，只留下不同的数字 。返回 已排序的链表</p><p><strong>思路：</strong></p><p>一次遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="43-下一个排列-中等"><a href="#43-下一个排列-中等" class="headerlink" title="43. 下一个排列-中等"></a><font color=DarkOrange>43. 下一个排列-中等</font></h4><p><strong>题目：</strong></p><p>整数数组的一个 <strong>排列</strong> 就是将其所有成员以序列或线性顺序排列</p><ul><li>例如，<code>arr = [1,2,3]</code> ，以下这些都可以视作 <code>arr</code> 的排列：<code>[1,2,3]</code>、<code>[1,3,2]</code>、<code>[3,1,2]</code>、<code>[2,3,1]</code></li></ul><p>整数数组的 <strong>下一个排列</strong> 是指其整数的下一个字典序更大的排列。更正式地，如果数组的所有排列根据其字典顺序从小到大排列在一个容器中，那么数组的 <strong>下一个排列</strong> 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列，那么这个数组必须重排为字典序最小的排列（即，其元素按升序排列）</p><ul><li>例如，<code>arr = [1,2,3]</code> 的下一个排列是 <code>[1,3,2]</code> </li><li>类似地，<code>arr = [2,3,1]</code> 的下一个排列是 <code>[3,1,2]</code> </li><li>而 <code>arr = [3,2,1]</code> 的下一个排列是 <code>[1,2,3]</code> ，因为 <code>[3,2,1]</code> 不存在一个字典序更大的排列</li></ul><p>给你一个整数数组 <code>nums</code> ，找出 <code>nums</code> 的下一个排列</p><p>必须<strong>原地</strong>修改，只允许使用额外常数空间</p><p><strong>思路：</strong></p><p>两遍扫描</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="44-x-的平方根-简单"><a href="#44-x-的平方根-简单" class="headerlink" title="44. x 的平方根 -简单"></a><font color=DarkOrange>44. x 的平方根 -简单</font></h4><p><strong>题目：</strong></p><p>给你一个非负整数 <code>x</code> ，计算并返回 <code>x</code> 的 <strong>算术平方根</strong> </p><p>由于返回类型是整数，结果只保留 <strong>整数部分</strong> ，小数部分将被 **舍去 **</p><p><strong>注意：</strong>不允许使用任何内置指数函数和算符，例如 <code>pow(x, 0.5)</code> 或者 <code>x ** 0.5</code>  </p><p><strong>思路：</strong></p><p>方法一：袖珍计算器算法</p><p>方法二：二分查找</p><p>方法三：牛顿迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="45-两数相加-中等"><a href="#45-两数相加-中等" class="headerlink" title="45. 两数相加-中等"></a><font color=DarkOrange>45. 两数相加-中等</font></h4><p><strong>题目：</strong></p><p>给你两个 <strong>非空</strong> 的链表，表示两个非负的整数。它们每位数字都是按照 <strong>逆序</strong> 的方式存储的，并且每个节点只能存储 <strong>一位</strong> 数字</p><p>请你将两个数相加，并以相同形式返回一个表示和的链表</p><p>你可以假设除了数字 0 之外，这两个数都不会以 0 开头</p><p><strong>思路：</strong></p><p>模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="46-字符串转换整数-atoi-中等"><a href="#46-字符串转换整数-atoi-中等" class="headerlink" title="46. 字符串转换整数 (atoi)-中等"></a><font color=DarkOrange>46. 字符串转换整数 (atoi)-中等</font></h4><p><strong>题目：</strong></p><p>请你来实现一个 <code>myAtoi(string s)</code> 函数，使其能将字符串转换成一个 32 位有符号整数（类似 C&#x2F;C++ 中的 <code>atoi</code> 函数）</p><p>函数 <code>myAtoi(string s)</code> 的算法如下：</p><ol><li>读入字符串并丢弃无用的前导空格</li><li>检查下一个字符（假设还未到字符末尾）为正还是负号，读取该字符（如果有）。 确定最终结果是负数还是正数。 如果两者都不存在，则假定结果为正</li><li>读入下一个字符，直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略</li><li>将前面步骤读入的这些数字转换为整数（即，”123” -&gt; 123， “0032” -&gt; 32）。如果没有读入数字，则整数为 0 。必要时更改符号（从步骤 2 开始）</li><li>如果整数数超过 32 位有符号整数范围 <code>[−231, 231 − 1]</code> ，需要截断这个整数，使其保持在这个范围内。具体来说，小于 <code>−231</code> 的整数应该被固定为 <code>−231</code> ，大于 <code>231 − 1</code> 的整数应该被固定为 <code>231 − 1</code> </li><li>返回整数作为最终结果</li></ol><p><strong>注意：</strong></p><ul><li>本题中的空白字符只包括空格字符 <code>&#39; &#39;</code> </li><li>除前导空格或数字后的其余字符串外，<strong>请勿忽略</strong> 任何其他字符</li></ul><p><strong>思路：</strong></p><p>自动机</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="47-最长公共子序列-中等"><a href="#47-最长公共子序列-中等" class="headerlink" title="47. 最长公共子序列-中等"></a><font color=DarkOrange>47. 最长公共子序列-中等</font></h4><p><strong>题目：</strong></p><p>给定两个字符串 <code>text1</code> 和 <code>text2</code>，返回这两个字符串的最长 <strong>公共子序列</strong> 的长度。如果不存在 <strong>公共子序列</strong> ，返回 <code>0</code> </p><p>一个字符串的 <strong>子序列</strong> 是指这样一个新的字符串：它是由原字符串在不改变字符的相对顺序的情况下删除某些字符（也可以不删除任何字符）后组成的新字符串</p><ul><li>例如，<code>&quot;ace&quot;</code> 是 <code>&quot;abcde&quot;</code> 的子序列，但 <code>&quot;aec&quot;</code> 不是 <code>&quot;abcde&quot;</code> 的子序列</li></ul><p>两个字符串的 <strong>公共子序列</strong> 是这两个字符串所共同拥有的子序列</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="48-括号生成-中等"><a href="#48-括号生成-中等" class="headerlink" title="48. 括号生成-中等"></a><font color=DarkOrange>48. 括号生成-中等</font></h4><p><strong>题目：</strong></p><p>数字 <code>n</code> 代表生成括号的对数，请你设计一个函数，用于能够生成所有可能的并且 <strong>有效的</strong> 括号组合</p><p><strong>思路：</strong></p><p>方法一：暴力法</p><p>方法二：回溯法</p><p>方法三：按括号序列的长度递归</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="49-滑动窗口最大值-困难"><a href="#49-滑动窗口最大值-困难" class="headerlink" title="49. 滑动窗口最大值-困难"></a><font color=DarkOrange>49. 滑动窗口最大值-困难</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code>，有一个大小为 <code>k</code> 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的<code>k</code> 个数字。滑动窗口每次只向右移动一位</p><p>返回 滑动窗口中的最大值</p><p><strong>思路：</strong></p><p>方法一：优先队列</p><p>方法二：单调队列</p><p>方法三：分块 + 预处理</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="50-复原-IP-地址-中等"><a href="#50-复原-IP-地址-中等" class="headerlink" title="50. 复原 IP 地址-中等"></a><font color=DarkOrange>50. 复原 IP 地址-中等</font></h4><p><strong>题目：</strong></p><p><strong>有效 IP 地址</strong> 正好由四个整数（每个整数位于 <code>0</code> 到 <code>255</code> 之间组成，且不能含有前导 <code>0</code>），整数之间用 <code>&#39;.&#39;</code> 分隔</p><ul><li>例如：<code>&quot;0.1.2.201&quot;</code> 和<code> &quot;192.168.1.1&quot;</code> 是 <strong>有效</strong> IP 地址，但是 <code>&quot;0.011.255.245&quot;</code>、<code>&quot;192.168.1.312&quot;</code> 和<code>&quot;192.168@1.1&quot;</code> 是 <strong>无效</strong> IP 地址</li></ul><p>给定一个只包含数字的字符串 <code>s</code> ，用以表示一个 IP 地址，返回所有可能的<strong>有效 IP 地址</strong>，这些地址可以通过在 <code>s</code> 中插入 <code>&#39;.&#39;</code> 来形成。你 <strong>不能</strong> 重新排序或删除 <code>s</code> 中的任何数字。你可以按 <strong>任何</strong> 顺序返回答案</p><p><strong>思路：</strong></p><p>回溯</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="51-缺失的第一个正数-困难"><a href="#51-缺失的第一个正数-困难" class="headerlink" title="51. 缺失的第一个正数-困难"></a><font color=DarkOrange>51. 缺失的第一个正数-困难</font></h4><p><strong>题目：</strong></p><p>给你一个未排序的整数数组 <code>nums</code> ，请你找出其中没有出现的最小的正整数</p><p>请你实现时间复杂度为 <code>O(n)</code> 并且只使用常数级别额外空间的解决方案</p><p><strong>思路：</strong></p><p>方法一：哈希表</p><p>方法二：置换</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="52-链表中倒数第k个节点-简单"><a href="#52-链表中倒数第k个节点-简单" class="headerlink" title="52. 链表中倒数第k个节点-简单"></a><font color=DarkOrange>52. 链表中倒数第k个节点-简单</font></h4><p><strong>题目：</strong></p><p>输入一个链表，输出该链表中倒数第k个节点。为了符合大多数人的习惯，本题从1开始计数，即链表的尾节点是倒数第1个节点</p><p>例如，一个链表有 <code>6</code> 个节点，从头节点开始，它们的值依次是 <code>1、2、3、4、5、6</code>。这个链表的倒数第 <code>3</code> 个节点是值为 <code>4</code> 的节点</p><p><strong>思路：</strong></p><p>方法一：顺序查找</p><p>方法二：双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="53-从前序与中序遍历序列构造二叉树-中等"><a href="#53-从前序与中序遍历序列构造二叉树-中等" class="headerlink" title="53. 从前序与中序遍历序列构造二叉树-中等"></a><font color=DarkOrange>53. 从前序与中序遍历序列构造二叉树-中等</font></h4><p><strong>题目：</strong></p><p>给定两个整数数组 <code>preorder</code> 和 <code>inorder</code> ，其中 <code>preorder</code> 是二叉树的<strong>先序遍历</strong>， <code>inorder</code> 是同一棵树的<strong>中序遍历</strong>，请构造二叉树并返回其根节点</p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="54-比较版本号-中等"><a href="#54-比较版本号-中等" class="headerlink" title="54. 比较版本号-中等"></a><font color=DarkOrange>54. 比较版本号-中等</font></h4><p><strong>题目：</strong></p><p>给你两个版本号 <code>version1</code> 和 <code>version2</code> ，请你比较它们</p><p>版本号由一个或多个修订号组成，各修订号由一个 <code>&#39;.&#39;</code> 连接。每个修订号由 <strong>多位数字</strong> 组成，可能包含 <strong>前导零</strong> 。每个版本号至少包含一个字符。修订号从左到右编号，下标从 0 开始，最左边的修订号下标为 0 ，下一个修订号下标为 1 ，以此类推。例如，<code>2.5.33</code> 和 <code>0.1</code> 都是有效的版本号</p><p>比较版本号时，请按从左到右的顺序依次比较它们的修订号。比较修订号时，只需比较 <strong>忽略任何前导零后的整数值</strong> 。也就是说，修订号 <code>1</code> 和修订号 <code>001</code> <strong>相等</strong> 。如果版本号没有指定某个下标处的修订号，则该修订号视为 <code>0</code> 。例如，版本 <code>1.0</code> 小于版本<code>1.1</code> ，因为它们下标为 <code>0</code> 的修订号相同，而下标为 <code>1</code> 的修订号分别为 <code>0</code> 和 <code>1</code> ，<code>0 &lt; 1</code> </p><p>返回规则如下：</p><ul><li>如果 <code>*version1* &gt; *version2*</code> 返回 <code>1</code></li><li>如果 <code>*version1* &lt; *version2*</code> 返回 <code>-1</code></li><li>除此之外返回 <code>0</code></li></ul><p><strong>思路：</strong></p><p>方法一：字符串分割</p><p>方法二：双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="55-零钱兑换-中等"><a href="#55-零钱兑换-中等" class="headerlink" title="55. 零钱兑换-中等"></a><font color=DarkOrange>55. 零钱兑换-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>coins</code> ，表示不同面额的硬币；以及一个整数 <code>amount</code> ，表示总金额</p><p>计算并返回可以凑成总金额所需的 <strong>最少的硬币个数</strong> 。如果没有任何一种硬币组合能组成总金额，返回 <code>-1</code> </p><p>你可以认为每种硬币的数量是无限的</p><p><strong>思路：</strong></p><p>方法一：记忆化搜索</p><p>方法二：动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="56-最小覆盖子串-困难"><a href="#56-最小覆盖子串-困难" class="headerlink" title="56. 最小覆盖子串-困难"></a><font color=DarkOrange>56. 最小覆盖子串-困难</font></h4><p><strong>题目：</strong></p><p>给你一个字符串 <code>s</code> 、一个字符串 <code>t</code> 。返回 <code>s</code> 中涵盖 <code>t</code> 所有字符的最小子串。如果 <code>s</code> 中不存在涵盖 <code>t</code> 所有字符的子串，则返回空字符串 <code>&quot;&quot;</code> </p><p><strong>注意：</strong></p><ul><li>对于 <code>t</code> 中重复字符，我们寻找的子字符串中该字符数量必须不少于 <code>t</code> 中该字符数量。</li><li>如果 <code>s</code> 中存在这样的子串，我们保证它是唯一的答案</li></ul><p><strong>思路：</strong></p><p>滑动窗口</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="57-二叉树的前序遍历-简单"><a href="#57-二叉树的前序遍历-简单" class="headerlink" title="57. 二叉树的前序遍历-简单"></a><font color=DarkOrange>57. 二叉树的前序遍历-简单</font></h4><p><strong>题目：</strong></p><p>给你二叉树的根节点 <code>root</code> ，返回它节点值的 <strong>前序</strong> 遍历</p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p>方法三：Morris 遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="58-反转字符串中的单词-中等"><a href="#58-反转字符串中的单词-中等" class="headerlink" title="58. 反转字符串中的单词-中等"></a><font color=DarkOrange>58. 反转字符串中的单词-中等</font></h4><p><strong>题目：</strong></p><p>给你一个字符串 <code>s</code> ，请你反转字符串中 <strong>单词</strong> 的顺序</p><p><strong>单词</strong> 是由非空格字符组成的字符串。<code>s</code> 中使用至少一个空格将字符串中的 <strong>单词</strong> 分隔开</p><p>返回 <strong>单词</strong> 顺序颠倒且 <strong>单词</strong> 之间用单个空格连接的结果字符串</p><p><strong>注意：</strong>输入字符串 <code>s</code>中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中，单词间应当仅用单个空格分隔，且不包含任何额外的空格</p><p><strong>思路：</strong></p><p>方法一：使用语言特性</p><p>方法二：自行编写对应的函数</p><p>方法三：双端队列</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="59-字符串相乘-中等"><a href="#59-字符串相乘-中等" class="headerlink" title="59. 字符串相乘-中等"></a><font color=DarkOrange>59. 字符串相乘-中等</font></h4><p><strong>题目：</strong></p><p>给定两个以字符串形式表示的非负整数 <code>num1</code> 和 <code>num2</code>，返回 <code>num1</code> 和 <code>num2</code> 的乘积，它们的乘积也表示为字符串形式</p><p><strong>注意：</strong>不能使用任何内置的 BigInteger 库或直接将输入转换为整数</p><p><strong>思路：</strong></p><p>方法一：做加法</p><p>方法二：做乘法</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="60-最小栈-中等"><a href="#60-最小栈-中等" class="headerlink" title="60. 最小栈-中等"></a><font color=DarkOrange>60. 最小栈-中等</font></h4><p><strong>题目：</strong></p><p>设计一个支持 <code>push</code> ，<code>pop</code> ，<code>top</code> 操作，并能在常数时间内检索到最小元素的栈</p><p>实现 <code>MinStack</code> 类：</p><ul><li><code>MinStack()</code> 初始化堆栈对象</li><li><code>void push(int val)</code> 将元素val推入堆栈</li><li><code>void pop()</code> 删除堆栈顶部的元素</li><li><code>int top()</code> 获取堆栈顶部的元素</li><li><code>int getMin()</code> 获取堆栈中的最小元素</li></ul><p><strong>思路：</strong></p><p>辅助栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="61-平衡二叉树-简单"><a href="#61-平衡二叉树-简单" class="headerlink" title="61. 平衡二叉树-简单"></a><font color=DarkOrange>61. 平衡二叉树-简单</font></h4><p><strong>题目：</strong></p><p>给定一个二叉树，判断它是否是高度平衡的二叉树</p><p>本题中，一棵高度平衡二叉树定义为：</p><blockquote><p>一个二叉树<em>每个节点</em> 的左右两个子树的高度差的绝对值不超过 1 </p></blockquote><p><strong>思路：</strong></p><p>方法一：自顶向下的递归</p><p>方法二：自底向上的递归</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="62-子集-中等"><a href="#62-子集-中等" class="headerlink" title="62. 子集-中等"></a><font color=DarkOrange>62. 子集-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code> ，数组中的元素 <strong>互不相同</strong> 。返回该数组所有可能的子集（幂集）</p><p>解集 <strong>不能</strong> 包含重复的子集。你可以按 <strong>任意顺序</strong> 返回解集</p><p><strong>思路：</strong></p><p>方法一：迭代法实现子集枚举</p><p>方法二：递归法实现子集枚举</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="63-二叉树的最大深度-简单"><a href="#63-二叉树的最大深度-简单" class="headerlink" title="63. 二叉树的最大深度-简单"></a><font color=DarkOrange>63. 二叉树的最大深度-简单</font></h4><p><strong>题目：</strong></p><p>给定一个二叉树，找出其最大深度</p><p>二叉树的深度为根节点到最远叶子节点的最长路径上的节点数</p><p><strong>说明:</strong> 叶子节点是指没有子节点的节点</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="64-求根节点到叶节点数字之和-中等"><a href="#64-求根节点到叶节点数字之和-中等" class="headerlink" title="64. 求根节点到叶节点数字之和-中等"></a><font color=DarkOrange>64. 求根节点到叶节点数字之和-中等</font></h4><p><strong>题目：</strong></p><p>给你一个二叉树的根节点 <code>root</code> ，树中每个节点都存放有一个 <code>0</code> 到 <code>9</code> 之间的数字</p><p>每条从根节点到叶节点的路径都代表一个数字：</p><ul><li>例如，从根节点到叶节点的路径 <code>1 -&gt; 2 -&gt; 3</code> 表示数字 <code>123</code></li></ul><p>计算从根节点到叶节点生成的 <strong>所有数字之和</strong> </p><p><strong>叶节点</strong> 是指没有子节点的节点</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="65-最长有效括号-困难"><a href="#65-最长有效括号-困难" class="headerlink" title="65. 最长有效括号-困难"></a><font color=DarkOrange>65. 最长有效括号-困难</font></h4><p><strong>题目：</strong></p><p>给你一个只包含 <code>&#39;(&#39;</code> 和 <code>&#39;)&#39;</code> 的字符串，找出最长有效（格式正确且连续）括号子串的长度</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：栈</p><p>方法三：不需要额外的空间</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="66-对称二叉树-简单"><a href="#66-对称二叉树-简单" class="headerlink" title="66. 对称二叉树-简单"></a><font color=DarkOrange>66. 对称二叉树-简单</font></h4><p><strong>题目：</strong></p><p>给你一个二叉树的根节点 <code>root</code> ， 检查它是否轴对称</p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="67-验证二叉搜索树-中等"><a href="#67-验证二叉搜索树-中等" class="headerlink" title="67. 验证二叉搜索树-中等"></a><font color=DarkOrange>67. 验证二叉搜索树-中等</font></h4><p><strong>题目：</strong></p><p>给你一个二叉树的根节点 <code>root</code> ，判断其是否是一个有效的二叉搜索树</p><p><strong>有效</strong> 二叉搜索树定义如下：</p><ul><li>节点的左子树只包含 <strong>小于</strong> 当前节点的数</li><li>节点的右子树只包含 <strong>大于</strong> 当前节点的数</li><li>所有左子树和右子树自身必须也是二叉搜索树</li></ul><p><strong>思路：</strong></p><p>方法一: 递归</p><p>方法二：中序遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="68-最小路径和-中等"><a href="#68-最小路径和-中等" class="headerlink" title="68. 最小路径和-中等"></a><font color=DarkOrange>68. 最小路径和-中等</font></h4><p><strong>题目：</strong></p><p>给定一个包含非负整数的 m x n 网格 grid ，请找出一条从左上角到右下角的路径，使得路径上的数字总和为最小</p><p><strong>说明：</strong>每次只能向下或者向右移动一步</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="69-二叉树的直径-简单"><a href="#69-二叉树的直径-简单" class="headerlink" title="69. 二叉树的直径-简单"></a><font color=DarkOrange>69. 二叉树的直径-简单</font></h4><p><strong>题目：</strong></p><p>给定一棵二叉树，你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点</p><p><strong>思路：</strong></p><p>深度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="70-路径总和-II-中等"><a href="#70-路径总和-II-中等" class="headerlink" title="70. 路径总和 II-中等"></a><font color=DarkOrange>70. 路径总和 II-中等</font></h4><p><strong>题目：</strong></p><p>给你二叉树的根节点 <code>root</code> 和一个整数目标和 <code>targetSum</code> ，找出所有 <strong>从根节点到叶子节点</strong> 路径总和等于给定目标和的路径</p><p><strong>叶子节点</strong> 是指没有子节点的节点</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="71-Rand7-实现-Rand10-简单"><a href="#71-Rand7-实现-Rand10-简单" class="headerlink" title="71.  Rand7() 实现 Rand10()-简单"></a><font color=DarkOrange>71.  Rand7() 实现 Rand10()-简单</font></h4><p><strong>题目：</strong></p><p>给定方法 <code>rand7</code> 可生成 <code>[1,7]</code> 范围内的均匀随机整数，试写一个方法 <code>rand10</code> 生成 <code>[1,10]</code> 范围内的均匀随机整数</p><p>你只能调用 <code>rand7()</code> 且不能调用其他方法。请不要使用系统的 <code>Math.random()</code> 方法</p><p>每个测试用例将有一个内部参数 <code>n</code>，即你实现的函数 <code>rand10()</code> 在测试时将被调用的次数。请注意，这不是传递给 <code>rand10()</code> 的参数</p><p><strong>思路：</strong></p><p>拒绝采样</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="72-组合总和-中等"><a href="#72-组合总和-中等" class="headerlink" title="72. 组合总和-中等"></a><font color=DarkOrange>72. 组合总和-中等</font></h4><p><strong>题目：</strong></p><p>给你一个 <strong>无重复元素</strong> 的整数数组 <code>candidates</code> 和一个目标整数 <code>target</code> ，找出 <code>candidates</code> 中可以使数字和为目标数 <code>target</code> 的 所有 <strong>不同组合</strong> ，并以列表形式返回。你可以按 <strong>任意顺序</strong> 返回这些组合</p><p><code>candidates</code> 中的 <strong>同一个</strong> 数字可以 <strong>无限制重复被选取</strong> 。如果至少一个数字的被选数量不同，则两种组合是不同的</p><p>对于给定的输入，保证和为 <code>target</code> 的不同组合数少于 <code>150</code> 个</p><p><strong>思路：</strong></p><p>搜索回溯</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="73-旋转图像-中等"><a href="#73-旋转图像-中等" class="headerlink" title="73. 旋转图像-中等"></a><font color=DarkOrange>73. 旋转图像-中等</font></h4><p><strong>题目：</strong></p><p>给定一个 <em>n</em> × <em>n</em> 的二维矩阵 <code>matrix</code> 表示一个图像。请你将图像顺时针旋转 90 度</p><p>你必须在<strong>原地</strong> 旋转图像，这意味着你需要直接修改输入的二维矩阵。<strong>请不要</strong> 使用另一个矩阵来旋转图像</p><p><strong>思路：</strong></p><p>方法一：使用辅助数组</p><p>方法二：原地旋转</p><p>方法三：用翻转代替旋转</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="74-路径总和-简单"><a href="#74-路径总和-简单" class="headerlink" title="74. 路径总和-简单"></a><font color=DarkOrange>74. 路径总和-简单</font></h4><p><strong>题目：</strong></p><p>给你二叉树的根节点 <code>root</code> 和一个表示目标和的整数 <code>targetSum</code> 。判断该树中是否存在 <strong>根节点到叶子节点</strong> 的路径，这条路径上所有节点值相加等于目标和 <code>targetSum</code> 。如果存在，返回 <code>true</code> ；否则，返回 <code>false</code> </p><p><strong>叶子节点</strong> 是指没有子节点的节点</p><p><strong>思路：</strong></p><p>方法一：广度优先搜索</p><p>方法二：递归</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="75-回文链表-简单"><a href="#75-回文链表-简单" class="headerlink" title="75. 回文链表-简单"></a><font color=DarkOrange>75. 回文链表-简单</font></h4><p><strong>题目：</strong></p><p>给你一个单链表的头节点 <code>head</code> ，请你判断该链表是否为回文链表。如果是，返回 <code>true</code> ；否则，返回 <code>false</code> </p><p><strong>思路：</strong></p><p>方法一：将值复制到数组中后用双指针法</p><p>方法二：递归</p><p>方法三：快慢指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="76-多数元素-简单"><a href="#76-多数元素-简单" class="headerlink" title="76. 多数元素-简单"></a><font color=DarkOrange>76. 多数元素-简单</font></h4><p><strong>题目：</strong></p><p>给定一个大小为 <code>n</code> 的数组 <code>nums</code> ，返回其中的多数元素。多数元素是指在数组中出现次数 <strong>大于</strong> <code>⌊ n/2 ⌋</code> 的元素</p><p>你可以假设数组是非空的，并且给定的数组总是存在多数元素</p><p><strong>思路：</strong></p><p>方法一：哈希表</p><p>方法二：排序</p><p>方法三：随机化</p><p>方法四：分治</p><p>方法五：Boyer-Moore 投票算法</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="77-最长重复子数组-中等"><a href="#77-最长重复子数组-中等" class="headerlink" title="77. 最长重复子数组-中等"></a><font color=DarkOrange>77. 最长重复子数组-中等</font></h4><p><strong>题目：</strong></p><p>给两个整数数组 <code>nums1</code> 和 <code>nums2</code> ，返回两个数组中 <strong>公共的</strong> 、长度最长的子数组的长度 </p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：滑动窗口</p><p>方法三：二分查找 + 哈希</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="78-最大正方形-中等"><a href="#78-最大正方形-中等" class="headerlink" title="78. 最大正方形-中等"></a><font color=DarkOrange>78. 最大正方形-中等</font></h4><p><strong>题目：</strong></p><p>在一个由 <code>&#39;0&#39;</code> 和 <code>&#39;1&#39;</code> 组成的二维矩阵内，找到只包含 <code>&#39;1&#39;</code> 的最大正方形，并返回其面积</p><p><strong>思路：</strong></p><p>方法一：暴力法</p><p>方法二：动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="79-字符串解码-中等"><a href="#79-字符串解码-中等" class="headerlink" title="79. 字符串解码-中等"></a><font color=DarkOrange>79. 字符串解码-中等</font></h4><p><strong>题目：</strong></p><p>给定一个经过编码的字符串，返回它解码后的字符串</p><p>编码规则为: <code>k[encoded_string]</code>，表示其中方括号内部的 <code>encoded_string</code> 正好重复 <code>k</code> 次。注意 <code>k</code> 保证为正整数</p><p>你可以认为输入字符串总是有效的；输入字符串中没有额外的空格，且输入的方括号总是符合格式要求的</p><p>此外，你可以认为原始数据不包含数字，所有的数字只表示重复的次数 <code>k</code> ，例如不会出现像 <code>3a</code> 或 <code>2[4]</code> 的输入</p><p><strong>思路：</strong></p><p>方法一：栈操作</p><p>方法二：递归</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="80-搜索二维矩阵-II-中等"><a href="#80-搜索二维矩阵-II-中等" class="headerlink" title="80. 搜索二维矩阵 II-中等"></a><font color=DarkOrange>80. 搜索二维矩阵 II-中等</font></h4><p><strong>题目：</strong></p><p>编写一个高效的算法来搜索 <code>*m* x *n*</code> 矩阵 <code>matrix</code> 中的一个目标值 <code>target</code> 。该矩阵具有以下特性：</p><ul><li>每行的元素从左到右升序排列</li><li>每列的元素从上到下升序排列</li></ul><p><strong>思路：</strong></p><p>方法一：直接查找</p><p>方法二：二分查找</p><p>方法三：Z 字形查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="81-翻转二叉树-简单"><a href="#81-翻转二叉树-简单" class="headerlink" title="81. 翻转二叉树-简单"></a><font color=DarkOrange>81. 翻转二叉树-简单</font></h4><p><strong>题目：</strong></p><p>给你一棵二叉树的根节点 <code>root</code> ，翻转这棵二叉树，并返回其根节点</p><p><strong>思路：</strong></p><p>递归</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="82-在排序数组中查找元素的第一个和最后一个位置-中等"><a href="#82-在排序数组中查找元素的第一个和最后一个位置-中等" class="headerlink" title="82. 在排序数组中查找元素的第一个和最后一个位置-中等"></a><font color=DarkOrange>82. 在排序数组中查找元素的第一个和最后一个位置-中等</font></h4><p><strong>题目：</strong></p><p>给你一个按照非递减顺序排列的整数数组 <code>nums</code>，和一个目标值 <code>target</code>。请你找出给定目标值在数组中的开始位置和结束位置</p><p>如果数组中不存在目标值 <code>target</code>，返回 <code>[-1, -1]</code></p><p>你必须设计并实现时间复杂度为 <code>O(log n)</code> 的算法解决此问题</p><p><strong>思路：</strong></p><p>二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="83-最长公共前缀-简单"><a href="#83-最长公共前缀-简单" class="headerlink" title="83. 最长公共前缀-简单"></a><font color=DarkOrange>83. 最长公共前缀-简单</font></h4><p><strong>题目：</strong></p><p>编写一个函数来查找字符串数组中的最长公共前缀</p><p>如果不存在公共前缀，返回空字符串 <code>&quot;&quot;</code></p><p><strong>思路：</strong></p><p>方法一：横向扫描</p><p>方法二：纵向扫描</p><p>方法三：分治</p><p>方法四：二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="84-寻找峰值-中等"><a href="#84-寻找峰值-中等" class="headerlink" title="84. 寻找峰值-中等"></a><font color=DarkOrange>84. 寻找峰值-中等</font></h4><p><strong>题目：</strong></p><p>峰值元素是指其值严格大于左右相邻值的元素</p><p>给你一个整数数组 <code>nums</code>，找到峰值元素并返回其索引。数组可能包含多个峰值，在这种情况下，返回 <strong>任何一个峰值</strong> 所在位置即可</p><p>你可以假设 <code>nums[-1] = nums[n] = -∞</code> </p><p>你必须实现时间复杂度为 <code>O(log n)</code> 的算法来解决此问题</p><p><strong>思路：</strong></p><p>方法一：寻找最大值</p><p>方法二：迭代爬坡</p><p>方法三：方法二的二分查找优化</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="85-最长连续序列-中等"><a href="#85-最长连续序列-中等" class="headerlink" title="85. 最长连续序列-中等"></a><font color=DarkOrange>85. 最长连续序列-中等</font></h4><p><strong>题目：</strong></p><p>给定一个未排序的整数数组 <code>nums</code> ，找出数字连续的最长序列（不要求序列元素在原数组中连续）的长度</p><p>请你设计并实现时间复杂度为 <code>O(n)</code> 的算法解决此问题</p><p><strong>思路：</strong></p><p>哈希表</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="86-基本计算器-II-中等"><a href="#86-基本计算器-II-中等" class="headerlink" title="86. 基本计算器 II-中等"></a><font color=DarkOrange>86. 基本计算器 II-中等</font></h4><p><strong>题目：</strong></p><p>给你一个字符串表达式 <code>s</code> ，请你实现一个基本计算器来计算并返回它的值</p><p>整数除法仅保留整数部分</p><p>你可以假设给定的表达式总是有效的。所有中间结果将在 <code>[-2^31, 2^31 - 1]</code> 的范围内</p><p><strong>注意：</strong>不允许使用任何将字符串作为数学表达式计算的内置函数，比如 <code>eval()</code> </p><p><strong>思路：</strong></p><p>栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="87-岛屿的最大面积-中等"><a href="#87-岛屿的最大面积-中等" class="headerlink" title="87. 岛屿的最大面积-中等"></a><font color=DarkOrange>87. 岛屿的最大面积-中等</font></h4><p><strong>题目：</strong></p><p>给你一个大小为 <code>m x n</code> 的二进制矩阵 <code>grid</code> </p><p><strong>岛屿</strong> 是由一些相邻的 <code>1</code> (代表土地) 构成的组合，这里的「相邻」要求两个 <code>1</code> 必须在 <strong>水平或者竖直的四个方向上</strong> 相邻。你可以假设 <code>grid</code> 的四个边缘都被 <code>0</code>（代表水）包围着</p><p>岛屿的面积是岛上值为 <code>1</code> 的单元格的数目</p><p>计算并返回 <code>grid</code> 中最大的岛屿面积。如果没有岛屿，则返回面积为 <code>0</code> </p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：深度优先搜索 + 栈</p><p>方法三：广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="88-删除排序链表中的重复元素-简单"><a href="#88-删除排序链表中的重复元素-简单" class="headerlink" title="88. 删除排序链表中的重复元素-简单"></a><font color=DarkOrange>88. 删除排序链表中的重复元素-简单</font></h4><p><strong>题目：</strong></p><p>给定一个已排序的链表的头 <code>head</code> ， 删除所有重复的元素，使每个元素只出现一次 。返回已排序的链表</p><p><strong>思路：</strong></p><p>一次遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="89-不同路径-中等"><a href="#89-不同路径-中等" class="headerlink" title="89. 不同路径-中等"></a><font color=DarkOrange>89. 不同路径-中等</font></h4><p><strong>题目：</strong></p><p>一个机器人位于一个 <code>m x n</code> 网格的左上角 （起始点在下图中标记为 “Start” ）</p><p>机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角（在下图中标记为 “Finish” ）</p><p>问总共有多少条不同的路径？</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：组合数学</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="90-打家劫舍-中等"><a href="#90-打家劫舍-中等" class="headerlink" title="90. 打家劫舍-中等"></a><font color=DarkOrange>90. 打家劫舍-中等</font></h4><p><strong>题目：</strong></p><p>你是一个专业的小偷，计划偷窃沿街的房屋。每间房内都藏有一定的现金，影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统，<strong>如果两间相邻的房屋在同一晚上被小偷闯入，系统会自动报警</strong></p><p>给定一个代表每个房屋存放金额的非负整数数组，计算你 <strong>不触动警报装置的情况下</strong> ，一夜之内能够偷窃到的最高金额</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="91-买卖股票的最佳时机-II-中等"><a href="#91-买卖股票的最佳时机-II-中等" class="headerlink" title="91. 买卖股票的最佳时机 II-中等"></a><font color=DarkOrange>91. 买卖股票的最佳时机 II-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>prices</code> ，其中 <code>prices[i]</code> 表示某支股票第 <code>i</code> 天的价格</p><p>在每一天，你可以决定是否购买和&#x2F;或出售股票。你在任何时候 <strong>最多</strong> 只能持有 <strong>一股</strong> 股票。你也可以先购买，然后在 <strong>同一天</strong> 出售</p><p>返回你能获得的 <strong>最大</strong> 利润</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：贪心</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="92-两两交换链表中的节点-中等"><a href="#92-两两交换链表中的节点-中等" class="headerlink" title="92. 两两交换链表中的节点-中等"></a><font color=DarkOrange>92. 两两交换链表中的节点-中等</font></h4><p><strong>题目：</strong></p><p>给你一个链表，两两交换其中相邻的节点，并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题（即，只能进行节点交换）</p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="93-乘积最大子数组-中等"><a href="#93-乘积最大子数组-中等" class="headerlink" title="93. 乘积最大子数组-中等"></a><font color=DarkOrange>93. 乘积最大子数组-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 nums ，请你找出数组中乘积最大的非空连续子数组（该子数组中至少包含一个数字），并返回该子数组所对应的乘积</p><p>测试用例的答案是一个 <strong>32-位</strong> 整数</p><p><strong>子数组</strong> 是数组的连续子序列</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="94-移动零-简单"><a href="#94-移动零-简单" class="headerlink" title="94. 移动零-简单"></a><font color=DarkOrange>94. 移动零-简单</font></h4><p><strong>题目：</strong></p><p>给定一个数组 <code>nums</code>，编写一个函数将所有 <code>0</code> 移动到数组的末尾，同时保持非零元素的相对顺序</p><p><strong>请注意</strong> ，必须在不复制数组的情况下原地对数组进行操作</p><p><strong>思路：</strong></p><p>双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="95-二叉树最大宽度-中等"><a href="#95-二叉树最大宽度-中等" class="headerlink" title="95. 二叉树最大宽度-中等"></a><font color=DarkOrange>95. 二叉树最大宽度-中等</font></h4><p><strong>题目：</strong></p><p>给你一棵二叉树的根节点 <code>root</code> ，返回树的 <strong>最大宽度</strong> </p><p>树的 <strong>最大宽度</strong> 是所有层中最大的 <strong>宽度</strong> </p><p>每一层的 <strong>宽度</strong> 被定义为该层最左和最右的非空节点（即，两个端点）之间的长度。将这个二叉树视作与满二叉树结构相同，两端点间会出现一些延伸到这一层的 <code>null</code> 节点，这些 <code>null</code> 节点也计入长度</p><p>题目数据保证答案将会在 <strong>32 位</strong> 带符号整数范围内</p><p><strong>思路：</strong></p><p>方法一：广度优先搜索</p><p>方法二：深度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="96-复制带随机指针的链表-中等"><a href="#96-复制带随机指针的链表-中等" class="headerlink" title="96. 复制带随机指针的链表-中等"></a><font color=DarkOrange>96. 复制带随机指针的链表-中等</font></h4><p><strong>题目：</strong></p><p>给你一个长度为 <code>n</code> 的链表，每个节点包含一个额外增加的随机指针 <code>random</code> ，该指针可以指向链表中的任何节点或空节点</p><p>构造这个链表的 <strong><a href="https://baike.baidu.com/item/%E6%B7%B1%E6%8B%B7%E8%B4%9D/22785317?fr=aladdin">深拷贝</a><strong>。 深拷贝应该正好由 <code>n</code> 个 <strong>全新</strong> 节点组成，其中每个新节点的值都设为其对应的原节点的值。新节点的<code>next</code> 指针和 <code>random</code> 指针也都应指向复制链表中的新节点，并使原链表和复制链表中的这些指针能够表示相同的链表状态。</strong>复制链表中的指针都不应指向原链表中的节点</strong> </p><p>例如，如果原链表中有 <code>X</code> 和 <code>Y</code> 两个节点，其中 <code>X.random --&gt; Y</code> 。那么在复制链表中对应的两个节点 <code>x</code> 和 <code>y</code> ，同样有 <code>x.random --&gt; y</code> </p><p>返回复制链表的头节点</p><p>用一个由 <code>n</code> 个节点组成的链表来表示输入&#x2F;输出中的链表。每个节点用一个 <code>[val, random_index]</code> 表示：</p><ul><li><code>val</code>：一个表示 <code>Node.val</code> 的整数</li><li><code>random_index</code>：随机指针指向的节点索引（范围从 <code>0</code> 到 <code>n-1</code>）；如果不指向任何节点，则为 <code>null</code></li></ul><p>你的代码 <strong>只</strong> 接受原链表的头节点 <code>head</code> 作为传入参数</p><p><strong>思路：</strong></p><p>方法一：回溯 + 哈希表</p><p>方法二：迭代 + 节点拆分</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="97-排序数组-堆排序-中等"><a href="#97-排序数组-堆排序-中等" class="headerlink" title="97. 排序数组-堆排序-中等"></a><font color=DarkOrange>97. 排序数组-堆排序-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code>，请你将该数组升序排列</p><p><strong>思路：</strong></p><p>先将待排序的序列建成大根堆，使得每个父节点的元素大于等于它的子节点</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="98-寻找旋转排序数组中的最小值-中等"><a href="#98-寻找旋转排序数组中的最小值-中等" class="headerlink" title="98. 寻找旋转排序数组中的最小值-中等"></a><font color=DarkOrange>98. 寻找旋转排序数组中的最小值-中等</font></h4><p><strong>题目：</strong></p><p>已知一个长度为 <code>n</code> 的数组，预先按照升序排列，经由 <code>1</code> 到 <code>n</code> 次 <strong>旋转</strong> 后，得到输入数组。例如，原数组 <code>nums = [0,1,2,4,5,6,7]</code> 在变化后可能得到：</p><ul><li>若旋转 <code>4</code> 次，则可以得到 <code>[4,5,6,7,0,1,2]</code></li><li>若旋转 <code>7</code> 次，则可以得到 <code>[0,1,2,4,5,6,7]</code></li></ul><p>注意，数组 <code>[a[0], a[1], a[2], ..., a[n-1]]</code> <strong>旋转一次</strong> 的结果为数组 <code>[a[n-1], a[0], a[1], a[2], ..., a[n-2]]</code> </p><p>给你一个元素值 <strong>互不相同</strong> 的数组 <code>nums</code> ，它原来是一个升序排列的数组，并按上述情形进行了多次旋转。请你找出并返回数组中的 <strong>最小元素</strong> </p><p>你必须设计一个时间复杂度为 <code>O(log n)</code> 的算法解决此问题</p><p><strong>思路：</strong></p><p>二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="99-最大数-中等"><a href="#99-最大数-中等" class="headerlink" title="99. 最大数-中等"></a><font color=DarkOrange>99. 最大数-中等</font></h4><p><strong>题目：</strong></p><p>给定一组非负整数 <code>nums</code>，重新排列每个数的顺序（每个数不可拆分）使之组成一个最大的整数</p><p><strong>注意：</strong>输出结果可能非常大，所以你需要返回一个字符串而不是整数</p><p><strong>思路：</strong></p><p>排序</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="100-二叉树的序列化与反序列化-困难"><a href="#100-二叉树的序列化与反序列化-困难" class="headerlink" title="100. 二叉树的序列化与反序列化-困难"></a><font color=DarkOrange>100. 二叉树的序列化与反序列化-困难</font></h4><p><strong>题目：</strong></p><p>序列化是将一个数据结构或者对象转换为连续的比特位的操作，进而可以将转换后的数据存储在一个文件或者内存中，同时也可以通过网络传输到另一个计算机环境，采取相反方式重构得到原数据</p><p>请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 &#x2F; 反序列化算法执行逻辑，你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：括号表示编码 + 递归下降解码</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="101-长度最小的子数组-中等"><a href="#101-长度最小的子数组-中等" class="headerlink" title="101. 长度最小的子数组-中等"></a><font color=DarkOrange>101. 长度最小的子数组-中等</font></h4><p><strong>题目：</strong></p><p>给定一个含有 <code>n</code> 个正整数的数组和一个正整数 <code>target</code> </p><p>找出该数组中满足其和 <code>≥ target</code> 的长度最小的 <strong>连续子数组</strong> <code>[numsl, numsl+1, ..., numsr-1, numsr]</code> ，并返回其长度<strong>。</strong>如果不存在符合条件的子数组，返回 <code>0</code> </p><p><strong>思路：</strong></p><p>方法一：暴力法</p><p>方法二：前缀和 + 二分查找</p><p>方法三：滑动窗口</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="102-单词拆分-中等"><a href="#102-单词拆分-中等" class="headerlink" title="102. 单词拆分-中等"></a><font color=DarkOrange>102. 单词拆分-中等</font></h4><p><strong>题目：</strong></p><p>给你一个字符串 <code>s</code> 和一个字符串列表 <code>wordDict</code> 作为字典。请你判断是否可以利用字典中出现的单词拼接出 <code>s</code> </p><p><strong>注意：</strong>不要求字典中出现的单词全部都使用，并且字典中的单词可以重复使用</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="103-验证IP地址-中等"><a href="#103-验证IP地址-中等" class="headerlink" title="103. 验证IP地址-中等"></a><font color=DarkOrange>103. 验证IP地址-中等</font></h4><p><strong>题目：</strong></p><p>给定一个字符串 <code>queryIP</code>。如果是有效的 IPv4 地址，返回 <code>&quot;IPv4&quot;</code> ；如果是有效的 IPv6 地址，返回 <code>&quot;IPv6&quot;</code> ；如果不是上述类型的 IP 地址，返回 <code>&quot;Neither&quot;</code> </p><p><strong>有效的IPv4地址</strong> 是 <code>“x1.x2.x3.x4”</code> 形式的IP地址。 其中 <code>0 &lt;= xi &lt;= 255</code> 且 <code>xi</code> <strong>不能包含</strong> 前导零。例如: <code>“192.168.1.1”</code> 、 <code>“192.168.1.0”</code> 为有效IPv4地址， <code>“192.168.01.1”</code> 为无效IPv4地址; <code>“192.168.1.00”</code> 、 <code>“192.168@1.1”</code> 为无效IPv4地址</p><p><strong>一个有效的IPv6地址</strong> 是一个格式为<code>“x1:x2:x3:x4:x5:x6:x7:x8”</code> 的IP地址，其中：</p><ul><li><code>1 &lt;= xi.length &lt;= 4</code></li><li><code>xi</code> 是一个 <strong>十六进制字符串</strong> ，可以包含数字、小写英文字母( <code>&#39;a&#39;</code> 到 <code>&#39;f&#39;</code> )和大写英文字母( <code>&#39;A&#39;</code> 到 <code>&#39;F&#39;</code> )</li><li>在 <code>xi</code> 中允许前导零</li></ul><p>例如 <code>&quot;2001:0db8:85a3:0000:0000:8a2e:0370:7334&quot;</code> 和<code>&quot;2001:db8:85a3:0:0:8A2E:0370:7334&quot;</code> 是有效的 IPv6地址，而 <code>&quot;2001:0db8:85a3::8A2E:037j:7334&quot;</code> 和 <code>&quot;02001:0db8:85a3:0000:0000:8a2e:0370:7334&quot;</code> 是无效的 IPv6 地址</p><p><strong>思路：</strong></p><p>依次判断</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="104-和为-K-的子数组-中等"><a href="#104-和为-K-的子数组-中等" class="headerlink" title="104. 和为 K 的子数组-中等"></a><font color=DarkOrange>104. 和为 K 的子数组-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code> 和一个整数 <code>k</code> ，请你统计并返回该数组中和为 <code>k</code> 的连续子数组的个数</p><p><strong>思路：</strong></p><p>方法一：枚举</p><p>方法二：前缀和 + 哈希表优化</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="105-只出现一次的数字-简单"><a href="#105-只出现一次的数字-简单" class="headerlink" title="105. 只出现一次的数字-简单"></a><font color=DarkOrange>105. 只出现一次的数字-简单</font></h4><p><strong>题目：</strong></p><p>给你一个 <strong>非空</strong> 整数数组 <code>nums</code> ，除了某个元素只出现一次以外，其余每个元素均出现两次。找出那个只出现了一次的元素</p><p>你必须设计并实现线性时间复杂度的算法来解决此问题，且该算法只使用常量额外空间</p><p><strong>思路：</strong></p><p>位运算</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="106-用两个栈实现队列-简单"><a href="#106-用两个栈实现队列-简单" class="headerlink" title="106. 用两个栈实现队列-简单"></a><font color=DarkOrange>106. 用两个栈实现队列-简单</font></h4><p><strong>题目：</strong></p><p>用两个栈实现一个队列。队列的声明如下，请实现它的两个函数 <code>appendTail</code> 和 <code>deleteHead</code> ，分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素，<code>deleteHead</code> 操作返回 -1 )</p><p><strong>思路：</strong></p><p>双栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="107-对角线遍历-中等"><a href="#107-对角线遍历-中等" class="headerlink" title="107. 对角线遍历-中等"></a><font color=DarkOrange>107. 对角线遍历-中等</font></h4><p><strong>题目：</strong></p><p>给你一个大小为 m x n 的矩阵 mat ，请以对角线遍历的顺序，用一个数组返回这个矩阵中的所有元素</p><p><strong>思路：</strong></p><p>直接模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="108-移掉-K-位数字-中等"><a href="#108-移掉-K-位数字-中等" class="headerlink" title="108. 移掉 K 位数字-中等"></a><font color=DarkOrange>108. 移掉 K 位数字-中等</font></h4><p><strong>题目：</strong></p><p>给你一个以字符串表示的非负整数 <code>num</code> 和一个整数 <code>k</code> ，移除这个数中的 <code>k</code> 位数字，使得剩下的数字最小。请你以字符串形式返回这个最小的数字</p><p><strong>思路：</strong></p><p>贪心 + 单调栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="109-基本计算器-困难"><a href="#109-基本计算器-困难" class="headerlink" title="109. 基本计算器-困难"></a><font color=DarkOrange>109. 基本计算器-困难</font></h4><p><strong>题目：</strong></p><p>给你一个字符串表达式 <code>s</code> ，请你实现一个基本计算器来计算并返回它的值</p><p>注意:不允许使用任何将字符串作为数学表达式计算的内置函数，比如 <code>eval()</code> </p><p><strong>思路：</strong></p><p>括号展开 + 栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="110-二叉搜索树与双向链表-中等"><a href="#110-二叉搜索树与双向链表-中等" class="headerlink" title="110. 二叉搜索树与双向链表-中等"></a><font color=DarkOrange>110. 二叉搜索树与双向链表-中等</font></h4><p><strong>题目：</strong></p><p><strong>思路：</strong></p><p><strong>代码：</strong></p><h4 id="111-排序数组-归并排序-中等"><a href="#111-排序数组-归并排序-中等" class="headerlink" title="111. 排序数组-归并排序-中等"></a><font color=DarkOrange>111. 排序数组-归并排序-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code>，请你将该数组升序排列</p><p><strong>思路：</strong></p><p>利用了分治的思想来对序列进行排序</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="112-LFU-缓存-困难"><a href="#112-LFU-缓存-困难" class="headerlink" title="112. LFU 缓存-困难"></a><font color=DarkOrange>112. LFU 缓存-困难</font></h4><p><strong>题目：</strong></p><p>请你为最不经常使用（LFU）缓存算法设计并实现数据结构</p><p>实现 <code>LFUCache</code> 类：</p><ul><li><code>LFUCache(int capacity)</code> - 用数据结构的容量 <code>capacity</code> 初始化对象</li><li><code>int get(int key)</code> - 如果键 <code>key</code> 存在于缓存中，则获取键的值，否则返回 <code>-1</code> </li><li><code>void put(int key, int value)</code> - 如果键 <code>key</code> 已存在，则变更其值；如果键不存在，请插入键值对。当缓存达到其容量 <code>capacity</code> 时，则应该在插入新项之前，移除最不经常使用的项。在此问题中，当存在平局（即两个或更多个键具有相同使用频率）时，应该去除 <strong>最近最久未使用</strong> 的键</li></ul><p>为了确定最不常使用的键，可以为缓存中的每个键维护一个 <strong>使用计数器</strong> 。使用计数最小的键是最久未使用的键</p><p>当一个键首次插入到缓存中时，它的使用计数器被设置为 <code>1</code> (由于 put 操作)。对缓存中的键执行 <code>get</code> 或 <code>put</code> 操作，使用计数器的值将会递增</p><p>函数 <code>get</code> 和 <code>put</code> 必须以 <code>O(1)</code> 的平均时间复杂度运行</p><p><strong>思路：</strong></p><p>方法一：哈希表 + 平衡二叉树</p><p>方法二：双哈希表</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="113-每日温度-中等"><a href="#113-每日温度-中等" class="headerlink" title="113. 每日温度-中等"></a><font color=DarkOrange>113. 每日温度-中等</font></h4><p><strong>题目：</strong></p><p>给定一个整数数组 <code>temperatures</code> ，表示每天的温度，返回一个数组 <code>answer</code> ，其中 <code>answer[i]</code> 是指对于第 <code>i</code> 天，下一个更高温度出现在几天后。如果气温在这之后都不会升高，请在该位置用 <code>0</code> 来代替</p><p><strong>思路：</strong></p><p>方法一：暴力</p><p>方法二：单调栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="114-课程表-中等"><a href="#114-课程表-中等" class="headerlink" title="114. 课程表-中等"></a><font color=DarkOrange>114. 课程表-中等</font></h4><p><strong>题目：</strong></p><p>你这个学期必须选修 <code>numCourses</code> 门课程，记为 <code>0</code> 到 <code>numCourses - 1</code> </p><p>在选修某些课程之前需要一些先修课程。 先修课程按数组 <code>prerequisites</code> 给出，其中 <code>prerequisites[i] = [ai, bi]</code> ，表示如果要学习课程 <code>ai</code> 则 <strong>必须</strong> 先学习课程 <code>bi</code> </p><ul><li>例如，先修课程对 <code>[0, 1]</code> 表示：想要学习课程 <code>0</code> ，你需要先完成课程 <code>1</code></li></ul><p>请你判断是否可能完成所有课程的学习？如果可以，返回 <code>true</code> ；否则，返回 <code>false</code> </p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二: 广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="115-排序奇升偶降链表-中等"><a href="#115-排序奇升偶降链表-中等" class="headerlink" title="115. 排序奇升偶降链表-中等"></a><font color=DarkOrange>115. 排序奇升偶降链表-中等</font></h4><p><strong>题目：</strong></p><p>字节跳动高频题</p><p><strong>思路：</strong></p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="116-二叉树的完全性检验-中等"><a href="#116-二叉树的完全性检验-中等" class="headerlink" title="116. 二叉树的完全性检验-中等"></a><font color=DarkOrange>116. 二叉树的完全性检验-中等</font></h4><p><strong>题目：</strong></p><p>给定一个二叉树的 <code>root</code> ，确定它是否是一个完全二叉树</p><p>在一个 <strong>完全二叉树</strong> 中，除了最后一个关卡外，所有关卡都是完全被填满的，并且最后一个关卡中的所有节点都是尽可能靠左的。它可以包含 <code>1</code> 到 <code>2h</code> 节点之间的最后一级 <code>h</code> </p><p><strong>思路：</strong></p><p>广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="117-检测循环依赖-中等"><a href="#117-检测循环依赖-中等" class="headerlink" title="117. 检测循环依赖-中等"></a><font color=DarkOrange>117. 检测循环依赖-中等</font></h4><p><strong>题目：</strong></p><p>补充题</p><p><strong>思路：</strong></p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="118-二叉搜索树的第k大节点-简单"><a href="#118-二叉搜索树的第k大节点-简单" class="headerlink" title="118. 二叉搜索树的第k大节点-简单"></a><font color=DarkOrange>118. 二叉搜索树的第k大节点-简单</font></h4><p><strong>题目：</strong></p><p>给定一棵二叉搜索树，请找出其中第 k 大的节点的值</p><p><strong>思路：</strong></p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="119-盛最多水的容器-中等"><a href="#119-盛最多水的容器-中等" class="headerlink" title="119. 盛最多水的容器-中等"></a><font color=DarkOrange>119. 盛最多水的容器-中等</font></h4><p><strong>题目：</strong></p><p>给定一个长度为 <code>n</code> 的整数数组 <code>height</code> 。有 <code>n</code> 条垂线，第 <code>i</code> 条线的两个端点是 <code>(i, 0)</code> 和 <code>(i, height[i])</code> </p><p>找出其中的两条线，使得它们与 <code>x</code> 轴共同构成的容器可以容纳最多的水</p><p>返回容器可以储存的最大水量</p><p><strong>说明：</strong>你不能倾斜容器</p><p><strong>思路：</strong></p><p>双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="120-单词搜索-中等"><a href="#120-单词搜索-中等" class="headerlink" title="120. 单词搜索-中等"></a><font color=DarkOrange>120. 单词搜索-中等</font></h4><p><strong>题目：</strong></p><p>给定一个 <code>m x n</code> 二维字符网格 <code>board</code> 和一个字符串单词 <code>word</code> 。如果 <code>word</code> 存在于网格中，返回 <code>true</code> ；否则，返回 <code>false</code> </p><p>单词必须按照字母顺序，通过相邻的单元格内的字母构成，其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用</p><p><strong>思路：</strong></p><p>回溯</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="121-青蛙跳台阶问题-简单"><a href="#121-青蛙跳台阶问题-简单" class="headerlink" title="121. 青蛙跳台阶问题-简单"></a><font color=DarkOrange>121. 青蛙跳台阶问题-简单</font></h4><p><strong>题目：</strong></p><p>一只青蛙一次可以跳上1级台阶，也可以跳上2级台阶。求该青蛙跳上一个 <code>n</code> 级的台阶总共有多少种跳法</p><p>答案需要取模 1e9+7（1000000007），如计算初始结果为：1000000008，请返回 1</p><p><strong>思路：</strong></p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="122-组合总和-II-中等"><a href="#122-组合总和-II-中等" class="headerlink" title="122. 组合总和 II-中等"></a><font color=DarkOrange>122. 组合总和 II-中等</font></h4><p><strong>题目：</strong></p><p>给定一个候选人编号的集合 <code>candidates</code> 和一个目标数 <code>target</code> ，找出 <code>candidates</code> 中所有可以使数字和为 <code>target</code> 的组合</p><p><code>candidates</code> 中的每个数字在每个组合中只能使用 <strong>一次</strong> </p><p><strong>注意：</strong>解集不能包含重复的组合</p><p><strong>思路：</strong></p><p>回溯</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="123-跳跃游戏-中等"><a href="#123-跳跃游戏-中等" class="headerlink" title="123. 跳跃游戏-中等"></a><font color=DarkOrange>123. 跳跃游戏-中等</font></h4><p><strong>题目：</strong></p><p>给定一个非负整数数组 <code>nums</code> ，你最初位于数组的 <strong>第一个下标</strong> </p><p>数组中的每个元素代表你在该位置可以跳跃的最大长度</p><p>判断你是否能够到达最后一个下标</p><p><strong>思路：</strong></p><p>贪心</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="124-二叉树的后序遍历-简单"><a href="#124-二叉树的后序遍历-简单" class="headerlink" title="124. 二叉树的后序遍历-简单"></a><font color=DarkOrange>124. 二叉树的后序遍历-简单</font></h4><p><strong>题目：</strong></p><p>给你一棵二叉树的根节点 <code>root</code> ，返回其节点值的 <strong>后序遍历</strong> </p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p>方法三：Morris 遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="125-数组中的逆序对-困难"><a href="#125-数组中的逆序对-困难" class="headerlink" title="125. 数组中的逆序对-困难"></a><font color=DarkOrange>125. 数组中的逆序对-困难</font></h4><p><strong>题目：</strong></p><p>在数组中的两个数字，如果前面一个数字大于后面的数字，则这两个数字组成一个逆序对。输入一个数组，求出这个数组中的逆序对的总数</p><p><strong>思路：</strong></p><p>方法一：归并排序</p><p>方法二：离散化树状数组</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="126-螺旋矩阵-II-中等"><a href="#126-螺旋矩阵-II-中等" class="headerlink" title="126. 螺旋矩阵 II-中等"></a><font color=DarkOrange>126. 螺旋矩阵 II-中等</font></h4><p><strong>题目：</strong></p><p>给你一个正整数 <code>n</code> ，生成一个包含 <code>1</code> 到 <code>n2</code> 所有元素，且元素按顺时针顺序螺旋排列的 <code>n x n</code> 正方形矩阵 <code>matrix</code> </p><p><strong>思路：</strong></p><p>模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="127-搜索二维矩阵-中等"><a href="#127-搜索二维矩阵-中等" class="headerlink" title="127. 搜索二维矩阵-中等"></a><font color=DarkOrange>127. 搜索二维矩阵-中等</font></h4><p><strong>题目：</strong></p><p>编写一个高效的算法来判断 <code>m x n</code> 矩阵中，是否存在一个目标值。该矩阵具有如下特性：</p><ul><li>每行中的整数从左到右按升序排列</li><li>每行的第一个整数大于前一行的最后一个整数</li></ul><p><strong>思路：</strong></p><p>方法一：两次二分查找</p><p>方法二：一次二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="128-删除有序数组中的重复项-简单"><a href="#128-删除有序数组中的重复项-简单" class="headerlink" title="128. 删除有序数组中的重复项-简单"></a><font color=DarkOrange>128. 删除有序数组中的重复项-简单</font></h4><p><strong>题目：</strong></p><p>给你一个 <strong>升序排列</strong> 的数组 <code>nums</code> ，请你<strong>原地</strong> 删除重复出现的元素，使每个元素 <strong>只出现一次</strong> ，返回删除后数组的新长度。元素的 <strong>相对顺序</strong> 应该保持 <strong>一致</strong></p><p>由于在某些语言中不能改变数组的长度，所以必须将结果放在数组nums的第一部分。更规范地说，如果在删除重复项之后有 <code>k</code> 个元素，那么 <code>nums</code> 的前 <code>k</code> 个元素应该保存最终结果</p><p>将最终结果插入 <code>nums</code> 的前 <code>k</code> 个位置后返回 <code>k</code> </p><p>不要使用额外的空间，你必须在 <strong>原地修改输入数组</strong> 并在使用 O(1) 额外空间的条件下完成</p><p><strong>思路：</strong></p><p>双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="129-圆环回原点问题-中等"><a href="#129-圆环回原点问题-中等" class="headerlink" title="129. 圆环回原点问题-中等"></a><font color=DarkOrange>129. 圆环回原点问题-中等</font></h4><p><strong>题目：</strong></p><p>字节跳动高频题</p><p><strong>思路：</strong></p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="130-全排列-II-中等"><a href="#130-全排列-II-中等" class="headerlink" title="130. 全排列 II-中等"></a><font color=DarkOrange>130. 全排列 II-中等</font></h4><p><strong>题目：</strong></p><p>给定一个可包含重复数字的序列 <code>nums</code> ，<strong>按任意顺序</strong> 返回所有不重复的全排列</p><p><strong>思路：</strong></p><p>搜索回溯</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="131-零钱兑换-II-中等"><a href="#131-零钱兑换-II-中等" class="headerlink" title="131. 零钱兑换 II-中等"></a><font color=DarkOrange>131. 零钱兑换 II-中等</font></h4><p><strong>题目：</strong></p><p><strong>思路：</strong></p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="132-斐波那契数列-简单"><a href="#132-斐波那契数列-简单" class="headerlink" title="132. 斐波那契数列-简单"></a><font color=DarkOrange>132. 斐波那契数列-简单</font></h4><p><strong>题目：</strong></p><p>写一个函数，输入 <code>n</code> ，求斐波那契（Fibonacci）数列的第 <code>n</code> 项（即 <code>F(N)</code>）。斐波那契数列的定义如下：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">F(0) = 0,   F(1) = 1</span><br><span class="line">F(N) = F(N - 1) + F(N - 2), 其中 N &gt; 1.</span><br></pre></td></tr></table></figure><p>斐波那契数列由 0 和 1 开始，之后的斐波那契数就是由之前的两数相加而得出</p><p>答案需要取模 1e9+7（1000000007），如计算初始结果为：1000000008，请返回 1</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：矩阵快速幂</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="133-Pow-x-n-中等"><a href="#133-Pow-x-n-中等" class="headerlink" title="133. Pow(x, n)-中等"></a><font color=DarkOrange>133. Pow(x, n)-中等</font></h4><p><strong>题目：</strong></p><p>实现pow(x, n) ，即计算 <code>x</code> 的整数 <code>n</code> 次幂函数（即，<code>x^n</code> ）</p><p><strong>思路：</strong></p><p>方法一：快速幂 + 递归</p><p>方法二：快速幂 + 迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="134-旋转链表-中等"><a href="#134-旋转链表-中等" class="headerlink" title="134. 旋转链表-中等"></a><font color=DarkOrange>134. 旋转链表-中等</font></h4><p><strong>题目：</strong></p><p>给你一个链表的头节点 <code>head</code> ，旋转链表，将链表每个节点向右移动 <code>k</code> 个位置</p><p><strong>思路：</strong></p><p>闭合为环</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="135-删除二叉搜索树中的节点-中等"><a href="#135-删除二叉搜索树中的节点-中等" class="headerlink" title="135. 删除二叉搜索树中的节点-中等"></a><font color=DarkOrange>135. 删除二叉搜索树中的节点-中等</font></h4><p><strong>题目：</strong></p><p>给定一个二叉搜索树的根节点 <strong>root</strong> 和一个值 <strong>key</strong>，删除二叉搜索树中的 <strong>key</strong> 对应的节点，并保证二叉搜索树的性质不变。返回二叉搜索树（有可能被更新）的根节点的引用</p><p>一般来说，删除节点可分为两个步骤：</p><ol><li>首先找到需要删除的节点</li><li>如果找到了，删除它</li></ol><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="136-最小的k个数-简单"><a href="#136-最小的k个数-简单" class="headerlink" title="136. 最小的k个数-简单"></a><font color=DarkOrange>136. 最小的k个数-简单</font></h4><p><strong>题目：</strong></p><p>输入整数数组 <code>arr</code> ，找出其中最小的 <code>k</code> 个数。例如，输入4、5、1、6、2、7、3、8这8个数字，则最小的4个数字是1、2、3、4</p><p><strong>思路：</strong></p><p>方法一：排序</p><p>方法二：堆</p><p>方法三：快排思想</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="137-卖股票的最佳时机-III-困难"><a href="#137-卖股票的最佳时机-III-困难" class="headerlink" title="137. 卖股票的最佳时机 III-困难"></a><font color=DarkOrange>137. 卖股票的最佳时机 III-困难</font></h4><p><strong>题目：</strong></p><p>给定一个数组，它的第 i 个元素是一支给定的股票在第 i 天的价格</p><p>设计一个算法来计算你所能获取的最大利润。你最多可以完成 <strong>两笔</strong> 交易</p><p><strong>注意：</strong>你不能同时参与多笔交易（你必须在再次购买前出售掉之前的股票）</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="138-整数反转-简单"><a href="#138-整数反转-简单" class="headerlink" title="138. 整数反转-简单"></a><font color=DarkOrange>138. 整数反转-简单</font></h4><p><strong>题目：</strong></p><p>给你一个 32 位的有符号整数 <code>x</code> ，返回将 <code>x</code> 中的数字部分反转后的结果</p><p>如果反转后整数超过 32 位的有符号整数的范围 <code>[−2^31, 2^31 − 1]</code> ，就返回 0</p><p><strong>假设环境不允许存储 64 位整数（有符号或无符号）</strong></p><p><strong>思路：</strong></p><p>数学</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="139-连续子数组的最大和-简单"><a href="#139-连续子数组的最大和-简单" class="headerlink" title="139. 连续子数组的最大和-简单"></a><font color=DarkOrange>139. 连续子数组的最大和-简单</font></h4><p><strong>题目：</strong></p><p>输入一个整型数组，数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值</p><p>要求时间复杂度为O(n)</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：分治</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="140-整数组顺序使奇数位于偶数前面-简单"><a href="#140-整数组顺序使奇数位于偶数前面-简单" class="headerlink" title="140. 整数组顺序使奇数位于偶数前面-简单"></a><font color=DarkOrange>140. 整数组顺序使奇数位于偶数前面-简单</font></h4><p><strong>题目：</strong></p><p>输入一个整数数组，实现一个函数来调整该数组中数字的顺序，使得所有奇数在数组的前半部分，所有偶数在数组的后半部分</p><p><strong>思路：</strong></p><p>方法一：两次遍历</p><p>方法二：双指针 + 一次遍历</p><p>方法三：原地交换</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="141-二叉搜索树中第K小的元素-中等"><a href="#141-二叉搜索树中第K小的元素-中等" class="headerlink" title="141. 二叉搜索树中第K小的元素-中等"></a><font color=DarkOrange>141. 二叉搜索树中第K小的元素-中等</font></h4><p><strong>题目：</strong></p><p>给定一个二叉搜索树的根节点 <code>root</code> ，和一个整数 <code>k</code> ，请你设计一个算法查找其中第 <code>k</code> 个最小元素（从 1 开始计数）</p><p><strong>思路：</strong></p><p>方法一：中序遍历</p><p>方法二：记录子树的结点数</p><p>方法三：平衡二叉搜索树</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="142-用队列实现栈-简单"><a href="#142-用队列实现栈-简单" class="headerlink" title="142. 用队列实现栈-简单"></a><font color=DarkOrange>142. 用队列实现栈-简单</font></h4><p><strong>题目：</strong></p><p>请你仅使用两个队列实现一个后入先出（LIFO）的栈，并支持普通栈的全部四种操作（<code>push</code>、<code>top</code>、<code>pop</code> 和 <code>empty</code>）</p><p>实现 <code>MyStack</code> 类：</p><ul><li><code>void push(int x)</code> 将元素 x 压入栈顶</li><li><code>int pop()</code> 移除并返回栈顶元素</li><li><code>int top()</code> 返回栈顶元素</li><li><code>boolean empty()</code> 如果栈是空的，返回 <code>true</code> ；否则，返回 <code>false</code></li></ul><p><strong>注意：</strong></p><ul><li>你只能使用队列的基本操作 —— 也就是 <code>push to back</code>、<code>peek/pop from front</code>、<code>size</code> 和 <code>is empty</code> 这些操作</li><li>你所使用的语言也许不支持队列。 你可以使用 list （列表）或者 deque（双端队列）来模拟一个队列 , 只要是标准的队列操作即可</li></ul><p><strong>思路：</strong></p><p>方法一：两个队列</p><p>方法二：一个队列</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="143-字典序的第K小数字-困难"><a href="#143-字典序的第K小数字-困难" class="headerlink" title="143. 字典序的第K小数字-困难"></a><font color=DarkOrange>143. 字典序的第K小数字-困难</font></h4><p><strong>题目：</strong></p><p>给定整数 <code>n</code> 和 <code>k</code>，返回 <code>[1, n]</code> 中字典序第 <code>k</code> 小的数字</p><p><strong>思路：</strong></p><p>字典树思想</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="144-分发糖果-困难"><a href="#144-分发糖果-困难" class="headerlink" title="144. 分发糖果-困难"></a><font color=DarkOrange>144. 分发糖果-困难</font></h4><p><strong>题目：</strong></p><p><code>n</code> 个孩子站成一排。给你一个整数数组 <code>ratings</code> 表示每个孩子的评分</p><p>你需要按照以下要求，给这些孩子分发糖果：</p><ul><li>每个孩子至少分配到 <code>1</code> 个糖果</li><li>相邻两个孩子评分更高的孩子会获得更多的糖果</li></ul><p>请你给每个孩子分发糖果，计算并返回需要准备的 <strong>最少糖果数目</strong> </p><p><strong>思路：</strong></p><p>方法一：两次遍历</p><p>方法二：常数空间遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="145-圆圈中最后剩下的数字-简单"><a href="#145-圆圈中最后剩下的数字-简单" class="headerlink" title="145. 圆圈中最后剩下的数字-简单"></a><font color=DarkOrange>145. 圆圈中最后剩下的数字-简单</font></h4><p><strong>题目：</strong></p><p>0,1,···,n-1这n个数字排成一个圆圈，从数字0开始，每次从这个圆圈里删除第m个数字（删除后从下一个数字开始计数）。求出这个圆圈里剩下的最后一个数字</p><p>例如，0、1、2、3、4这5个数字组成一个圆圈，从数字0开始每次删除第3个数字，则删除的前4个数字依次是2、0、4、1，因此最后剩下的数字是3</p><p><strong>思路：</strong></p><p>方法一：数学 + 递归</p><p>方法二：数学 + 迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="146-颜色分类-中等"><a href="#146-颜色分类-中等" class="headerlink" title="146. 颜色分类-中等"></a><font color=DarkOrange>146. 颜色分类-中等</font></h4><p><strong>题目：</strong></p><p>给定一个包含红色、白色和蓝色、共 <code>n</code> 个元素的数组 <code>nums</code> ，<strong>原地</strong>对它们进行排序，使得相同颜色的元素相邻，并按照红色、白色、蓝色顺序排列</p><p>我们使用整数 <code>0</code>、 <code>1</code> 和 <code>2</code> 分别表示红色、白色和蓝色</p><p>必须在不使用库的sort函数的情况下解决这个问题</p><p><strong>思路：</strong></p><p>方法一：单指针</p><p>方法二：双指针</p><p>方法三：双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="147-矩阵中的最长递增路径-困难"><a href="#147-矩阵中的最长递增路径-困难" class="headerlink" title="147. 矩阵中的最长递增路径-困难"></a><font color=DarkOrange>147. 矩阵中的最长递增路径-困难</font></h4><p><strong>题目：</strong></p><p>给定一个 <code>m x n</code> 整数矩阵 <code>matrix</code> ，找出其中 <strong>最长递增路径</strong> 的长度</p><p>对于每个单元格，你可以往上，下，左，右四个方向移动。 你 <strong>不能</strong> 在 <strong>对角线</strong> 方向上移动或移动到 <strong>边界外</strong>（即不允许环绕）</p><p><strong>思路：</strong></p><p>方法一：记忆化深度优先搜索</p><p>方法二：拓扑排序</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="148-二维数组中的查找-中等"><a href="#148-二维数组中的查找-中等" class="headerlink" title="148. 二维数组中的查找-中等"></a><font color=DarkOrange>148. 二维数组中的查找-中等</font></h4><p><strong>题目：</strong></p><p>在一个 n * m 的二维数组中，每一行都按照从左到右 <strong>非递减</strong> 的顺序排序，每一列都按照从上到下 <strong>非递减</strong> 的顺序排序。请完成一个高效的函数，输入这样的一个二维数组和一个整数，判断数组中是否含有该整数</p><p><strong>思路：</strong></p><p>方法一：直接查找</p><p>方法二：二分查找</p><p>方法三：Z 字形查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="149-奇偶链表-中等"><a href="#149-奇偶链表-中等" class="headerlink" title="149. 奇偶链表-中等"></a><font color=DarkOrange>149. 奇偶链表-中等</font></h4><p><strong>题目：</strong></p><p>给定单链表的头节点 <code>head</code> ，将所有索引为奇数的节点和索引为偶数的节点分别组合在一起，然后返回重新排序的列表</p><p><strong>第一个</strong>节点的索引被认为是 <strong>奇数</strong> ， <strong>第二个</strong>节点的索引为 <strong>偶数</strong> ，以此类推</p><p>请注意，偶数组和奇数组内部的相对顺序应该与输入时保持一致</p><p>你必须在 <code>O(1)</code> 的额外空间复杂度和 <code>O(n)</code> 的时间复杂度下解决这个问题</p><p><strong>思路：</strong></p><p>分离节点后合并</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="150-解码方法-中等"><a href="#150-解码方法-中等" class="headerlink" title="150. 解码方法-中等"></a><font color=DarkOrange>150. 解码方法-中等</font></h4><p><strong>题目：</strong></p><p>一条包含字母 <code>A-Z</code> 的消息通过以下映射进行了 <strong>编码</strong> ：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;A&#x27;</span> -&gt; <span class="string">&quot;1&quot;</span></span><br><span class="line"><span class="string">&#x27;B&#x27;</span> -&gt; <span class="string">&quot;2&quot;</span></span><br><span class="line">...</span><br><span class="line"><span class="string">&#x27;Z&#x27;</span> -&gt; <span class="string">&quot;26&quot;</span></span><br></pre></td></tr></table></figure><p>要 <strong>解码</strong> 已编码的消息，所有数字必须基于上述映射的方法，反向映射回字母（可能有多种方法）。例如，<code>&quot;11106&quot;</code> 可以映射为：</p><ul><li><code>&quot;AAJF&quot;</code> ，将消息分组为 <code>(1 1 10 6)</code></li><li><code>&quot;KJF&quot;</code> ，将消息分组为 <code>(11 10 6)</code></li></ul><p>注意，消息不能分组为 <code>(1 11 06)</code> ，因为 <code>&quot;06&quot;</code> 不能映射为 <code>&quot;F&quot;</code> ，这是由于 <code>&quot;6&quot;</code> 和 <code>&quot;06&quot;</code> 在映射中并不等价</p><p>给你一个只含数字的 <strong>非空</strong> 字符串 <code>s</code> ，请计算并返回 <strong>解码</strong> 方法的 <strong>总数</strong> </p><p>题目数据保证答案肯定是一个 <strong>32 位</strong> 的整数</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="151-另一棵树的子树-简单"><a href="#151-另一棵树的子树-简单" class="headerlink" title="151. 另一棵树的子树-简单"></a><font color=DarkOrange>151. 另一棵树的子树-简单</font></h4><p><strong>题目：</strong></p><p>给你两棵二叉树 <code>root</code> 和 <code>subRoot</code> 。检验 <code>root</code> 中是否包含和 <code>subRoot</code> 具有相同结构和节点值的子树。如果存在，返回 <code>true</code> ；否则，返回 <code>false</code> </p><p>二叉树 <code>tree</code> 的一棵子树包括 <code>tree</code> 的某个节点和这个节点的所有后代节点。<code>tree</code> 也可以看做它自身的一棵子树</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索暴力匹配</p><p>方法二：深度优先搜索序列上做串匹配</p><p>方法三：树哈希</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="152-打乱数组-中等"><a href="#152-打乱数组-中等" class="headerlink" title="152. 打乱数组-中等"></a><font color=DarkOrange>152. 打乱数组-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code> ，设计算法来打乱一个没有重复元素的数组。打乱后，数组的所有排列应该是 <strong>等可能</strong> 的</p><p>实现 <code>Solution</code> class：</p><ul><li><code>Solution(int[] nums)</code> 使用整数数组 <code>nums</code> 初始化对象</li><li><code>int[] reset()</code> 重设数组到它的初始状态并返回</li><li><code>int[] shuffle()</code> 返回数组随机打乱后的结果</li></ul><p><strong>思路：</strong></p><p>方法一：暴力</p><p>方法二：Fisher-Yates 洗牌算法</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="153-验证回文串-简单"><a href="#153-验证回文串-简单" class="headerlink" title="153. 验证回文串-简单"></a><font color=DarkOrange>153. 验证回文串-简单</font></h4><p><strong>题目：</strong></p><p>如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后，短语正着读和反着读都一样。则可以认为该短语是一个 <strong>回文串</strong> </p><p>字母和数字都属于字母数字字符</p><p>给你一个字符串 <code>s</code>，如果它是 <strong>回文串</strong> ，返回 <code>true</code> ；否则，返回 <code>false</code> </p><p><strong>思路：</strong></p><p>方法一：筛选 + 判断</p><p>方法二：在原字符串上直接判断</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="154-回文数-简单"><a href="#154-回文数-简单" class="headerlink" title="154. 回文数-简单"></a><font color=DarkOrange>154. 回文数-简单</font></h4><p><strong>题目：</strong></p><p>给你一个整数 <code>x</code> ，如果 <code>x</code> 是一个回文整数，返回 <code>true</code> ；否则，返回 <code>false</code> </p><p>回文数是指正序（从左向右）和倒序（从右向左）读都是一样的整数</p><ul><li>例如，<code>121</code> 是回文，而 <code>123</code> 不是</li></ul><p><strong>思路：</strong></p><p>反转一半数字</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="154-轮转数组-中等"><a href="#154-轮转数组-中等" class="headerlink" title="154. 轮转数组-中等"></a><font color=DarkOrange>154. 轮转数组-中等</font></h4><p><strong>题目：</strong></p><p>给你一个数组，将数组中的元素向右轮转 <code>k</code> 个位置，其中 <code>k</code> 是非负数</p><p><strong>思路：</strong></p><p>方法一：使用额外的数组</p><p>方法二：环状替换</p><p>方法三：数组翻转</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="155-跳跃游戏-II-中等"><a href="#155-跳跃游戏-II-中等" class="headerlink" title="155. 跳跃游戏 II-中等"></a><font color=DarkOrange>155. 跳跃游戏 II-中等</font></h4><p><strong>题目：</strong></p><p>给你一个非负整数数组 <code>nums</code> ，你最初位于数组的第一个位置</p><p>数组中的每个元素代表你在该位置可以跳跃的最大长度</p><p>你的目标是使用最少的跳跃次数到达数组的最后一个位置</p><p>假设你总是可以到达数组的最后一个位置</p><p><strong>思路：</strong></p><p>方法一：反向查找出发位置</p><p>方法二：正向查找可到达的最大位置</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="157-两数相加-II-中等"><a href="#157-两数相加-II-中等" class="headerlink" title="157. 两数相加 II-中等"></a><font color=DarkOrange>157. 两数相加 II-中等</font></h4><p><strong>题目：</strong></p><p>给你两个 <strong>非空</strong> 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表</p><p>你可以假设除了数字 0 之外，这两个数字都不会以零开头</p><p><strong>思路：</strong></p><p>栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="158-二叉树的镜像-简单"><a href="#158-二叉树的镜像-简单" class="headerlink" title="158. 二叉树的镜像-简单"></a><font color=DarkOrange>158. 二叉树的镜像-简单</font></h4><p><strong>题目：</strong></p><div align="center"><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h88ink6q3sj30hk0fi752.jpg" alt="image.png" style="zoom:67%;" /></div><p><strong>思路：</strong></p><p>递归</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="159-寻找重复数-中等"><a href="#159-寻找重复数-中等" class="headerlink" title="159. 寻找重复数-中等"></a><font color=DarkOrange>159. 寻找重复数-中等</font></h4><p><strong>题目：</strong></p><p>给定一个包含 <code>n + 1</code> 个整数的数组 <code>nums</code> ，其数字都在 <code>[1, n]</code> 范围内（包括 <code>1</code> 和 <code>n</code>），可知至少存在一个重复的整数</p><p>假设 <code>nums</code> 只有 <strong>一个重复的整数</strong> ，返回 <strong>这个重复的数</strong> </p><p>你设计的解决方案必须 <strong>不修改</strong> 数组 <code>nums</code> 且只用常量级 <code>O(1)</code> 的额外空间</p><p><strong>思路：</strong></p><p>方法一：二分查找</p><p>方法二：二进制</p><p>方法三：快慢指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="160-实现-Trie-前缀树-中等"><a href="#160-实现-Trie-前缀树-中等" class="headerlink" title="160. 实现 Trie (前缀树)-中等"></a><font color=DarkOrange>160. 实现 Trie (前缀树)-中等</font></h4><p><strong>题目：</strong></p><p><strong>Trie</strong>（发音类似 “try”）或者说 <strong>前缀树</strong> 是一种树形数据结构，用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景，例如自动补完和拼写检查</p><p>请你实现 Trie 类：</p><ul><li><code>Trie()</code> 初始化前缀树对象</li><li><code>void insert(String word)</code> 向前缀树中插入字符串 <code>word</code> </li><li><code>boolean search(String word)</code> 如果字符串 <code>word</code> 在前缀树中，返回 <code>true</code>（即，在检索之前已经插入）；否则，返回 <code>false</code> </li><li><code>boolean startsWith(String prefix)</code> 如果之前已经插入的字符串 <code>word</code> 的前缀之一为 <code>prefix</code> ，返回 <code>true</code> ；否则，返回 <code>false</code></li></ul><p><strong>思路：</strong></p><p>字典树</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="161-数据流的中位数-困难"><a href="#161-数据流的中位数-困难" class="headerlink" title="161. 数据流的中位数-困难"></a><font color=DarkOrange>161. 数据流的中位数-困难</font></h4><p><strong>题目：</strong></p><p>中位数是有序列表中间的数。如果列表长度是偶数，中位数则是中间两个数的平均值</p><p>例如，</p><p>[2,3,4] 的中位数是 3</p><p>[2,3] 的中位数是 (2 + 3) &#x2F; 2 &#x3D; 2.5</p><p>设计一个支持以下两种操作的数据结构：</p><ul><li>void addNum(int num) - 从数据流中添加一个整数到数据结构中</li><li>double findMedian() - 返回目前所有元素的中位数</li></ul><p><strong>思路：</strong></p><p>方法一：优先队列</p><p>方法二：有序集合 + 双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="162-二叉树展开为链表-中等"><a href="#162-二叉树展开为链表-中等" class="headerlink" title="162. 二叉树展开为链表-中等"></a><font color=DarkOrange>162. 二叉树展开为链表-中等</font></h4><p><strong>题目：</strong></p><p>给你二叉树的根结点 <code>root</code> ，请你将它展开为一个单链表：</p><ul><li>展开后的单链表应该同样使用 <code>TreeNode</code> ，其中 <code>right</code> 子指针指向链表中下一个结点，而左子指针始终为 <code>null</code> </li><li>展开后的单链表应该与二叉树 <strong>先序遍历</strong> 顺序相同</li></ul><p><strong>思路：</strong></p><p>方法一：前序遍历</p><p>方法二：前序遍历和展开同步进行</p><p>方法三：寻找前驱节点</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="163-接近的三数之和-中等"><a href="#163-接近的三数之和-中等" class="headerlink" title="163. 接近的三数之和-中等"></a><font color=DarkOrange>163. 接近的三数之和-中等</font></h4><p><strong>题目：</strong></p><p>给你一个长度为 <code>n</code> 的整数数组 <code>nums</code> 和 一个目标值 <code>target</code>。请你从 <code>nums</code> 中选出三个整数，使它们的和与 <code>target</code> 最接近</p><p>返回这三个数的和</p><p>假定每组输入只存在恰好一个解</p><p><strong>思路：</strong></p><p>排序 + 双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="164-打家劫舍-II-中等"><a href="#164-打家劫舍-II-中等" class="headerlink" title="164. 打家劫舍 II-中等"></a><font color=DarkOrange>164. 打家劫舍 II-中等</font></h4><p><strong>题目：</strong></p><p>你是一个专业的小偷，计划偷窃沿街的房屋，每间房内都藏有一定的现金。这个地方所有的房屋都 <strong>围成一圈</strong> ，这意味着第一个房屋和最后一个房屋是紧挨着的。同时，相邻的房屋装有相互连通的防盗系统，<strong>如果两间相邻的房屋在同一晚上被小偷闯入，系统会自动报警</strong> </p><p>给定一个代表每个房屋存放金额的非负整数数组，计算你 <strong>在不触动警报装置的情况下</strong> ，今晚能够偷窃到的最高金额</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="165-三角形最小路径和-中等"><a href="#165-三角形最小路径和-中等" class="headerlink" title="165. 三角形最小路径和-中等"></a><font color=DarkOrange>165. 三角形最小路径和-中等</font></h4><p><strong>题目：</strong></p><p>给定一个三角形 <code>triangle</code> ，找出自顶向下的最小路径和</p><p>每一步只能移动到下一行中相邻的结点上。<strong>相邻的结点</strong> 在这里指的是 <strong>下标</strong> 与 <strong>上一层结点下标</strong> 相同或者等于 <strong>上一层结点下标 + 1</strong> 的两个结点。也就是说，如果正位于当前行的下标 <code>i</code> ，那么下一步可以移动到下一行的下标 <code>i</code> 或 <code>i + 1</code> </p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：动态规划 + 空间优化</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="166-顺时针打印矩阵-简单"><a href="#166-顺时针打印矩阵-简单" class="headerlink" title="166. 顺时针打印矩阵-简单"></a><font color=DarkOrange>166. 顺时针打印矩阵-简单</font></h4><p><strong>题目：</strong></p><p>输入一个矩阵，按照从外向里以顺时针的顺序依次打印出每一个数字</p><p><strong>思路：</strong></p><p>方法一：模拟</p><p>方法二：按层模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="167-正则表达式匹配-困难"><a href="#167-正则表达式匹配-困难" class="headerlink" title="167. 正则表达式匹配-困难"></a><font color=DarkOrange>167. 正则表达式匹配-困难</font></h4><p><strong>题目：</strong></p><p>给你一个字符串 <code>s</code> 和一个字符规律 <code>p</code>，请你来实现一个支持 <code>&#39;.&#39;</code> 和 <code>&#39;*&#39;</code> 的正则表达式匹配</p><ul><li><code>&#39;.&#39;</code> 匹配任意单个字符</li><li><code>&#39;*&#39;</code> 匹配零个或多个前面的那一个元素</li></ul><p>所谓匹配，是要涵盖 <strong>整个</strong> 字符串 <code>s</code>的，而不是部分字符串</p><p><strong>思路：</strong></p><p>动态规划</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="168-从中序与后序遍历序列构造二叉树-中等"><a href="#168-从中序与后序遍历序列构造二叉树-中等" class="headerlink" title="168. 从中序与后序遍历序列构造二叉树-中等"></a><font color=DarkOrange>168. 从中序与后序遍历序列构造二叉树-中等</font></h4><p><strong>题目：</strong></p><p>给定两个整数数组 <code>inorder</code> 和 <code>postorder</code> ，其中 <code>inorder</code> 是二叉树的中序遍历， <code>postorder</code> 是同一棵树的后序遍历，请你构造并返回这颗二叉树</p><p><strong>思路：</strong></p><p>方法一：递归</p><p>方法二：迭代</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="169-第-N-位数字-中等"><a href="#169-第-N-位数字-中等" class="headerlink" title="169. 第 N 位数字-中等"></a><font color=DarkOrange>169. 第 N 位数字-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数 <code>n</code> ，请你在无限的整数序列 <code>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]</code> 中找出并返回第 <code>n</code> 位上的数字</p><p><strong>思路：</strong></p><p>方法一：二分查找</p><p>方法二：直接计算</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="170-树的子结构-中等"><a href="#170-树的子结构-中等" class="headerlink" title="170. 树的子结构-中等"></a><font color=DarkOrange>170. 树的子结构-中等</font></h4><p><strong>题目：</strong></p><div align="center"><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h88j43kz1xj30p60gw40b.jpg" alt="image.png" style="zoom:67%;" /></div><p><strong>思路：</strong></p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="171-链表求和-中等"><a href="#171-链表求和-中等" class="headerlink" title="171. 链表求和-中等"></a><font color=DarkOrange>171. 链表求和-中等</font></h4><p><strong>题目：</strong></p><p>给定两个用链表表示的整数，每个节点包含一个数位</p><p>这些数位是反向存放的，也就是个位排在链表首部</p><p>编写函数对这两个整数求和，并用链表形式返回结果</p><p><strong>思路：</strong></p><p>模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="172-有效的括号字符串-中等"><a href="#172-有效的括号字符串-中等" class="headerlink" title="172. 有效的括号字符串-中等"></a><font color=DarkOrange>172. 有效的括号字符串-中等</font></h4><p><strong>题目：</strong></p><p>给定一个只包含三种字符的字符串：<code>（ </code>，<code>）</code> 和 <code>*</code>，写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则：</p><ol><li>任何左括号 <code>(</code> 必须有相应的右括号 <code>)</code></li><li>任何右括号 <code>)</code> 必须有相应的左括号 <code>(</code> </li><li>左括号 <code>(</code> 必须在对应的右括号之前 <code>)</code></li><li><code>*</code> 可以被视为单个右括号 <code>)</code> ，或单个左括号 <code>(</code> ，或一个空字符串</li><li>一个空字符串也被视为有效字符串</li></ol><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：栈</p><p>方法三：贪心</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="173-两个链表的第一个公共节点-简单"><a href="#173-两个链表的第一个公共节点-简单" class="headerlink" title="173. 两个链表的第一个公共节点-简单"></a><font color=DarkOrange>173. 两个链表的第一个公共节点-简单</font></h4><p><strong>题目：</strong></p><div align="center"><img src="http://tva1.sinaimg.cn/large/0079DIvogy1h88j86dqzej30lk0c6myc.jpg" alt="image.png" style="zoom:67%;" /></div><p><strong>思路：</strong></p><p>方法一：哈希集合</p><p>方法二：双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="174-前-K-个高频元素-中等"><a href="#174-前-K-个高频元素-中等" class="headerlink" title="174. 前 K 个高频元素-中等"></a><font color=DarkOrange>174. 前 K 个高频元素-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数数组 <code>nums</code> 和一个整数 <code>k</code> ，请你返回其中出现频率前 <code>k</code> 高的元素。你可以按 <strong>任意顺序</strong> 返回答案</p><p><strong>思路：</strong></p><p>方法一：堆</p><p>方法二：基于快速排序</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="175-不同的二叉搜索树-中等"><a href="#175-不同的二叉搜索树-中等" class="headerlink" title="175. 不同的二叉搜索树-中等"></a><font color=DarkOrange>175. 不同的二叉搜索树-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数 <code>n</code> ，求恰由 <code>n</code> 个节点组成且节点值从 <code>1</code> 到 <code>n</code> 互不相同的 <strong>二叉搜索树</strong> 有多少种？返回满足题意的二叉搜索树的种数</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：数学</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="176-两个数组的交集-简单"><a href="#176-两个数组的交集-简单" class="headerlink" title="176. 两个数组的交集-简单"></a><font color=DarkOrange>176. 两个数组的交集-简单</font></h4><p><strong>题目：</strong></p><p>给定两个数组 <code>nums1</code> 和 <code>nums2</code> ，返回它们的交集 。输出结果中的每个元素一定是 <strong>唯一</strong> 的。我们可以 <strong>不考虑输出结果的顺序</strong> </p><p><strong>思路：</strong></p><p>方法一：两个集合</p><p>方法二：排序 + 双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="177-36进制加法-中等"><a href="#177-36进制加法-中等" class="headerlink" title="177. 36进制加法-中等"></a><font color=DarkOrange>177. 36进制加法-中等</font></h4><p><strong>题目：</strong></p><p>字节高频题</p><p><strong>思路：</strong><br><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="178-数组中出现次数超过一半的数字-简单"><a href="#178-数组中出现次数超过一半的数字-简单" class="headerlink" title="178. 数组中出现次数超过一半的数字-简单"></a><font color=DarkOrange>178. 数组中出现次数超过一半的数字-简单</font></h4><p><strong>题目：</strong></p><p>数组中有一个数字出现的次数超过数组长度的一半，请找出这个数字</p><p>你可以假设数组是非空的，并且给定的数组总是存在多数元素</p><p><strong>思路：</strong></p><p>方法一：哈希表</p><p>方法二：排序</p><p>方法三：随机化</p><p>方法四：分治</p><p>方法五：Boyer-Moore 投票算法</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="179-Excel表列名称-简单"><a href="#179-Excel表列名称-简单" class="headerlink" title="179. Excel表列名称-简单"></a><font color=DarkOrange>179. Excel表列名称-简单</font></h4><p><strong>题目：</strong></p><p>给你一个整数 <code>columnNumber</code> ，返回它在 Excel 表中相对应的列名称</p><p>例如：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">A -&gt; 1</span><br><span class="line">B -&gt; 2</span><br><span class="line">C -&gt; 3</span><br><span class="line">...</span><br><span class="line">Z -&gt; 26</span><br><span class="line">AA -&gt; 27</span><br><span class="line">AB -&gt; 28 </span><br><span class="line">...</span><br></pre></td></tr></table></figure><p><strong>思路：</strong></p><p>数学</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="180-扑克牌中的顺子-简单"><a href="#180-扑克牌中的顺子-简单" class="headerlink" title="180. 扑克牌中的顺子-简单"></a><font color=DarkOrange>180. 扑克牌中的顺子-简单</font></h4><p><strong>题目：</strong></p><p>从<strong>若干副扑克牌</strong>中随机抽 <code>5</code> 张牌，判断是不是一个顺子，即这5张牌是不是连续的。2～10为数字本身，A为1，J为11，Q为12，K为13，而大、小王为 0 ，可以看成任意数字。A 不能视为 14</p><p><strong>思路：</strong></p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="181-鸡蛋掉落-困难"><a href="#181-鸡蛋掉落-困难" class="headerlink" title="181. 鸡蛋掉落-困难"></a><font color=DarkOrange>181. 鸡蛋掉落-困难</font></h4><p><strong>题目：</strong></p><p>给你 <code>k</code> 枚相同的鸡蛋，并可以使用一栋从第 <code>1</code> 层到第 <code>n</code> 层共有 <code>n</code> 层楼的建筑</p><p>已知存在楼层 <code>f</code> ，满足 <code>0 &lt;= f &lt;= n</code> ，任何从 <strong>高于</strong> <code>f</code> 的楼层落下的鸡蛋都会碎，从 <code>f</code> 楼层或比它低的楼层落下的鸡蛋都不会破</p><p>每次操作，你可以取一枚没有碎的鸡蛋并把它从任一楼层 <code>x</code> 扔下（满足 <code>1 &lt;= x &lt;= n</code>）。如果鸡蛋碎了，你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎，则可以在之后的操作中 <strong>重复使用</strong> 这枚鸡蛋</p><p>请你计算并返回要确定 <code>f</code> <strong>确切的值</strong> 的 <strong>最小操作次数</strong> 是多少？</p><p><strong>思路：</strong></p><p>方法一：动态规划 + 二分查找</p><p>方法二：决策单调性</p><p>方法三：数学法</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="182-最长递增子序列的个数-中等"><a href="#182-最长递增子序列的个数-中等" class="headerlink" title="182. 最长递增子序列的个数-中等"></a><font color=DarkOrange>182. 最长递增子序列的个数-中等</font></h4><p><strong>题目：</strong></p><p>给定一个未排序的整数数组 <code>nums</code> ， 返回最长递增子序列的个数</p><p><strong>注意</strong> 这个数列必须是 <strong>严格</strong> 递增的</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：贪心 + 前缀和 + 二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="183-简化路径-中等"><a href="#183-简化路径-中等" class="headerlink" title="183. 简化路径-中等"></a><font color=DarkOrange>183. 简化路径-中等</font></h4><p><strong>题目：</strong></p><p>给你一个字符串 <code>path</code> ，表示指向某一文件或目录的 Unix 风格 <strong>绝对路径</strong> （以 <code>&#39;/&#39;</code> 开头），请你将其转化为更加简洁的规范路径</p><p>在 Unix 风格的文件系统中，一个点（<code>.</code>）表示当前目录本身；此外，两个点 （<code>..</code>） 表示将目录切换到上一级（指向父目录）；两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠（即，<code>&#39;//&#39;</code>）都被视为单个斜杠 <code>&#39;/&#39;</code> 。 对于此问题，任何其他格式的点（例如，<code>&#39;...&#39;</code>）均被视为文件&#x2F;目录名称</p><p>请注意，返回的 <strong>规范路径</strong> 必须遵循下述格式：</p><ul><li>始终以斜杠 <code>&#39;/&#39;</code> 开头</li><li>两个目录名之间必须只有一个斜杠 <code>&#39;/&#39;</code> </li><li>最后一个目录名（如果存在）<strong>不能</strong> 以 <code>&#39;/&#39;</code> 结尾</li><li>此外，路径仅包含从根目录到目标文件或目录的路径上的目录（即，不含 <code>&#39;.&#39;</code> 或 <code>&#39;..&#39;</code>）</li></ul><p>返回简化后得到的 <strong>规范路径</strong> </p><p><strong>思路：</strong></p><p>栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="184-数组中重复的数据-中等"><a href="#184-数组中重复的数据-中等" class="headerlink" title="184. 数组中重复的数据-中等"></a><font color=DarkOrange>184. 数组中重复的数据-中等</font></h4><p><strong>题目：</strong></p><p>给你一个长度为 <code>n</code> 的整数数组 <code>nums</code> ，其中 <code>nums</code> 的所有整数都在范围 <code>[1, n]</code> 内，且每个整数出现 <strong>一次</strong> 或 <strong>两次</strong> 。请你找出所有出现 <strong>两次</strong> 的整数，并以数组形式返回</p><p>你必须设计并实现一个时间复杂度为 <code>O(n)</code> 且仅使用常量额外空间的算法解决此问题</p><p><strong>思路：</strong></p><p>方法一：将元素交换到对应的位置</p><p>方法二：使用正负号作为标记</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="185-斐波那契数-简单"><a href="#185-斐波那契数-简单" class="headerlink" title="185. 斐波那契数-简单"></a><font color=DarkOrange>185. 斐波那契数-简单</font></h4><p><strong>题目：</strong></p><p><strong>斐波那契数</strong> （通常用 <code>F(n)</code> 表示）形成的序列称为 <strong>斐波那契数列</strong> 。该数列由 <code>0</code> 和 <code>1</code> 开始，后面的每一项数字都是前面两项数字的和。也就是：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">F(0) = 0，F(1) = 1</span><br><span class="line">F(n) = F(n - 1) + F(n - 2)，其中 n &gt; 1</span><br></pre></td></tr></table></figure><p>给定 <code>n</code> ，请计算 <code>F(n)</code> </p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：矩阵快速幂</p><p>方法三：通项公式</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="186-删除字符串中的所有相邻重复项-简单"><a href="#186-删除字符串中的所有相邻重复项-简单" class="headerlink" title="186. 删除字符串中的所有相邻重复项-简单"></a><font color=DarkOrange>186. 删除字符串中的所有相邻重复项-简单</font></h4><p><strong>题目：</strong></p><p>给出由小写字母组成的字符串 <code>S</code>，<strong>重复项删除操作</strong>会选择两个相邻且相同的字母，并删除它们</p><p>在 S 上反复执行重复项删除操作，直到无法继续删除</p><p>在完成所有重复项删除操作后返回最终的字符串。答案保证唯一</p><p><strong>思路：</strong></p><p>栈</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="187-加油站-中等"><a href="#187-加油站-中等" class="headerlink" title="187. 加油站-中等"></a><font color=DarkOrange>187. 加油站-中等</font></h4><p><strong>题目：</strong></p><p>在一条环路上有 <code>n</code> 个加油站，其中第 <code>i</code> 个加油站有汽油 <code>gas[i]</code> 升</p><p>你有一辆油箱容量无限的的汽车，从第 <code>i</code> 个加油站开往第 <code>i+1</code> 个加油站需要消耗汽油 <code>cost[i]</code> 升。你从其中的一个加油站出发，开始时油箱为空</p><p>给定两个整数数组 <code>gas</code> 和 <code>cost</code> ，如果你可以绕环路行驶一周，则返回出发时加油站的编号，否则返回 <code>-1</code> 。如果存在解，则 <strong>保证</strong> 它是 <strong>唯一</strong> 的</p><p><strong>思路：</strong></p><p>一次遍历</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="188-有效三角形的个数-中等"><a href="#188-有效三角形的个数-中等" class="headerlink" title="188. 有效三角形的个数-中等"></a><font color=DarkOrange>188. 有效三角形的个数-中等</font></h4><p><strong>题目：</strong></p><p>给定一个包含非负整数的数组 <code>nums</code> ，返回其中可以组成三角形三条边的三元组个数</p><p><strong>思路：</strong></p><p>方法一：排序 + 二分查找</p><p>方法二：排序 + 双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="189-最大连续1的个数-III-中等"><a href="#189-最大连续1的个数-III-中等" class="headerlink" title="189. 最大连续1的个数 III-中等"></a><font color=DarkOrange>189. 最大连续1的个数 III-中等</font></h4><p><strong>题目：</strong></p><p>给定一个二进制数组 <code>nums</code> 和一个整数 <code>k</code>，如果可以翻转最多 <code>k</code> 个 <code>0</code> ，则返回数组中连续 <code>1</code> 的最大个数 </p><p><strong>思路：</strong></p><p>方法一：二分查找</p><p>方法二：滑动窗口</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="190-二叉树中和为某一值的路径-中等"><a href="#190-二叉树中和为某一值的路径-中等" class="headerlink" title="190. 二叉树中和为某一值的路径-中等"></a><font color=DarkOrange>190. 二叉树中和为某一值的路径-中等</font></h4><p><strong>题目：</strong></p><p>给你二叉树的根节点 <code>root</code> 和一个整数目标和 <code>targetSum</code> ，找出所有 <strong>从根节点到叶子节点</strong> 路径总和等于给定目标和的路径</p><p><strong>叶子节点</strong> 是指没有子节点的节点</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="191-在排序数组中查找数字-I-简单"><a href="#191-在排序数组中查找数字-I-简单" class="headerlink" title="191. 在排序数组中查找数字 I-简单"></a><font color=DarkOrange>191. 在排序数组中查找数字 I-简单</font></h4><p><strong>题目：</strong></p><p>统计一个数字在排序数组中出现的次数</p><p><strong>思路：</strong></p><p>二分查找</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="192-分隔链表-中等"><a href="#192-分隔链表-中等" class="headerlink" title="192. 分隔链表-中等"></a><font color=DarkOrange>192. 分隔链表-中等</font></h4><p><strong>题目：</strong></p><p>给你一个链表的头节点 <code>head</code> 和一个特定值 <code>x</code> ，请你对链表进行分隔，使得所有 <strong>小于</strong> <code>x</code> 的节点都出现在 <strong>大于或等于</strong> <code>x</code> 的节点之前</p><p>你应当 <strong>保留</strong> 两个分区中每个节点的初始相对位置</p><p><strong>思路：</strong></p><p>模拟</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="193-24-点游戏-困难"><a href="#193-24-点游戏-困难" class="headerlink" title="193. 24 点游戏-困难"></a><font color=DarkOrange>193. 24 点游戏-困难</font></h4><p><strong>题目：</strong></p><p>给定一个长度为4的整数数组 <code>cards</code> 。你有 <code>4</code> 张卡片，每张卡片上都包含一个范围在 <code>[1,9]</code> 的数字。您应该使用运算符 <code>[&#39;+&#39;, &#39;-&#39;, &#39;*&#39;, &#39;/&#39;]</code> 和括号 <code>&#39;(&#39;</code> 和 <code>&#39;)&#39;</code> 将这些卡片上的数字排列成数学表达式，以获得值24</p><p>你须遵守以下规则：</p><ul><li>除法运算符 <code>&#39;/&#39;</code> 表示实数除法，而不是整数除法<ul><li>例如， <code>4 /(1 - 2 / 3)= 4 /(1 / 3)= 12</code></li></ul></li><li>每个运算都在两个数字之间。特别是，不能使用 <code>“-”</code> 作为一元运算符<ul><li>例如，如果 <code>cards =[1,1,1,1]</code> ，则表达式 <code>“-1 -1 -1 -1”</code> 是 <strong>不允许</strong> 的</li></ul></li><li>你不能把数字串在一起<ul><li>例如，如果 <code>cards =[1,2,1,2]</code> ，则表达式 <code>“12 + 12”</code> 无效</li></ul></li></ul><p>如果可以得到这样的表达式，其计算结果为 <code>24</code> ，则返回 <code>true </code>，否则返回 <code>false</code> </p><p><strong>思路：</strong></p><p>回溯</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="194-二叉树的最小深度-简单"><a href="#194-二叉树的最小深度-简单" class="headerlink" title="194. 二叉树的最小深度-简单"></a><font color=DarkOrange>194. 二叉树的最小深度-简单</font></h4><p><strong>题目：</strong></p><p>给定一个二叉树，找出其最小深度</p><p>最小深度是从根节点到最近叶子节点的最短路径上的节点数量</p><p><strong>说明：</strong>叶子节点是指没有子节点的节点</p><p><strong>思路：</strong></p><p>方法一：深度优先搜索</p><p>方法二：广度优先搜索</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="195-下一个更大元素-III-中等"><a href="#195-下一个更大元素-III-中等" class="headerlink" title="195. 下一个更大元素 III-中等"></a><font color=DarkOrange>195. 下一个更大元素 III-中等</font></h4><p><strong>题目：</strong></p><p>给你一个正整数 <code>n</code> ，请你找出符合条件的最小整数，其由重新排列 <code>n</code> 中存在的每位数字组成，并且其值大于 <code>n</code> 。如果不存在这样的正整数，则返回 <code>-1</code> </p><p><strong>注意</strong> ，返回的整数应当是一个 <strong>32 位整数</strong> ，如果存在满足题意的答案，但不是 <strong>32 位整数</strong> ，同样返回 <code>-1</code> </p><p><strong>思路：</strong></p><p>方法一：下一个排列</p><p>方法二：数学</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="196-通配符匹配-困难"><a href="#196-通配符匹配-困难" class="headerlink" title="196. 通配符匹配-困难"></a><font color=DarkOrange>196. 通配符匹配-困难</font></h4><p><strong>题目：</strong></p><p>给定一个字符串 (<code>s</code>) 和一个字符模式 (<code>p</code>) ，实现一个支持 <code>&#39;?&#39;</code> 和 <code>&#39;*&#39;</code> 的通配符匹配</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;?&#x27;</span> 可以匹配任何单个字符。</span><br><span class="line"><span class="string">&#x27;*&#x27;</span> 可以匹配任意字符串（包括空字符串）。</span><br></pre></td></tr></table></figure><p>两个字符串<strong>完全匹配</strong>才算匹配成功</p><p><strong>说明:</strong></p><ul><li><code>s</code> 可能为空，且只包含从 <code>a-z</code> 的小写字母</li><li><code>p</code> 可能为空，且只包含从 <code>a-z</code> 的小写字母，以及字符 <code>?</code> 和 <code>*</code></li></ul><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：贪心算法</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="197-完全平方数-中等"><a href="#197-完全平方数-中等" class="headerlink" title="197. 完全平方数-中等"></a><font color=DarkOrange>197. 完全平方数-中等</font></h4><p><strong>题目：</strong></p><p>给你一个整数 <code>n</code> ，返回和为 <code>n</code> 的完全平方数的最少数量</p><p><strong>完全平方数</strong> 是一个整数，其值等于另一个整数的平方；换句话说，其值等于一个整数自乘的积。例如，<code>1</code>、<code>4</code>、<code>9</code> 和 <code>16</code> 都是完全平方数，而 <code>3</code> 和 <code>11</code> 不是</p><p><strong>思路：</strong></p><p>方法一：动态规划</p><p>方法二：数学</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="198-解数独-困难"><a href="#198-解数独-困难" class="headerlink" title="198. 解数独-困难"></a><font color=DarkOrange>198. 解数独-困难</font></h4><p><strong>题目：</strong></p><p>编写一个程序，通过填充空格来解决数独问题</p><p>数独的解法需 <strong>遵循如下规则</strong>：</p><ol><li>数字 <code>1-9</code> 在每一行只能出现一次</li><li>数字 <code>1-9</code> 在每一列只能出现一次</li><li>数字 <code>1-9</code> 在每一个以粗实线分隔的 <code>3x3</code> 宫内只能出现一次</li></ol><p>数独部分空格内已填入了数字，空白格用 <code>&#39;.&#39;</code> 表示</p><p><strong>思路：</strong></p><p>方法一：回溯</p><p>方法二：位运算优化</p><p>方法三：枚举优化</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h4 id="199-阿拉伯数字转中文数字-中等"><a href="#199-阿拉伯数字转中文数字-中等" class="headerlink" title="199. 阿拉伯数字转中文数字-中等"></a><font color=DarkOrange>199. 阿拉伯数字转中文数字-中等</font></h4><p><strong>题目：</strong><br><strong>思路：</strong><br><strong>代码：</strong></p><h4 id="200-反转字符串-简单"><a href="#200-反转字符串-简单" class="headerlink" title="200. 反转字符串-简单"></a><font color=DarkOrange>200. 反转字符串-简单</font></h4><p><strong>题目：</strong></p><p>编写一个函数，其作用是将输入的字符串反转过来。输入字符串以字符数组 <code>s</code> 的形式给出</p><p>不要给另外的数组分配额外的空间，你必须<strong>原地修改输入数组</strong>、使用 O(1) 的额外空间解决这一问题</p><p><strong>思路：</strong></p><p>双指针</p><p><strong>代码：</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><hr>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;面试LeetCode算法题整理，按照出现的频率依次递减排序，题目类型包含：简单、中等、困难&lt;/p&gt;
&lt;p&gt;CodeTop地址：&lt;a href=&quot;https://codetop.cc/home&quot;&gt;点击跳转&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;备注：&lt;/strong&gt;出现的频</summary>
      
    
    
    
    <category term="面试" scheme="https://huajun-chen.github.io/categories/%E9%9D%A2%E8%AF%95/"/>
    
    
    <category term="算法" scheme="https://huajun-chen.github.io/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>云原生15-微服务项目的开发和部署案例</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F15-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%BC%80%E5%8F%91%E5%92%8C%E9%83%A8%E7%BD%B2%E6%A1%88%E4%BE%8B/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F15-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%BC%80%E5%8F%91%E5%92%8C%E9%83%A8%E7%BD%B2%E6%A1%88%E4%BE%8B/</id>
    <published>2022-11-08T15:30:00.000Z</published>
    <updated>2022-11-20T15:18:00.982Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生14-基于Kubernetes和Istio的安全保证</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F14-%E5%9F%BA%E4%BA%8EKubernetes%E5%92%8CIstio%E7%9A%84%E5%AE%89%E5%85%A8%E4%BF%9D%E8%AF%81/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F14-%E5%9F%BA%E4%BA%8EKubernetes%E5%92%8CIstio%E7%9A%84%E5%AE%89%E5%85%A8%E4%BF%9D%E8%AF%81/</id>
    <published>2022-11-08T15:00:00.000Z</published>
    <updated>2022-11-20T15:17:54.758Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生13-Kubernetes集群联邦和Istio多集群管理</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F13-Kubernetes%E9%9B%86%E7%BE%A4%E8%81%94%E9%82%A6%E5%92%8CIstio%E5%A4%9A%E9%9B%86%E7%BE%A4%E7%AE%A1%E7%90%86/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F13-Kubernetes%E9%9B%86%E7%BE%A4%E8%81%94%E9%82%A6%E5%92%8CIstio%E5%A4%9A%E9%9B%86%E7%BE%A4%E7%AE%A1%E7%90%86/</id>
    <published>2022-11-08T14:00:00.000Z</published>
    <updated>2022-11-20T15:17:47.605Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生12-基于Istio的高级流量管理</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F12-%E5%9F%BA%E4%BA%8EIstio%E7%9A%84%E9%AB%98%E7%BA%A7%E6%B5%81%E9%87%8F%E7%AE%A1%E7%90%86/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F12-%E5%9F%BA%E4%BA%8EIstio%E7%9A%84%E9%AB%98%E7%BA%A7%E6%B5%81%E9%87%8F%E7%AE%A1%E7%90%86/</id>
    <published>2022-11-08T13:00:00.000Z</published>
    <updated>2022-11-20T15:17:41.235Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生11-将应用迁移至Kubernetes平台</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F11-%E5%B0%86%E5%BA%94%E7%94%A8%E8%BF%81%E7%A7%BB%E8%87%B3Kubernetes%E5%B9%B3%E5%8F%B0/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F11-%E5%B0%86%E5%BA%94%E7%94%A8%E8%BF%81%E7%A7%BB%E8%87%B3Kubernetes%E5%B9%B3%E5%8F%B0/</id>
    <published>2022-11-08T12:00:00.000Z</published>
    <updated>2022-11-20T15:17:35.108Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生10-Kubernetes的生产化运维</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F10-Kubernetes%E7%9A%84%E7%94%9F%E4%BA%A7%E5%8C%96%E8%BF%90%E7%BB%B4/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F10-Kubernetes%E7%9A%84%E7%94%9F%E4%BA%A7%E5%8C%96%E8%BF%90%E7%BB%B4/</id>
    <published>2022-11-08T11:00:00.000Z</published>
    <updated>2022-11-20T15:17:28.578Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生09-生产化集群的管理</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F09-%E7%94%9F%E4%BA%A7%E5%8C%96%E9%9B%86%E7%BE%A4%E7%9A%84%E7%AE%A1%E7%90%86/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F09-%E7%94%9F%E4%BA%A7%E5%8C%96%E9%9B%86%E7%BE%A4%E7%9A%84%E7%AE%A1%E7%90%86/</id>
    <published>2022-11-08T10:00:00.000Z</published>
    <updated>2022-11-20T15:17:21.265Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生08-Kubernetes控制平面组件：生命周期管理和服务发现</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F08-Kubernetes%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2%E7%BB%84%E4%BB%B6%EF%BC%9A%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E7%AE%A1%E7%90%86%E5%92%8C%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F08-Kubernetes%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2%E7%BB%84%E4%BB%B6%EF%BC%9A%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E7%AE%A1%E7%90%86%E5%92%8C%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0/</id>
    <published>2022-11-08T09:00:00.000Z</published>
    <updated>2022-11-20T15:17:12.964Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生07-Kubernetes控制平面组件：调度器和控制器</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F07-Kubernetes%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2%E7%BB%84%E4%BB%B6%EF%BC%9A%E8%B0%83%E5%BA%A6%E5%99%A8%E5%92%8C%E6%8E%A7%E5%88%B6%E5%99%A8/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F07-Kubernetes%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2%E7%BB%84%E4%BB%B6%EF%BC%9A%E8%B0%83%E5%BA%A6%E5%99%A8%E5%92%8C%E6%8E%A7%E5%88%B6%E5%99%A8/</id>
    <published>2022-11-08T08:00:00.000Z</published>
    <updated>2022-11-20T15:17:05.783Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生06-Kubernetes控制平面组件：API Server</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F06-Kubernetes%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2%E7%BB%84%E4%BB%B6%EF%BC%9AAPI-Server/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F06-Kubernetes%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2%E7%BB%84%E4%BB%B6%EF%BC%9AAPI-Server/</id>
    <published>2022-11-08T07:00:00.000Z</published>
    <updated>2022-11-20T15:16:59.453Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生05-Kubernetes控制平面组件：etcd</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F05-Kubernetes%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2%E7%BB%84%E4%BB%B6%EF%BC%9Aetcd/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F05-Kubernetes%E6%8E%A7%E5%88%B6%E5%B9%B3%E9%9D%A2%E7%BB%84%E4%BB%B6%EF%BC%9Aetcd/</id>
    <published>2022-11-08T06:00:00.000Z</published>
    <updated>2022-11-20T15:16:52.904Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生04-Kubernetes架构原则和对象设计</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F04-Kubernetes%E6%9E%B6%E6%9E%84%E5%8E%9F%E5%88%99%E5%92%8C%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F04-Kubernetes%E6%9E%B6%E6%9E%84%E5%8E%9F%E5%88%99%E5%92%8C%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1/</id>
    <published>2022-11-08T05:00:00.000Z</published>
    <updated>2022-11-20T15:16:46.692Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
  <entry>
    <title>云原生03-Docker核心技术</title>
    <link href="https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F03-Docker%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF/"/>
    <id>https://huajun-chen.github.io/2022/11/08/%E4%BA%91%E5%8E%9F%E7%94%9F03-Docker%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF/</id>
    <published>2022-11-08T04:00:00.000Z</published>
    <updated>2022-11-20T15:16:33.714Z</updated>
    
    <content type="html"><![CDATA[<p>待完成。。。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;待完成。。。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="后端" scheme="https://huajun-chen.github.io/categories/%E5%90%8E%E7%AB%AF/"/>
    
    
    <category term="云原生" scheme="https://huajun-chen.github.io/tags/%E4%BA%91%E5%8E%9F%E7%94%9F/"/>
    
  </entry>
  
</feed>
