🔄 复习日 Day 15 / Review Day 15
📊 进度 / Progress: Day 15/150 · NeetCode: 14/150 · SysDesign: 13/40 · Behavioral: 13/40 · Frontend: 13/50 · AI: 6/30
🔥 4-day streak!
今天是复习日!回顾过去4天的内容。
Today is a review day! Let's revisit the past 4 days of content.
回顾范围 / Review scope: Days 11–14
- 🏗️ Consistent Hashing, CAP Theorem, Message Queues, Microservices vs Monolith
- 💻 Two Sum II, 3Sum, Container With Most Water, Trapping Rain Water
- 🗣️ Proactive problem-solving, Prioritization, Delivering bad news, Cross-team initiatives
- 🎨 React useEffect, useRef, useMemo/useCallback, Custom Hooks
- 🤖 AI News, RLHF, AI News, LoRA & QLoRA
📝 Quick Quiz — 3 Mini-Reviews
Q1: [🏗️ System Design — Consistent Hashing & CAP Theorem]
你在设计一个分布式缓存系统(比如 Redis Cluster)。当一个节点崩溃时,使用普通哈希(hash(key) % N)和一致性哈希(Consistent Hashing)各会发生什么?为什么分布式数据库(如 Cassandra)选择 Eventual Consistency 而不是强一致性?
You're designing a distributed cache (like Redis Cluster). When one node goes down, what happens with regular hashing (hash(key) % N) vs consistent hashing? And why do databases like Cassandra prefer eventual consistency over strong consistency?
<details><summary>显示答案 / Show Answer</summary>
普通哈希的问题 / Regular hashing problem:
当节点数 N 变化(比如从 5 变成 4),几乎所有的 key 都需要重新映射到不同节点 — 导致大规模缓存失效(cache stampede)。
When N changes (5→4), nearly all keys get remapped to different nodes — causing a massive cache miss storm.
一致性哈希的优势 / Consistent hashing advantage:
将节点和 key 都映射到一个"哈希环"上。某节点下线时,只有该节点顺时针方向的 key 需要迁移到下一个节点,其他 key 完全不受影响。通常只影响 1/N 的数据。
Both nodes and keys are mapped onto a ring. When a node goes down, only the keys between the failed node and its predecessor need to migrate to the next node clockwise — roughly 1/N of all keys.
Virtual nodes (VNodes) 虚拟节点进一步让每个物理节点在哈希环上占据多个位置,使数据分布更均匀。
CAP & Eventual Consistency:
CAP 定理说在网络分区(P)发生时,你必须在一致性(C)和可用性(A)之间选一个。Cassandra 选择 AP(可用性 + 分区容忍),允许暂时不一致,通过后台的 gossip protocol 和 hinted handoff 最终达到一致。这对"写多读多"场景更实用 — 写入不会因为网络抖动而失败。
CAP says during a network partition, choose C or A. Cassandra picks AP (availability + partition tolerance), accepting that different replicas may briefly disagree. Background reconciliation (gossip, read repair, hinted handoff) eventually converges. For high-traffic apps, "eventually consistent" is a feature — writes don't fail just because one replica is slow.
核心记忆点 / Key insight: Consistent hashing = minimal redistribution. CAP = pick your tradeoff explicitly.
</details>
Q2: [💻 Algorithms — Two Pointers: Container With Most Water vs Trapping Rain Water]
两道题都用双指针,都涉及"水",但思路有微妙差别。Container With Most Water(#11)和 Trapping Rain Water(#42)的关键区别是什么?为什么前者一次遍历就够,后者需要追踪历史最大值?
Both problems use two pointers and involve "water", but the logic is subtly different. What's the key difference between Container With Most Water (#11) and Trapping Rain Water (#42)? Why does the first need only one pass while the second requires tracking historical maximums?
<details><summary>显示答案 / Show Answer</summary>
Container With Most Water (#11) — 选最大容器:
你在两个柱子之间装水,水量 = min(left, right) * distance。双指针从两端向中间移动,每次移动较短的那端 — 因为较长端已经尽力了,继续缩小宽度只有移动短板才有可能增加面积。
You're choosing two walls. Water volume = min(left, right) * width. Move the shorter pointer inward — the taller wall can't improve the result unless the other wall gets taller. This greedy choice is provably correct.
Trapping Rain Water (#42) — 计算每个格子的积水:
每个位置能接的水 = min(leftMax, rightMax) - height[i]。关键是每个位置都受其左右两侧最高柱子的限制,需要知道历史最大值。
双指针做法:维护 leftMax 和 rightMax,哪侧较小就处理哪侧(因为较小侧的瓶颈已经确定)。
Every cell can hold water = min(leftMax, rightMax) - height[i]. Each cell is bounded by the tallest wall on BOTH sides — you must track running maximums. Two-pointer trick: whichever side has the smaller max, process it (its bottleneck is determined regardless of the other side's future values).
核心区别 / Core difference:
- Container: 两点之间 的最大矩形,贪心移动短板 ✓
- Trapping: 每个点 上方的积水,需要双侧历史最大值 ✓
记忆口诀: Container = "短板决定上限,移短板求最大";Trapping = "每格水位 = 两侧最高墙的最小值 − 自身高度"
</details>
Q3: [🎨 Frontend — React Hooks: useEffect, useRef, useMemo/useCallback, Custom Hooks]
你在做一个数据密集型 dashboard,需要:
- 在组件挂载时 fetch 数据并在卸载时取消请求
- 直接操作一个 DOM 元素(聚焦输入框)而不触发重渲染
- 避免昂贵的排序函数在每次渲染时重复执行
- 把上面的 fetch 逻辑复用到多个组件
请说明应该用哪个 Hook,以及最常见的错误写法。
You're building a data-heavy dashboard and need to: (1) fetch data on mount and cancel on unmount, (2) focus a DOM element without triggering re-renders, (3) avoid re-running an expensive sort on every render, (4) reuse the fetch logic across components. Which hook for each, and what's the most common mistake?
<details><summary>显示答案 / Show Answer</summary>
1. Fetch + 取消请求 → useEffect
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal }).then(setData);
return () => controller.abort(); // cleanup!
}, [url]); // dependency array matters!
❌ 最常见错误:省略 cleanup,导致组件卸载后仍然 setState,产生内存泄漏和 "Can't perform a React state update on an unmounted component" 警告。
❌ Most common mistake: forgetting the cleanup function, causing state updates on unmounted components.
2. 操作 DOM → useRef
const inputRef = useRef(null);
// inputRef.current.focus() — doesn't trigger re-render
useRef 的值改变不会触发重渲染,适合存储 DOM 引用、定时器 ID、或任何"不影响 UI"的可变值。
Changing .current never triggers a re-render — perfect for DOM refs, timer IDs, or previous values.
3. 避免重复计算 → useMemo
const sorted = useMemo(() => expensiveSort(data), [data]);
❌ 过度使用 useMemo 反而增加开销。只在真正昂贵的计算或引用稳定性(传给子组件)时使用。
❌ Over-memoizing adds overhead. Only use for genuinely expensive computations or referential stability.
4. 复用逻辑 → Custom Hook
function useDashboardData(url) {
const [data, setData] = useState(null);
useEffect(() => { /* fetch logic */ }, [url]);
return data;
}
Custom hooks = 把 hook 逻辑从组件里提取出来,不是 HOC,不是 render props,就是普通函数(必须以 use 开头)。
Custom hooks extract stateful logic — not a new React feature, just a naming convention (use prefix) that signals to React's linter.
记忆矩阵 / Memory matrix:
| Goal | Hook |
|---|---|
| Side effects, fetch, subscriptions | useEffect |
| DOM access, mutable value (no re-render) | useRef |
| Expensive computation cache | useMemo |
| Stable function reference | useCallback |
| Reusable stateful logic | Custom Hook |
</details>
💡 复习巩固记忆,螺旋式上升。每次回顾不只是"记住了吗",而是"能用自己的话解释吗"。
Review doesn't just ask "do you remember?" — it asks "can you explain it in your own words?"
📅 明天继续新内容!Day 16 coming tomorrow!
Generated by byte-by-byte · Day 15 of 150 · 2026-04-01