leecodecode【面试150】【2026.7.7打卡-java版本】

查找和最小的 K 对数字

要点:最小堆int[]{数字,坐标},想成数组。【x,0】先加进去

class Solution { public List> kSmallestPairs(int[] nums1, int[] nums2, int k) { //最小堆 PriorityQueue pq = new PriorityQueue<>((a,b) -> a[0] - b[0]); for(int i = 0; i < Math.min(nums1.length,k);i++){ pq.add(new int[]{nums1[i] + nums2[0], i, 0}); } List> ans = new ArrayList<>(k); while(k-- > 0){ int[] top = pq.poll(); int i = top[1]; int j = top[2]; ans.add(List.of(nums1[i], nums2[j])); if(j+1 < nums2.length){ pq.add(new int[]{nums1[i] + nums2[j+1], i, j+1}); } } return ans; } }

颠倒二进制位

要点:32位置的模拟

class Solution { public int reverseBits(int n) { int ans = 0; for(int i = 0; i < 32; i ++) { ans = n % 2 + 2 * ans; n = n>>1; } return ans; } }

位1的个数

要点:n>>1

class Solution { public int hammingWeight(int n) { int ans = 0; while(n != 0){ if(n%2 == 1){ ans++; } n=n>>>1 ; } return ans; } }

只出现一次的数字

要点:异或^

class Solution { public int singleNumber(int[] nums) { // int ans = 0; for(int num : nums){ ans ^= num; } return ans; } }

只出现一次的数字 II

要点:位置上相加%3

class Solution { public int singleNumber(int[] nums) { //异或 %3 int ans = 0; for(int i = 0; i < 32; i++){ int cnt1 = 0; for(int num : nums){ //取第i位置 cnt1 += num >> i & 1; } ans = ans | ((cnt1 % 3) << i); } return ans; } }

数字范围按位与

要点:抹平后续

class Solution { public int rangeBitwiseAnd(int left, int right) { int shift = 0; while(left < right){ left = left >> 1; right = right >> 1; shift++; } return right << shift; } }

随机知识

📚 MySQL + Redis 面试核心知识点总结

一、MySQL 篇

1. 基础架构:一条 SQL 是怎么执行的?

text

客户端 → 连接器(管理连接/权限)→ 查询缓存(8.0已废弃)→ 解析器(词法/语法分析)→ 优化器(选择索引)→ 执行器(调用存储引擎接口)→ InnoDB

2. 存储引擎:InnoDB vs MyISAM

对比维度InnoDBMyISAM
事务✅ 支持❌ 不支持
行级锁✅ 支持❌ 只支持表锁
外键✅ 支持❌ 不支持
MVCC✅ 支持❌ 不支持
聚簇索引✅ 是❌ 否
适用场景读写并发高、事务敏感读多写少、非事务型

结论:MySQL 5.5+ 默认 InnoDB,几乎 90% 场景都用它。

3. 索引(重中之重)

3.1 B+Tree 索引
  • 为什么用 B+Tree 而不是 B-Tree 或二叉树?

    • B+Tree 非叶子节点不存数据,一个磁盘页能存更多索引,树更矮(IO 次数少)。

    • 叶子节点用双向链表连接,支持范围查询和顺序遍历。

3.2 聚簇索引 vs 非聚簇索引(回表)
类型叶子节点存什么说明
聚簇索引整行数据InnoDB 主键索引就是聚簇索引
非聚簇索引(二级索引)主键 ID查询非索引字段需要回表(再查一次主键索引)
覆盖索引查询所需字段直接在索引中,不回表如select id,name where name='xxx'且name和id是联合索引
3.3 最左前缀原则

联合索引(a, b, c)相当于三个索引:(a)、(a,b)、(a,b,c)。

  • where a=1 and b=2✅ 用索引

  • where b=2 and c=3❌ 不走索引(跳过了 a)

  • where a=1 and c=3→ 只走(a)部分

3.4 索引下推(ICP,Index Condition Pushdown)

MySQL 5.6+ 引入。在存储引擎层就过滤掉不符合条件的记录,减少回表次数。

  • 例子:where a>1 and b=2,先通过a找到记录,在引擎层直接判断b=2,不符合的不回表。

3.5 什么时候索引失效?(必背)
情况原因
like '%abc'以 % 开头,B+Tree 无法定位
or两边有非索引字段整条 SQL 走全表扫描
对索引字段做函数/计算如where date(create_time) = '2025-01-01'
隐式类型转换如varchar字段传int
!=/<>无法用索引做等值查找
is null/is not null多数情况下失效
3.6 为什么索引不宜建太多?
  • 占用磁盘空间。

