Leecode 0503. 下一个更大元素 II
503. 下一个更大元素 II给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。 示例 1: 12345输入: nums = [1,2,1]输出: [2,-1,2]解释: 第一个 1 的下一个更大的数是 2;数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。 示例 2: 12输入: nums = [1,2,3,4,3]输出: [2,3,4,-1,4] 解题思路核心思路是单调栈 + 数组翻倍模拟循环,通过将数组复制一份拼接在末尾(模拟循环),利用单调栈高效找到每个元素的下一个更大元素: 模拟循环数组: 将原数组 nums 复制一份并拼接在末尾(如 [1,2,1] 变为...
Leecode 0496. 下一个更大元素 I
496. 下一个更大元素 Inums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。 给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。 对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。 返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。 示例 1: 123456输入:nums1 = [4,1,2], nums2 = [1,3,4,2].输出:[-1,3,-1]解释:nums1 中每个值的下一个更大元素如下所述:- 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。- 1 ,用加粗斜体标识,nums2 =...
Redis 缓存三大故障 - 缓存击穿
导言在分布式系统中,Redis 作为高性能分布式缓存,可有效减轻数据库压力、提升接口响应速度,但高并发场景下,缓存雪崩、缓存击穿、缓存穿透三类异常易引发系统稳定性问题。 一、缓存击穿 —— 热点数据 “过期瞬间” 的单点突破1. 核心定义缓存击穿是指某一 “热点数据”(高并发访问的单一数据)的缓存过期失效瞬间,大量并发请求同时查询该数据,由于缓存已无对应数据,所有请求直接穿透至数据库,导致数据库针对该热点数据的查询压力骤增、甚至出现查询超时的现象。 核心特征:区别于缓存雪崩,其关键在于 “单个热点数据失效”,影响范围为 “局部”(仅该热点数据相关查询)。 2. 触发条件缓存击穿的发生需同时满足两个条件: 热点数据缓存过期:某一数据访问量极高(如每秒数千次查询),且其 Redis 缓存恰好过期; 无预热机制的突发热点:突发高并发请求集中访问某一数据(如临时热门内容),而该数据未提前缓存,导致请求直接打向 DB。 3. 解决方案对比 解决方案 实现逻辑 优点 缺点 适用场景 互斥锁(分布式锁) 缓存失效时,仅允许一个请求获取锁并查询...
Redis 缓存三大故障 - 缓存雪崩
导言在分布式系统中,Redis 作为高性能分布式缓存,可有效减轻数据库压力、提升接口响应速度,但高并发场景下,缓存雪崩、缓存击穿、缓存穿透三类异常易引发系统稳定性问题。 一、缓存雪崩 —— 大量缓存 “集体失效” 的连锁反应1. 核心定义缓存雪崩是指某一时间段内,大量缓存数据同时过期失效,或缓存服务(如 Redis 集群)整体不可用,导致原本由缓存承接的高并发请求全部穿透至数据库,引发数据库压力骤增、甚至宕机,进而可能导致整个业务服务雪崩的现象。 核心特征:区别于其他异常,其关键在于 “批量失效 / 整体不可用”,影响范围为 “全局”(而非局部)。 2. 触发条件缓存雪崩的发生通常源于两类场景,满足任一即可触发: 缓存集中过期:大量缓存数据设置了相同或相近的过期时间(如统一设为 24 小时、固定时间点过期),到期后集体失效,请求失去缓存承接; 缓存服务不可用:Redis 集群因硬件故障、网络波动、内存溢出被系统终止等原因,出现整体宕机或无法访问,导致缓存层完全失效。 3....
Leecode 0084. 柱状图中最大的矩形
84. 柱状图中最大的矩形给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 示例 1: 123输入:heights = [2,1,5,6,2,3]输出:10解释:最大的矩形为图中红色区域,面积为 10 示例 2: 12输入: heights = [2,4]输出: 4 解题思路该解法是对单调栈思路的优化实现,通过在数组末尾添加哨兵元素和栈初始化技巧,将左右边界的计算合并到一次遍历中,代码更简洁且效率更高。 核心优化思路 哨兵元素(Sentinel): 在原数组末尾添加 -1(高度为负数的哨兵),确保遍历结束时栈中所有元素都会被弹出计算(相当于 “大火收汁”); 栈初始时推入 -1(索引哨兵),解决栈空时的边界判断问题,同时自然对应 “左侧无更矮柱子” 的情况(left[i] = -1)。 一次遍历计算左右边界: 遍历每个元素作为右侧边界(right),当当前高度小于栈顶高度时,栈顶元素的左右边界均已确定: 右边界:当前索引...
Leecode 0402. 移掉 K 位数字
402. 移掉 K 位数字给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。 示例 1 : 123输入:num = "1432219", k = 3输出:"1219"解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。 示例 2 : 123输入:num = "10200", k = 1输出:"200"解释:移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。 示例 3 : 123输入:num = "10", k = 2输出:"0"解释:从原数字移除所有的数字,剩余为空就是 0 。 解题思路核心思路是单调栈 + 贪心算法,通过维护一个递增的栈来确保剩余数字最小,同时控制移除的数字数量不超过 k: 单调栈逻辑: 遍历字符串中的每个数字,对于当前数字c: 若栈不为空,且栈顶数字大于 c,且仍有可移除的次数(k >...
Leecode 0042. 接雨水
42. 接雨水给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 123输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]输出:6解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 示例 2: 12输入:height = [4,2,0,3,2,5]输出:9 解题思路核心思路是双指针边界,通过每个柱子能接住的雨水量取决于其左右两侧的最高柱子中较矮的那个(短板效应): 边界定义: 对于位置 i,左侧最高柱子高度为 left_max[i]; 右侧最高柱子高度为 right_max[i]; 位置 i 能接住的雨水量为 min(left_max[i], right_max[i]) - height[i](若结果为正,否则为 0)。 优化实现: 采用双指针法,无需额外存储 left_max 和 right_max 数组,将空间复杂度降至 O (1); 用 left 和 right...
Redis 哨兵模式(Sentinel)
导言哨兵模式(Sentinel)是 Redis 主从复制架构的 “高可用增强层”,通过分布式共识机制解决了主从复制中 “主节点宕机需手动切换” 的痛点,实现故障自动检测、主节点自动选举、从节点自动同步,是中小规模 Redis 集群(数据量 < 10GB、读多写少)的生产级高可用标准方案。 一、哨兵模式的核心定位与价值1.1 在理解哨兵前,需先明确其与主从复制的关系:主从复制负责 “数据同步”(主写从读、数据备份),但无法自动处理主节点故障; 哨兵负责 “高可用保障”(监控、故障转移、配置自动更新),是主从架构的 “大脑”,二者协同实现 99.99% 服务可用性。 1.2 哨兵模式的核心价值 彻底告别手动运维:主节点宕机后,无需人工干预,10-30 秒内完成故障转移 分布式容错:多哨兵节点共识判断,避免单点误判(如网络抖动导致的假宕机) 客户端透明路由:客户端可通过哨兵获取当前主节点地址,无需硬编码 IP / 端口 配置动态同步:故障转移后,自动通知所有从节点切换新主节点,更新同步关系 二、哨兵的核心功能与工作原理2.1...
Redis 主从复制
导言作为分布式系统中实现数据高可用与读写分离的核心技术,Redis 主从复制(Master-Replica Replication)通过多节点数据同步,解决了单点故障风险与读写负载不均问题。 一、核心原理:全量复制与增量复制双机制Redis 主从复制通过 “全量初始化 + 增量衔接” 的方式实现数据同步,两种复制模式适配不同场景需求,需明确触发条件与执行流程。 1. 全量复制:从节点初始化同步触发场景 从节点首次连接主节点(冷启动场景) 从节点断开时间超过repl_backlog_buffer(复制积压缓冲区)大小 主节点执行flushall/flushdb后,从节点同步时无有效偏移量 关键细节 RDB 传输期间主节点通过复制客户端缓冲区(默认 1GB)缓存新写请求,缓冲区满会导致复制失败,需根据写入量调整client-output-buffer-limit replica 从节点加载 RDB 时会阻塞读请求,可通过replica-lazy-flush yes(默认开启)延迟清空数据,减少阻塞时间 2....
Redis 内存满故障机制
一、Redis 内存分配原理与数据存储特性要解决内存满的问题,首先需理解 Redis 如何占用内存 —— 其内存消耗并非仅用于存储键值对,而是由多模块构成,且数据类型的编码特性直接影响内存效率。 1.1 内存结构组成(按占用比例排序)Redis 的内存消耗主要分为 4 个部分,其中数据区是核心: 数据区(~80%-90%):存储键值对数据,包含键(Key)、值(Value)及数据结构元数据(如哈希表桶、链表节点、跳表索引等)。 例:一个Hash类型键,若采用ziplist编码,会存储字段 / 值的紧凑数组;若转成hashtable,则需额外存储哈希桶、链表指针等元数据,内存占用显著增加。 缓冲区(~5%-15%):包括三类关键缓冲,易被忽视但可能引发内存溢出: 客户端缓冲:每个客户端连接的输入 / 输出缓冲(默认无上限,大量闲置连接会导致缓冲堆积); 复制缓冲:主从同步时的repl-backlog-buffer(默认 1MB,若同步延迟高会扩容); AOF 缓冲:AOF...
Redis 作为 MySQL 缓存选择因素归类
引言:高并发时代下的数据库性能困境与缓存破局在现代应用架构中,高并发读取场景(如电商商品详情页、CMS 文章列表、用户会话查询)已成为系统性能的核心挑战。MySQL 作为主流关系型数据库,其 InnoDB 存储引擎基于磁盘 IO 实现数据持久化,在单机并发读场景下,性能通常局限于 1k-10k QPS(受磁盘寻道时间、页缓存命中率影响),难以满足秒杀、大促等峰值需求。 Redis 作为开源高性能内存数据库,凭借 内存级 IO 特性(读 QPS 可达 10 万 - 100 万,写 QPS 可达 5 万 - 50 万)、丰富的数据结构和灵活的过期策略,成为 MySQL 缓存的首选方案。 一、技术原理:Redis 与 MySQL 的协作核心Redis 作为 MySQL 缓存的本质是 “将热点数据从磁盘迁移到内存”,但需解决数据一致性、缓存命中率、异常场景处理三大核心问题。 要点 1:缓存协作模型选型(4 种经典模式)Redis 与 MySQL...
Leecode 0316. 去除重复字母
316. 去除重复字母给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。 示例 1: 12输入:s = "bcabc"输出:"abc" 示例 2: 12输入:s = "cbacdcbc"输出:"acdb" 核心思路是单调栈 + 贪心算法,通过维护一个单调递增的栈来确保字典序最小,同时利用计数数组判断字符是否还有剩余,确保每个字符只保留一次: 预处理: 统计字符串中每个字符的出现次数(count 数组); 记录字符是否已在栈中(in_stack 数组),避免重复添加。 单调栈逻辑: 遍历字符串中的每个字符C: 减少 count[c](当前字符已被考虑); 若 c 已在栈中,直接跳过; 若 c 不在栈中,且栈不为空,且栈顶字符大于 c,且栈顶字符在后续还有出现(count[栈顶字符] > 0),则弹出栈顶字符(确保字典序更小); 将 c...
Leecode 0409. 最长回文串
409. 最长回文串给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的 回文串 的长度。 在构造过程中,请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串。 示例 1: 1234输入:s = "abccccdd"输出:7解释:我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。 示例 2: 123输入:s = "a"输出:1解释:可以构造的最长回文串是"a",它的长度是 1。 解题思路核心思路是统计字符频率,利用回文串的特性计算最大长度: 回文串特性: 回文串对称位置的字符相同; 偶数长度的回文串:所有字符出现次数均为偶数; 奇数长度的回文串:仅有一个字符出现奇数次(位于中心),其余均为偶数次。 频率统计: 统计字符串中每个字符的出现次数; 累计所有字符的最大偶数次(例如,出现 5 次的字符可贡献 4 次); 若存在出现奇数次的字符,可在结果中加 1(作为中心字符)。 计算逻辑: 初始化结果...
Leecode 0045. 跳跃游戏 II
45. 跳跃游戏 II给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在索引 i 处,你可以跳转到任意 (i + j) 处: 0 <= j <= nums[i] 且 i + j < n 返回到达 n - 1 的最小跳跃次数。测试用例保证可以到达 n - 1。 示例 1: 1234输入: nums = [2,3,1,1,4]输出: 2解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 示例 2: 12输入: nums = [2,3,0,1,4]输出: 2 解题思路核心思路是贪心算法,通过跟踪 “当前跳跃的最远边界” 和 “下一次跳跃的最远可达位置”,在每一步跳跃时选择最优范围,实现最少跳跃次数: 贪心策略: 用 end 表示当前跳跃能到达的最远边界(初始为 0); 用 max_reach 表示从当前位置到 end 之间的所有位置能跳到的最远位置; 用...
通用代码审查清单整理
一、常规功能与可读性(P1+P2) 序号 审查项 判定标准(二元可验证) 优先级 1 功能实现完整性 代码覆盖所有预期需求点(对照需求清单无遗漏,无逻辑错误,如模板特化、重载函数功能符合设计) P1 2 代码易懂性 新接手开发者可在 10 分钟内理解核心逻辑(无过度复杂模板嵌套、晦涩宏定义、无拼音 / 英文混杂命名) P1 3 编码规范符合性 完全匹配团队 C++ 规范(如大括号位置、命名空间使用、const/constexpr正确修饰、缩进无违规) P1 4 冗余代码清理 无重复代码(≥3 行相同逻辑未抽取为函数 / 模板)、无注释掉的无效代码块(如废弃的类成员、未使用的全局函数) P1 5 循环安全性 循环有明确终止条件(无死循环风险),无循环内重计算(如重复获取std::vector长度),无迭代器失效场景(如循环中增删容器元素) P1 6 全局变量 / 对象合理性 无不必要全局变量(可替换为局部变量 /...
C++/MySQL/Redis 锁机制 - 3
Redis 锁机制:分布式集群的并发控制Redis 作为分布式缓存与数据库,其锁机制主要解决跨节点、跨进程的分布式并发问题(如微服务集群中共享资源的互斥访问)。核心是 “分布式锁”,基于 Redis 原子命令和 Lua 脚本实现,支持可重入、公平锁等特性。 1. 基础分布式锁:基于 SETNX 命令核心定义利用 Redis 的 SETNX(SET if Not Exists)原子命令实现的分布式锁:若键不存在则设置值(获取锁),若已存在则失败(锁已被持有),确保同一时间仅一个节点的一个线程获取锁。 底层实现 核心命令:SET lock_key thread_id NX EX 10(NX:不存在才设置,EX:过期时间 10 秒); 锁标识:用 thread_id(如 “node1_thread2”)标记持有锁的线程,避免误释放其他线程的锁; 过期时间:防止线程崩溃导致锁无法释放(死锁),需设置合理的过期时间(大于业务执行时间)。 代码示例(Redis CLI 实现)123456789101112131415# 1. 获取锁:SETNX +...
C++/MySQL/Redis 锁机制 - 2
MySQL 锁机制:数据库事务中的数据一致性保障MySQL 作为关系型数据库,其锁机制与事务隔离级别深度绑定,核心解决多事务并发访问时的数据一致性问题(如脏读、不可重复读、幻读)。锁的粒度从 “表级” 到 “行级”,支持乐观锁与悲观锁,适配不同并发场景。 1. 表级锁:粗粒度悲观锁核心定义锁定整个数据表,同一时间仅允许特定类型的操作(读 / 写)执行,是 MySQL 中粒度最粗的锁。MyISAM 存储引擎默认支持,InnoDB 也支持但不常用。 底层实现 读锁(共享锁,S 锁):多个事务可同时获取读锁,允许读操作,禁止写操作; 写锁(排他锁,X 锁):仅一个事务可获取写锁,禁止其他事务读 / 写操作; 锁冲突检测在 MySQL 服务器层完成,无需深入存储引擎,开销低但并发度低。 代码示例(手动加表锁)1234567891011-- 1. 会话1:获取表读锁(允许其他会话读,禁止写)LOCK TABLES user_info READ;SELECT * FROM user_info WHERE id = 1; -- 允许执行UPDATE...
C++/MySQL/Redis 锁机制 - 1
导言在并发编程与分布式系统中,锁机制是保障数据一致性的核心技术。不同技术栈因运行环境(本地进程 / 数据库 / 分布式集群)差异,锁的实现逻辑、核心特性与适用场景存在显著区别。 一、C++ 锁机制:本地进程内的并发控制C++ 作为系统级编程语言,其锁机制基于操作系统内核态同步原语(如互斥量、信号量)与用户态原子操作实现,核心解决单进程内多线程共享内存的线程安全问题。C++11 及以后通过 <thread>、 <mutex>、 <atomic> 等标准库提供统一锁接口,同时支持自定义锁实现。 1. 互斥锁(std::mutex):C++ 基础悲观锁核心定义C++ 标准库中的基础悲观锁,通过操作系统互斥量(Mutex)实现,保证同一时间只有一个线程进入临界区,其他竞争线程会阻塞等待,直到锁释放。是解决本地线程并发冲突的 “通用方案”。 底层实现 依赖操作系统内核态同步原语(如 Linux 的 pthread_mutex_t、Windows 的...
线程局部存储
一、TLS 在多线程环境中的关键技术作用 核心定义:线程局部存储(Thread Local Storage,TLS)是多线程编程中的一种内存隔离机制,为每个线程分配独立的内存空间(即 “线程私有副本”),使线程对该空间的数据访问无需竞争锁资源,且数据仅对所属线程可见。 解决的核心问题: 避免多线程数据竞争:当多个线程需使用同一逻辑变量但无需共享时(如线程内计数器),TLS 替代共享内存 + 锁的方案,消除锁开销与死锁风险。 保证线程数据独立性:确保线程在生命周期内的私有数据(如上下文信息、临时计算结果)不被其他线程篡改,维持线程运行稳定性。 简化线程数据管理:无需手动为每个线程分配 / 释放私有内存,由 TLS 机制自动管理内存生命周期(随线程创建而分配,随线程退出而释放)。 二、TLS 的实现机制2.1 静态分配(编译期确定)原理: 在编译阶段,编译器将标注 “线程局部” 的变量(如 C++ 的thread_local、POSIX 的__thread)分配到特定的 TLS 段(ELF 文件中的.tbss/.tls...
std::tuple 的使用
一、tuple 核心定位与基本特性std::tuple(定义于 头文件)是 C++17 标准库中用于打包多个异构数据类型的轻量级容器,其核心价值在于: 无需定义自定义结构体 / 类,即可承载任意数量的不同类型数据; 配合 C++17 新特性(如类模板参数推导 CTAD、结构化绑定),大幅简化异构数据的创建与访问; 无动态内存分配,内存开销与手动定义的结构体相当,性能高效。 关键区别: 与 std::array:array 仅支持同构类型(如 array<int, 3>),tuple 支持异构类型(如 tuple<int, string, double>); 与 std::pair:pair 仅支持最多 2 个元素,tuple 无元素数量限制。 二、tuple 基本用法(创建与访问)1. 创建方式(C++17 CTAD 特性重点)C++17 引入类模板参数推导(CTAD),创建 tuple 时无需显式指定模板参数,编译器会自动推导类型。 创建方式 代码示例 说明 CTAD 直接初始化 tuple t1(42,...