最近 Google VO 高频出现这道 Config Diff 系统 题目,看似简单的字典比较,实则是一道 层层递进的工程设计题。
很多同学第一版写完就松了口气,结果被 3 轮 Followup 打得措手不及。今天 oavoservice 带你完整拆解这道题,从基础版到生产级实现。
📋 题目描述
给定两个嵌套字典 left 和 right,比较它们并输出一个包含三个部分的结果字典:
- added — 右边新增的 key
- deleted — 右边删除的 key
- edited — 两边都有但值不同的 key
🎯 面试流程还原
第一步:Clarify(关键!)
面试官一开始会让你 clarify,这里一定要问清楚:
- Q: Value 可以是嵌套字典吗?
- A: 一开始不需要考虑 nested,所有 value 都是基本类型
- Q: Value 可以是 list/array 吗?
- A: 不需要考虑
💡 oavoservice 提醒: Clarify 阶段决定了你的第一版代码复杂度。先从简单版本开始,为后续 Followup 留出空间。
✅ 基础版:扁平字典比较
思路
三次遍历:
- 遍历
left的 key,找 deleted 和 edited - 遍历
right的 key,找 added
oavoservice 满分解法
def config_diff(left: dict, right: dict) -> dict:
result = {
"added": {},
"deleted": {},
"edited": {}
}
# 找 deleted 和 edited
for key in left:
if key not in right:
result["deleted"][key] = left[key]
elif left[key] != right[key]:
result["edited"][key] = {"old": left[key], "new": right[key]}
# 找 added
for key in right:
if key not in left:
result["added"][key] = right[key]
return result
示例
left = {"a": 1, "b": 2, "c": 3}
right = {"a": 1, "b": 5, "d": 4}
# Output:
{
"added": {"d": 4},
"deleted": {"c": 3},
"edited": {"b": {"old": 2, "new": 5}}
}
复杂度分析
- Time: O(n + m),n 和 m 分别是 left 和 right 的 key 数量
- Space: O(n + m),存储结果
测试用例设计
面试官会问你如何设计 test case:
- 空字典 —
{}, {}→ 全空 - 完全相同 —
{"a": 1}, {"a": 1}→ 全空 - 完全不同 —
{"a": 1}, {"b": 2}→ deleted + added - 只有 edited —
{"a": 1}, {"a": 2} - 混合情况 — added + deleted + edited 都有
🚀 Followup 1:支持 Nested Dictionary
题目变化
现在 value 可以是嵌套字典,需要递归比较。
核心思路
- 如果两边都是 dict → 递归比较
- 如果一边是 dict 一边不是 → 视为 edited
- 其他情况 → 基础比较逻辑
oavoservice 满分解法
def config_diff_nested(left: dict, right: dict) -> dict:
result = {
"added": {},
"deleted": {},
"edited": {}
}
all_keys = set(left.keys()) | set(right.keys())
for key in all_keys:
left_val = left.get(key)
right_val = right.get(key)
if key not in left:
# Added
result["added"][key] = right_val
elif key not in right:
# Deleted
result["deleted"][key] = left_val
elif isinstance(left_val, dict) and isinstance(right_val, dict):
# 递归比较嵌套字典
nested_diff = config_diff_nested(left_val, right_val)
# 只有非空的部分才加入结果
if any(nested_diff.values()):
result["edited"][key] = nested_diff
elif left_val != right_val:
# 值不同(包括类型不同)
result["edited"][key] = {"old": left_val, "new": right_val}
return result
示例
left = {
"db": {"host": "localhost", "port": 3306},
"cache": {"enabled": True}
}
right = {
"db": {"host": "prod.db.com", "port": 3306},
"cache": {"enabled": True, "ttl": 300}
}
# Output:
{
"added": {},
"deleted": {},
"edited": {
"db": {
"added": {},
"deleted": {},
"edited": {"host": {"old": "localhost", "new": "prod.db.com"}}
},
"cache": {
"added": {"ttl": 300},
"deleted": {},
"edited": {}
}
}
}
🚀 Followup 2:支持 List 作为 Value
题目变化
现在 value 可以是 list,如何处理?
讨论要点(面试官想听的)
这里面试官不一定要你实现,更想听你的设计思考:
简单方案:整体比较
- 两个 list 直接
==比较 - 不同就算 edited,记录 old/new
- 两个 list 直接
复杂方案:元素级别比较
- 需要定义"相同元素"的标准
- 如果 list 元素是 dict,可能需要 ID 字段来匹配
- 类似 React 的 key 概念
顺序敏感 vs 顺序无关
[1, 2, 3]vs[3, 2, 1]是否相同?
oavoservice 推荐实现(整体比较版)
def config_diff_with_list(left: dict, right: dict) -> dict:
result = {"added": {}, "deleted": {}, "edited": {}}
all_keys = set(left.keys()) | set(right.keys())
for key in all_keys:
left_val = left.get(key)
right_val = right.get(key)
if key not in left:
result["added"][key] = right_val
elif key not in right:
result["deleted"][key] = left_val
elif isinstance(left_val, dict) and isinstance(right_val, dict):
nested_diff = config_diff_with_list(left_val, right_val)
if any(nested_diff.values()):
result["edited"][key] = nested_diff
elif isinstance(left_val, list) and isinstance(right_val, list):
# List 整体比较
if left_val != right_val:
result["edited"][key] = {"old": left_val, "new": right_val}
elif left_val != right_val:
result["edited"][key] = {"old": left_val, "new": right_val}
return result
🚀 Followup 3:Alternative Output Structure
题目变化
面试官可能要求换一种输出格式,比如:
Flat Path 格式:
{
"added": ["cache.ttl"],
"deleted": ["old_key"],
"edited": ["db.host"]
}
或带路径的详细格式:
[
{"path": "db.host", "type": "edited", "old": "localhost", "new": "prod.db.com"},
{"path": "cache.ttl", "type": "added", "value": 300}
]
oavoservice 满分解法(Flat Path 版)
def config_diff_flat(left: dict, right: dict, prefix: str = "") -> dict:
result = {"added": [], "deleted": [], "edited": []}
all_keys = set(left.keys()) | set(right.keys())
for key in all_keys:
path = f"{prefix}.{key}" if prefix else key
left_val = left.get(key)
right_val = right.get(key)
if key not in left:
result["added"].append(path)
elif key not in right:
result["deleted"].append(path)
elif isinstance(left_val, dict) and isinstance(right_val, dict):
nested = config_diff_flat(left_val, right_val, path)
result["added"].extend(nested["added"])
result["deleted"].extend(nested["deleted"])
result["edited"].extend(nested["edited"])
elif left_val != right_val:
result["edited"].append(path)
return result
💡 面试官真正考察的是什么?
这道题不只是考算法,更考察:
- Clarification 能力 — 先问清楚再写
- 递归思维 — 处理嵌套结构
- 边界条件 — 类型不匹配、空值处理
- 工程思维 — 输出格式设计、可扩展性
- Trade-off 讨论 — List 比较的多种方案
🤯 常见翻车点
- 第一版写太复杂 — 一开始就考虑 nested,浪费时间
- 递归没处理好返回值 — 嵌套结果为空时的处理
- 类型判断遗漏 — 一边是 dict 一边不是的情况
- Followup 讨论太浅 — List 比较只说一种方案
🚀 oavoservice:你的 Google VO 全程护航
Google 面试的特点是 层层 Followup,一道题能追问 30-45 分钟。很多同学基础版写得不错,但在 Followup 阶段被问懵。
oavoservice 的 VO 实时辅助 可以帮你:
✅ 实时思路提醒 — Followup 方向预判
✅ 边界条件提示 — 避免遗漏关键 case
✅ 讨论要点准备 — Trade-off 分析支持
✅ 全程不干扰 — 适配 Google Meet / Zoom
不要让一个 Followup 断送你的 Google offer。
We consistently provide professional interview assistance services for major tech companies like Google, Meta, Amazon, and TikTok. Feel free to contact us if you're interested.
👉 立即添加微信:Coding0201
锁定你的 Google 面试机会!