  • 更新性能下降:每次insert/update/delete,所有索引都要同步更新。

4. 事务与隔离级别

4.1 四大隔离级别
级别脏读不可重复读幻读
READ UNCOMMITTED✅✅✅
READ COMMITTED❌✅✅
REPEATABLE READ(MySQL默认)❌❌⚠️(部分避免)
SERIALIZABLE❌❌❌
4.2 事务隔离级别的实现(MVCC)

MVCC(多版本并发控制):每一行数据有多个版本(通过隐藏字段trx_id和roll_pointer指向 Undo Log)。不同事务读到不同版本的数据,实现非阻塞读。

  • 快照读:select(不加锁),读的是快照版本。

  • 当前读:select for update/update/insert,读的是最新版本,并加锁。

5. 三大日志(MySQL 的“保险丝”)

日志位置作用
Binlog(归档日志)Server 层记录所有变更(增删改),用于主从复制和数据恢复。逻辑日志(SQL 语句或行数据)
Redo Log(重做日志)InnoDB 层记录物理修改(“在 Page X 偏移 Y 处写入 Z”)。保证事务持久性(崩溃恢复)。WAL(Write-Ahead Logging)技术:先写日志,再写磁盘
Undo Log(回滚日志)InnoDB 层记录修改前的版本,用于事务回滚和MVCC 快照读
5.1 两阶段提交(保证 Binlog + Redo Log 一致性)

text

Redo Log Prepare → 写 Binlog → Redo Log Commit

这是保证 MySQL 崩溃恢复时,主从数据一致的关键机制。

6. 锁机制

6.1 行锁分类
锁类型含义
记录锁(Record Lock)锁定单行记录
间隙锁(Gap Lock)锁定一个范围(不包含记录本身),防止幻读
临键锁(Next-Key Lock)记录锁 + 间隙锁,InnoDB RR 级别默认

面试金句:MySQL 在 RR(可重复读)级别下,通过MVCC(快照读)+Next-Key Lock(当前读)解决了幻读问题。

6.2 死锁
  • 产生条件:循环等待 + 互斥 + 不可抢占 + 请求与保持。

  • 解决方案:按固定顺序访问资源;使用SELECT ... FOR UPDATE时注意顺序;开启innodb_deadlock_detect死锁检测自动回滚。

7. 性能优化(Explain 解读)

Explain 结果中重点看什么?
列名关注点
typeconst>ref>range>index>ALL(全表扫描,要避免)
key实际使用的索引名,NULL代表没走索引
rows预估扫描行数,越小越好
ExtraUsing filesort(需要额外排序,慢)
Using temporary(用了临时表,慢)
Using index(覆盖索引,快)

8. 分库分表

策略说明
垂直分库按业务模块分(订单库、用户库)
垂直分表大字段拆出去,减少单表宽度
水平分表按某个字段取模/范围分到多张表
分表中间件ShardingSphere-JDBC、MyCat

二、Redis 篇

1. 为什么 Redis 这么快?

  1. 纯内存操作(读写都是内存,微秒级)。

  2. 单线程(6.0 之前):避免了上下文切换和锁竞争(但 6.0+ 多线程仅用于网络 I/O)。

  3. I/O 多路复用(epoll):一个线程监听多个 Socket 连接。

  4. 高效的数据结构:SDS、跳表、压缩列表等。

2. 五大基础数据类型 + 底层实现(重点)

数据类型用途底层结构
String缓存、计数器、分布式锁SDS(简单动态字符串)
Hash对象属性、购物车ziplist(元素少)/ hashtable(元素多)
List消息队列、最近 N 条quicklist(双向链表 + ziplist 混合)
Set去重、交并差intset(全整数少)/ hashtable
ZSet排行榜、延时队列ziplist(少)/ skiplist + dict(多)

3. 持久化方式

方式原理优缺点
RDB(快照)全量内存数据写入.rdb文件恢复快,占用小;但可能丢失最后一次快照后的数据
AOF(日志)记录每一条写命令数据更完整(appendfsync always/everysec);文件大,恢复慢
混合持久化(4.0+)RDB + AOF 混合兼顾恢复速度和数据完整性

4. 过期策略 + 淘汰策略

4.1 过期删除策略
策略说明
惰性删除访问时检查,过期才删除
定期删除每 100ms 随机抽取一批带 TTL 的 key 检查并删除
主动淘汰(内存满时)见下方淘汰策略
4.2 内存淘汰策略(maxmemory-policy)
策略说明
noeviction不淘汰,直接返回错误
allkeys-lru在所有 key 中淘汰最近最少使用
volatile-lru在设置过 TTL 的 key 中淘汰 LRU
allkeys-random/volatile-random随机淘汰
volatile-ttl淘汰过期时间最近的 key

大厂主流选型:allkeys-lru(追求命中率)或volatile-lru(只淘汰临时数据)。

5. 缓存三大问题 + 解决方案

5.1 缓存穿透(查不存在的 key)

请求的 key 在 Redis 和 DB 都不存在,绕过缓存直接打 DB。

解决方案:

