🔄 复习日 / Review Day — Day 70
📊 NeetCode: 58/150 · SysDesign: 57/40 · Behavioral: 57/40 · Frontend: 37/50 · AI: 28/30
🔥 4-day streak!
今天是复习日!回顾过去4天的内容。
Today is review day! Let's revisit the past 4 days.
回顾主题 / Topics covered (Days 66–69):
- 🏗️ Web Search Autocomplete · Rate Limiter as a Service · Distributed Tracing · Secrets Management
- 💻 Count Good Nodes · Validate BST · Kth Smallest in BST · Construct BT from Pre+Inorder
- 🗣️ Raising concerns on direction · Individual vs team enablement · Quarterly goals · Advocating for juniors
- 🐍 State Machine · Repository Pattern · Descriptors (@property) · Metaclasses
- 🤖 AI in Production · Open Source vs Closed LLMs
📝 Quick Quiz — 3 Mini-Reviews
Q1: [🏗️ System Design] 在设计分布式追踪系统 (Jaeger/Zipkin) 时,Trace ID 是如何在服务之间传播的?它解决了什么核心问题?
When designing a distributed tracing system like Jaeger or Zipkin, how is the Trace ID propagated between services? What core problem does it solve?
<details><summary>显示答案 / Show Answer</summary>
Trace ID 通过 HTTP header(如 X-B3-TraceId、W3C traceparent)或 gRPC metadata 在服务之间传递——每个服务调用下游时必须将其带入请求头。它解决的核心问题是分布式系统的可观测性:在微服务架构中,一个请求可能跨越十几个服务,单看日志无法判断哪里慢、哪里出错。Trace ID 将所有 Span 串联成一棵完整的调用树,让你能一眼看出延迟在哪个服务中产生。
The Trace ID is propagated via HTTP headers (e.g., X-B3-TraceId, W3C traceparent) or gRPC metadata — each service must forward it when calling downstream services. This solves the core observability problem in distributed systems: a single user request may traverse a dozen services, and logs alone can't tell you where latency or failures occurred. The Trace ID stitches all Spans into a complete call tree, making bottlenecks immediately visible.
</details>
Q2: [💻 Algorithms] 从前序遍历 (Preorder) 和中序遍历 (Inorder) 重建二叉树时,关键洞察是什么?时间复杂度如何?
When constructing a binary tree from Preorder and Inorder traversals, what is the key insight? What is the time complexity?
<details><summary>显示答案 / Show Answer</summary>
关键洞察有两点:① 前序遍历的第一个元素永远是当前子树的根节点;② 在中序遍历中找到该根节点,其左边的元素都属于左子树,右边属于右子树。用 HashMap 预存中序遍历的值→下标映射可将查找根节点的操作从 O(n) 降至 O(1),整体时间复杂度 O(n),空间复杂度 O(n)(HashMap + 递归调用栈)。
def buildTree(preorder, inorder):
idx_map = {val: i for i, val in enumerate(inorder)}
def build(pre_l, pre_r, in_l, in_r):
if pre_l > pre_r:
return None
root_val = preorder[pre_l]
root = TreeNode(root_val)
mid = idx_map[root_val]
left_size = mid - in_l
root.left = build(pre_l+1, pre_l+left_size, in_l, mid-1)
root.right = build(pre_l+left_size+1, pre_r, mid+1, in_r)
return root
return build(0, len(preorder)-1, 0, len(inorder)-1)
Two key insights: ① The first element of Preorder is always the root of the current subtree; ② Finding that root in Inorder splits the array into left and right subtrees. Pre-building a HashMap of value→index reduces each root lookup from O(n) to O(1), giving overall O(n) time and O(n) space (HashMap + call stack).
</details>
Q3: [🐍 Python Craft] Python 中的描述符 (Descriptor) 协议是什么?@property 是如何基于描述符实现的?什么时候应该直接写描述符而不是用 @property?
What is Python's Descriptor protocol? How does @property build on it? When should you write a raw descriptor instead of using @property?
<details><summary>显示答案 / Show Answer</summary>
描述符是实现了 get、set、delete 中至少一个方法的类。当你访问实例属性时,Python 会先检查类的 dict 中是否有描述符,若有则调用描述符的 get 而非直接返回值。@property 是 Python 内置的描述符工厂——它把一个普通函数包装成只读(get)或可读写(加上 setter)的描述符。
应该写原生描述符而非 @property 的场景:
- 同一验证逻辑需要复用到多个类的多个属性(@property 每次都要重写)
- 需要元数据感知(如 ORM 字段:
name = CharField(max_length=100)) - 构建框架级别的抽象(如 SQLAlchemy Column、Django Field)
class PositiveInt:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, objtype=None):
return obj.__dict__.get(self.name)
def __set__(self, obj, value):
if value <= 0:
raise ValueError(f"{self.name} must be positive")
obj.__dict__[self.name] = value
class Product:
price = PositiveInt() # reuse across any class
stock = PositiveInt()
A descriptor is any class implementing get, set, or delete. On attribute access, Python checks if the class dict holds a descriptor and calls get instead of returning the raw value. @property is simply Python's built-in descriptor factory wrapping a function. Write a raw descriptor when: the same validation logic needs to be reused across many attributes or classes, you need ORM-style field metadata, or you're building a framework abstraction (SQLAlchemy Column, Django Field).
</details>
💡 复习巩固记忆,螺旋式上升。Spaced repetition builds lasting knowledge.
📅 明天继续新内容!Tomorrow: Day 71, new content!