Leetcode 0021.合并两个有序链表
21. 合并两个有序链表将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 12输入:l1 = [1,2,4], l2 = [1,3,4]输出:[1,1,2,3,4,4] 示例 2: 12输入:l1 = [], l2 = []输出:[] 示例 3: 12输入:l1 = [], l2 = [0]输出:[0] 题目大意需要将两个升序排列的链表合并成一个新的升序链表,新链表由原两个链表的所有节点组成,且保持升序排列。 解题思路 使用虚拟头节点(dummy node)简化边界情况处理 双指针遍历两个链表,比较当前节点值,将较小的节点接入结果链表 当一个链表遍历完毕后,将另一个链表的剩余部分直接接入结果链表 这种方法的时间复杂度为 O (n + m),其中 n 和 m 分别是两个链表的长度,空间复杂度为 O (1),仅使用了常数个额外节点。 1234567891011121314151617181920212223242526272829303132333435363738/** * Definition for...
C++ 模板工厂模式:从手动注册到自动发现的进化之路
在软件开发中,工厂模式是解耦对象创建与使用的经典方案。但传统工厂模式在面对频繁新增产品时,总会陷入修改工厂类的尴尬。本文将带你探索如何用 C++ 模板实现自动注册的工厂模式,彻底解决这一痛点。 一、传统工厂的 "if-else 地狱"假设我们要开发一个支持多种日志输出的组件(控制台日志、文件日志、网络日志),传统工厂实现可能是这样的: 123456789101112131415161718class Logger {public: virtual void log(const std::string& msg) = 0; virtual ~Logger() = default;};class ConsoleLogger : public Logger { /* 实现 */ };class FileLogger : public Logger { /* 实现 */ };class LoggerFactory {public: static...
Gerrit使用指北
一、Gerrit 是什么?为什么需要它?Gerrit 是一款基于 Git 的开源代码审查工具,核心价值在于强制代码评审流程,通过多人协作把关代码质量,减少线上缺陷,同时保留完整的变更追溯记录。它特别适合中小型团队: 支持细粒度权限控制(谁能提交 / 评审 / 合并代码) 与 Git 原生兼容,无需改变现有开发习惯 网页端可视化评审界面,支持评论、打分、变更追踪 可集成 CI/CD 流程(如 Jenkins、GitHub Actions),实现自动化验证 对比直接提交 Git 仓库:Gerrit 通过「虚拟分支」机制拦截直接提交,确保所有代码变更都经过评审,尤其适合需要严格质量管控的 C/C++ 工程(如嵌入式、工具类项目)。 二、环境准备与安装配置(服务器端)1. 核心依赖 操作系统:Linux(推荐 Ubuntu 20.04+/CentOS 7+) 依赖软件:Java 8+(Gerrit 基于 Java 开发)、Git、数据库(默认 H2,生产环境推荐 MySQL/PostgreSQL) 2....
CMake+Git实现C++项目版本号管理
一、基础认知:版本号规范与核心逻辑在开展实操之前,需明确两个核心基础内容:版本号的规范化格式标准与该方案的核心实现逻辑,为后续操作提供理论支撑。 1. 语义化版本规范(SemVer)建议采用「语义化版本规范(Semantic Versioning, SemVer)」,其格式定义为:主版本号.次版本号.补丁版本号(例如 v1.2.3),各组成部分的语义含义如下: 主版本号(Major):当项目进行不兼容的API变更时递增,此时旧版本代码无法直接适配(例如 v2.0.0,代表项目功能架构发生重大调整); 次版本号(Minor):当项目新增向后兼容的功能时递增,不影响现有代码的正常运行(例如 v1.3.0,代表在原有基础上扩展功能); 补丁版本号(Patch):当项目进行向后兼容的问题修复时递增,仅修正缺陷不新增功能(例如 v1.2.4,代表针对现有版本的Bug修复); 可选后缀:包括预发布版本标识(例如 v1.2.3-beta,用于标识测试阶段版本)与构建信息(例如 v1.2.3+20241201,用于记录版本编译时间)。 2....
YAML 配置指南
一、什么是 YAML?—— 不止于「另一种配置文件」YAML 全称 YAML Ain't Markup Language(YAML 不是标记语言),听着像绕口令,核心却是「反标记语言」的设计理念:用最简洁的语法描述数据结构,让人类一眼能看懂,机器也能轻松解析。 它诞生于 2001 年,初衷是替代 XML 的繁琐标签和 JSON 的大括号,如今已成为配置文件的「首选格式」—— 你在 Kubernetes、Docker Compose、Spring Boot、GitHub Actions 等场景中,随处可见它的身影。 核心定位:人类可读、机器可解析的数据序列化语言,专注于配置场景的简洁性和易用性。 二、为什么选择 YAML?—— 三大核心优势对比 XML、JSON,YAML 的优势一目了然: 特性 XML(繁琐) JSON(简洁但局限) YAML(平衡之选) 语法简洁度 需闭合标签() 需大括号 / 引号,无注释 无多余符号,支持注释 可读性 低(标签冗余) 中(结构清晰但缺乏注释) 高(自然语言般的层级) 数据类型支持 需定义...
C++相对路径:从编译到运行
步骤 1:说明编译与运行时工作目录的分离特性首先,我们必须明确一个基本原则:编译器的工作目录和程序运行时的工作目录是两个完全独立的概念。 1.1 编译时路径解析编译器(如GCC, Clang, MSVC)在处理源代码时,主要涉及两种路径: #include "my_header.h":这种形式的包含指令,编译器会首先在包含该指令的源文件所在的目录下查找my_header.h。如果找不到,再在编译器指定的系统或用户包含路径(通过-I参数指定)中查找。 #include <iostream>:这种形式,编译器会直接在系统或用户指定的包含路径中查找,而不会在当前源文件目录中查找。 关键点:编译时的路径解析是为了定位源文件和头文件,以便将它们组合成一个翻译单元并生成目标文件(.o或.obj)。这个过程与程序最终运行时需要读取的数据文件(如配置、图片、资源)毫无关系。 1.2...
Leetcode 0570. 至少有5名直接下属的经理
570. 至少有5名直接下属的经理表: Employee 123456789101112+-------------+---------+| Column Name | Type |+-------------+---------+| id | int || name | varchar || department | varchar || managerId | int |+-------------+---------+id 是此表的主键(具有唯一值的列)。该表的每一行表示雇员的名字、他们的部门和他们的经理的id。如果managerId为空,则该员工没有经理。没有员工会成为自己的管理者。 编写一个解决方案,找出至少有五个直接下属的经理。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 123456789101112131415161718输入: Employee 表:+-----+-------+------------+-----------+| id | name | department...
Leetcode 0626. 换座位
626. 换座位表: Seat 123456789+-------------+---------+| Column Name | Type |+-------------+---------+| id | int || student | varchar |+-------------+---------+id 是该表的主键(唯一值)列。该表的每一行都表示学生的姓名和 ID。ID 序列始终从 1 开始并连续增加。 编写解决方案来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。 按 id 升序 返回结果表。 查询结果格式如下所示。 示例 1: 1234567891011121314151617181920212223输入: Seat 表:+----+---------+| id | student |+----+---------+| 1 | Abbot || 2 | Doris || 3 | Emerson || 4 | Green || 5 | Jeames ...
Leetcode 0180. 连续出现的数字
180. 连续出现的数字表:Logs 12345678+-------------+---------+| Column Name | Type |+-------------+---------+| id | int || num | varchar |+-------------+---------+在 SQL 中,id 是该表的主键。id 是一个自增列。 找出所有至少连续出现三次的数字。 返回的结果表中的数据可以按 任意顺序 排列。 结果格式如下面的例子所示: 示例 1: 123456789101112131415161718192021输入:Logs 表:+----+-----+| id | num |+----+-----+| 1 | 1 || 2 | 1 || 3 | 1 || 4 | 2 || 5 | 1 || 6 | 2 || 7 | 2 |+----+-----+输出:Result 表:+-----------------+| ConsecutiveNums...
Leetcode 0461.hamming-distance
461. 汉明距离两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。 给你两个整数 x 和 y,计算并返回它们之间的汉明距离。 示例 1: 1234567输入:x = 1, y = 4输出:2解释:1 (0 0 0 1)4 (0 1 0 0) ↑ ↑上面的箭头指出了对应二进制位不同的位置。 示例 2: 12输入:x = 3, y = 1输出:1 题目大意 汉明距离是指两个整数的二进制表示中,对应位置二进制位不同的数目。给定两个整数 x 和 y,计算并返回它们之间的汉明距离。 例如: 输入 x=1, y=4,二进制分别为 0001 和 0100,对应位不同的位置有 2 处,输出 2; 输入 x=3, y=1,二进制分别为 0011 和 0001,对应位不同的位置有 1 处,输出 1。 解题思路核心思路是利用异或运算 + 统计 1 的个数,步骤如下: 异或运算(XOR):异或的特性是 “相同为 0,不同为 1”。对 x 和 y 做异或操作,得到的结果 xor_result 中,每一位的 1 都对应 x 和 y...
BM25 算法解析
一、BM25 算法核心原理:从公式到 C++ 实现关注点BM25(Best Matching 25)是基于概率检索模型的改进算法,核心是在 TF-IDF 的基础上增加文档长度归一化和参数可调性,解决 “长文档过度匹配” 的问题。理解原理时,需重点关注与 C++ 实现强相关的设计点。 1.1 核心公式与参数意义BM25 的单术语 - 文档相关性评分公式如下: $score(q, d) = IDF(q) \times \frac{TF(q, d) \times (k_1 + 1)}{TF(q, d) + k_1 \times (1 - b + b \times \frac{len(d)}{avg_len})}$ 其中关键参数与 C++ 实现的关联的: $TF(q,d)$在文档$d$中的词频,需存储在倒排索引中,用float类型平衡精度与内存; $len(d)$文档$d$的长度(术语数),需在文档元数据中记录,用uint32_t节省内存; $avg_len$所有文档的平均长度,预处理阶段计算后全局缓存,避免重复计算; $k$词频饱和系数(通常取...
C++ 高级特性
一、C++11新特性概述记忆口诀:C++11新特性,语法库扩双提升;auto decltype智能指,nullptr范围循环使;右值引用move效,无序容器正则到;Lambda匿名函数好,代码简洁效率高。1. 语法改进 统一初始化方法 成员变量默认初始化 auto关键字:编译器自动推断类型 decltype:推导表达式类型 智能指针:std::shared_ptr、std::unique_ptr 空指针nullptr:替代NULL,类型明确 基于范围的for循环:简化容器遍历 右值引用和move语义:提高资源转移效率 2. 标准库扩充 无序容器(哈希表):类似map但效率更高 正则表达式:模式匹配字符串 Lambda表达式:定义匿名函数 二、智能指针记忆口诀:智能指针分三类,shared_ptr共享随;引用计数来管理,线程安全要注意;unique_ptr独占权,禁止拷贝所有权;weak_ptr旁观态,lock检查免崩溃。1. shared_ptr(共享指针) 实现机制:基于引用计数,多指针共享同一资源 核心组件: 模板指针T*...
C++ 并发编程
一、并发基础核心组件口诀:线程对象要管理,互斥锁来保安全,原子操作不可拆,条件变量通信忙1.1 std::thread - 线程管理 构造方式: 默认构造:创建空线程对象 初始化构造:thread t(func, args...),传入函数和参数 移动构造:支持线程所有权转移,不支持拷贝 生命周期管理: join():主线程等待子线程完成,阻塞当前线程 detach():线程独立运行,与主线程分离 关键注意:线程对象销毁前必须调用join()或detach(),否则程序崩溃 常见陷阱:局部线程对象销毁时,若线程函数仍在运行会导致崩溃(解决:使用detach()或确保join()被调用) 1.2 std::mutex - 互斥锁 基本功能:保护共享资源,确保同一时间只有一个线程访问 核心方法:lock()(加锁)、unlock()(解锁)、try_lock()(尝试加锁,非阻塞) 使用建议:配合RAII包装器使用,避免忘记解锁导致死锁 1.3 std::lock_guard -...
C++ 网络编程
一、TCP Socket通信实现记忆口诀:服创绑监听,接收发关尽;客创连收发,关闭要记心。服务器端流程 创建socket:调用socket()创建流式套接字(TCP) 绑定地址:通过bind()将socket与IP地址和端口绑定 监听连接:使用listen()开启监听,设置最大连接队列 接受连接:调用accept()阻塞等待客户端连接,返回新socket 数据收发:使用send()和recv()进行数据传输 关闭socket:通信结束后关闭连接 客户端流程 创建socket:同服务器端 连接服务器:通过connect()向服务器发起连接请求 数据收发:同服务器端 关闭socket:通信结束后关闭连接 服务器端代码示例1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465#include <iostream>#include <cstring>#include...
C++ 面向对象
一、C++三大特性记忆口诀三大特性记分明,封装继承多态行;封装数据和操作,权限控制安全定;继承复用加扩展,子类父类心相印;多态接口行为异,编译运行两类型。 核心概念 封装:数据与操作打包,通过访问权限控制暴露(public/private/protected),提高安全性,隐藏实现细节 继承:子类拥有父类属性和行为,可在原有基础上扩展,实现代码复用 多态:同一种接口不同行为,分编译时多态(函数重载、运算符重载)和运行时多态(虚函数+继承) 代码示例123456789101112131415161718192021222324252627#include <iostream>using namespace std;// 封装class Animal {protected: string name;public: Animal(string n) : name(n) {} virtual void speak() { // 虚函数实现多态 cout << name...
C++ 实现 JWT 工具类封装
一、JWT概念JWT(JSON Web Token)是一种用于在网络上安全传输信息的紧凑、自包含的方式。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),通过点分隔的字符串形式呈现。在身份验证和信息交换场景中应用广泛,因为它可以验证信息的完整性和真实性。 1.1 准备工作在开始之前,我们需要确保系统中安装了libjwt库,这是一个轻量级的 JWT 实现库。在 Ubuntu/Debian 系统上,可以使用以下命令安装: 1sudo apt-get install libjwt-dev 1.2 jwt.cc1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889#include <jwt.h>#include...
C++ 内存管理
一、智能指针记忆口诀:智能指针三兄弟,unique独占share共享,weak观测防循环,RAII思想记心上智能指针是一种自动管理动态内存的工具类,用于防止内存泄漏。C++提供了三种常用的智能指针: unique_ptr(独占智能指针): 独占对象所有权,同一时间只能有一个指针指向一个对象 禁止拷贝构造和拷贝赋值,支持移动语义 适合独占资源的场景 shared_ptr(共享智能指针): 共享对象所有权,允许多个指针指向同一个对象 使用引用计数,当引用计数为0时释放资源 可以通过use_count()查看引用计数 weak_ptr(弱引用指针): 不拥有资源,不增加引用计数 用于解决shared_ptr的循环引用问题 需要通过lock()方法提升为shared_ptr才能访问资源 RAII机制(资源获取即初始化): 当创建智能指针对象时,它立即接管资源 当智能指针生命周期结束时,自动调用析构函数释放资源 无需手动调用delete,有效防止内存泄漏 代码示例1234567891011121314//...
C++ STL 背诵版知识点总结
一、STL容器总览口诀:三容器两适配,序列关联加无序1.1 容器分类 序列容器:vector(动态数组)、list(双向链表)、deque(双端队列)、array(固定数组)、forward_list(单向链表) 关联容器:set(有序唯一集合)、map(有序键值对)、multiset(有序可重复集合)、multimap(有序可重复键值对) 无序容器:unordered_set、unordered_map、unordered_multiset、unordered_multimap 容器适配器:stack(栈)、queue(队列)、priority_queue(优先队列) 1.2 底层结构与性能对比 vector/deque: 动态数组,支持随机访问 list/forward_list: 链表,高效插入删除 set/map: 红黑树,有序且查找/插入为O(logN) unordered_*:...
双栈 TCP 回声服务器 -- v3.0
要将双栈 TCP 回声服务器从线程池模式改造为Reactor 模式,核心是基于I/O 多路复用(epoll) 实现 “事件驱动” 的高效 I/O 处理 —— 通过单线程(或主线程)监听多个 Socket 的 I/O 事件,事件触发时再分发到对应处理器,避免线程上下文切换开销,更适合高并发场景。 一、Reactor 模式核心原理与组件Reactor 模式(反应器模式)是一种事件驱动架构,核心思想是 “将 I/O 事件从业务逻辑中分离”,通过以下组件实现: 组件 作用 Reactor(反应器) 核心调度器:运行事件循环,通过 I/O 多路复用(epoll)等待事件,分发事件到处理器 EventDemultiplexer 事件多路分离器:封装 epoll,负责注册 / 删除事件、等待事件触发(本文用 epoll) EventHandler(处理器) 事件处理接口:定义handleRead/handleWrite/handleError等统一接口,子类实现具体逻辑(如...
简单echo服务器 -- v2.0
在原有双栈兼容基础上,新增线程池替代进程、文件日志、超时处理、自定义协议四大核心优化,解决进程开销高、排查难、资源占用、粘包等问题,适用于高并发场景。 一、核心优化方案设计 优化功能 实现思路 线程池优化 设计固定大小线程池(基于pthread),复用线程处理客户端连接,避免频繁创建销毁进程的开销 文件日志系统 实现线程安全的日志类,记录时间戳、日志级别、事件详情,写入本地文件(如echo_server.log) 超时处理 通过setsockopt设置SO_RCVTIMEO/SO_SNDTIMEO,为recv/send设置超时(默认 5 秒) 自定义协议 定义 “4 字节长度头 + 数据” 格式,解决 TCP 粘包问题(长度头用网络字节序传输) 二、通用工具类实现(日志 + 线程池)1....