  • 布隆过滤器(Bloom Filter):先判断 key 是否存在,不存在直接返回。

  • 缓存空值:对不存在的 key 也缓存null,并设短 TTL。

5.2 缓存击穿(热点 key 突然过期)

一个热点 key 过期瞬间,大量请求同时打到 DB。

解决方案:

  • 互斥锁(SETNX):只允许一个线程去查 DB,其他等待/重试。

  • 逻辑过期:Redis 不设物理过期,在 Value 里存过期时间戳,过期时异步更新,当前先返回旧数据。

5.3 缓存雪崩(大批 key 同时过期)

多个 key 同时过期,或 Redis 宕机,大量请求直接打 DB。

解决方案:

  • 过期时间加随机值:避免大量 key 同时过期。

  • 多级缓存:本地缓存(Caffeine)+ Redis 两层。

  • 熔断降级:Redis 挂了直接返回兜底数据,不打 DB。

  • Redis 高可用:主从 + 哨兵 / Cluster 集群。

6. 分布式锁(Redisson + 看门狗)

标准写法(原子性):

bash

SET lock_key unique_value NX EX 30

Redisson 的改进(看门狗 WatchDog):

  • 默认锁有效期 30 秒,业务没执行完自动续期(每 10 秒续一次)。

  • 防止业务执行时间长导致锁自动释放,引发并发问题。

底层依赖:lua脚本保证原子性(判断锁持有者 + 释放锁)。

7. 集群模式

模式适用场景特点
主从复制读写分离一主多从,主写从读。主挂需人工介入
哨兵模式(Sentinel)高可用在主从基础上加哨兵,自动故障转移(选新主)
Cluster 集群海量数据(> 10G)分片(16384 个槽位),多主多从。不支持跨槽位事务

三、面试综合追问:“MySQL 和 Redis 怎么配合使用?”

典型场景:读请求先查 Redis,命中则返回;未命中则查 MySQL,回写 Redis 并返回。

写请求:先更新 MySQL,再删除(或更新)Redis 缓存。

大厂选型:

  • 强一致场景(转账、支付):走 MySQL,不用缓存。

  • 读多写少场景(商品详情、文章):Redis + MySQL,允许短暂不一致。

  • 最终一致方案:订阅 MySQL Binlog(如 Canal),异步更新 Redis,彻底解耦。

🎯 面试金句(背下来直接加分)

  1. MySQL 索引:“B+Tree 的非叶子节点不存数据,叶子节点用链表相连,既支持等值查询,也支持范围查询,磁盘 IO 次数少。”

  2. 事务隔离:“InnoDB 在 RR 级别下,通过 MVCC 快照读 + Next-Key Lock 当前读,解决了幻读问题。”

  3. Redis 快:“单线程 + 内存 + I/O 多路复用 + 高效数据结构,四者缺一不可。”

  4. 缓存三大问题:“穿透用布隆过滤器,击穿用互斥锁或逻辑过期,雪崩用过期随机值 + 熔断降级。”

  5. 分布式锁:“SET NX EX+lua脚本保证原子性,Redisson 看门狗解决锁续期问题。”

把这份笔记刻进脑子里,MySQL + Redis 这块你就可以从容应对绝大多数面试了!如果某个具体点(如 Binlog 的三种格式、跳表原理、哨兵选举过程)想深挖,随时可以继续聊。

碎碎念:后续会更新每天学习的八股和算法 题,开始准备秋招的第58天。努力连续更新100天!以后每天就按,秋招项目【java +agent】,科研,必做项目,算法,八股,锻炼身体来总结。

总结:继续重新看八股了,加油加油

1.算法面试150 118/150 2h

2.秋招项目,【java 项目】,

【agent 项目 】,

3.科研要跑一下,

4.实习;7h

6.背八股,2h

7.锻炼身体,

总结:mysql和redis