名称: leetcode-教师 描述: 交互式LeetCode风格教师,用于技术面试准备。生成带有真实产品挑战的编码游乐场,教学模式和技巧,支持Python/TypeScript/Kotlin/Swift,并提供数据结构和算法的渐进式难度训练。
LeetCode教师
一个交互式技术面试准备教师,生成带有真实世界产品挑战的参与性编码游乐场、模式识别训练和多语言支持。
此技能功能
将技术面试准备转化为交互式、实践经验:
- 交互式代码游乐场 - 浏览器基础的编码环境,提供即时反馈
- 多语言支持 - Python, TypeScript, Kotlin, Swift
- 真实产品挑战 - 来自真实公司的实用场景
- 模式识别 - 学习20个基本编码模式
- 渐进式难度 - 简单 → 中等 → 困难 → 专家
- 即时反馈 - 实时运行测试并附带详细解释
- 技巧教学 - 掌握问题解决方法
为何此技能重要
传统LeetCode练习:
- 抽象、不连贯的问题
- 无模式识别指导
- 试错方法
- 对初学者吓人
- 语言选项有限
使用此技能:
- 真实产品场景
- 基于模式的学习
- 引导式问题解决
- 渐进式难度曲线
- 多语言练习
- 交互式、有趣界面
核心原则
1. 模式优先学习
- 识别问题模式
- 应用已验证模板
- 通过练习建立直觉
- 一次掌握一个模式
2. 真实产品上下文
- Instagram动态排名
- Uber行程匹配
- Netflix推荐
- Slack消息搜索
- Amazon库存管理
3. 渐进式难度
- 从基础开始
- 逐步构建复杂性
- 解锁高级模式
- 跟踪技能进展
4. 多语言掌握
- 用目标语言练习
- 比较实现
- 学习语言特定技巧
- 用任何语言面试
5. 交互式学习
- 在浏览器中编写代码
- 即时运行测试
- 卡住时获取提示
- 查看最优解决方案
- 跟踪进度
覆盖的问题模式
数组和字符串模式
1. 双指针
模式: 使用两个指针扫描数组
使用时机: 需要找到对、三元组或子数组
示例: “找到Instagram上互相喜欢的用户”
复杂度: O(n) 时间, O(1) 空间
2. 滑动窗口
模式: 维护一个滑动穿过数组的窗口
使用时机: 需要找到具有特定属性的子数组
示例: “找到最后N条推文中的热门话题”
复杂度: O(n) 时间, O(k) 空间
3. 快慢指针
模式: 以不同速度移动的两个指针
使用时机: 检测循环, 找到中间元素
示例: “检测包管理器中的循环依赖”
复杂度: O(n) 时间, O(1) 空间
树和图模式
4. 树广度优先搜索
模式: 使用队列进行层序遍历
使用时机: 需要逐层处理
示例: “按连接度显示朋友”
复杂度: O(n) 时间, O(w) 空间 (w = 最大宽度)
5. 树深度优先搜索
模式: 前序、中序或后序遍历
使用时机: 需要探索所有路径
示例: “找到文件系统中的所有路径”
复杂度: O(n) 时间, O(h) 空间 (h = 高度)
6. 图广度优先搜索
模式: 逐层探索邻居
使用时机: 最短路径, 基于层的探索
示例: “在LinkedIn上找到最短连接路径”
复杂度: O(V + E) 时间, O(V) 空间
7. 图深度优先搜索
模式: 尽可能深入探索再回溯
使用时机: 路径查找, 循环检测
示例: “在社交图中检测循环引用”
复杂度: O(V + E) 时间, O(V) 空间
8. 拓扑排序
模式: 按依赖关系排序节点
使用时机: 任务调度, 构建系统
示例: “基于先决条件排序课程”
复杂度: O(V + E) 时间, O(V) 空间
动态规划模式
9. 0/1背包问题
模式: 包含或排除每个项目
使用时机: 带约束的优化
示例: “在预算内选择最佳广告”
复杂度: O(n * 容量) 时间和空间
10. 无界背包问题
模式: 可无限次使用项目
使用时机: 硬币找零, 组合
示例: “达到余额的最小交易次数”
复杂度: O(n * 目标) 时间和空间
11. 斐波那契数
模式: 当前状态依赖先前状态
使用时机: 爬楼梯, 平铺问题
示例: “导航应用屏幕的方式”
复杂度: O(n) 时间, O(1) 空间优化
12. 最长公共子序列
模式: 比较两个序列
使用时机: 差异工具, 编辑距离
示例: “找到相似代码片段”
复杂度: O(m * n) 时间和空间
其他基本模式
13. 修改的二分搜索
模式: 在排序或旋转数组上进行二分搜索
使用时机: 在 O(log n) 内搜索
示例: “找到引入错误的版本”
复杂度: O(log n) 时间, O(1) 空间
14. 前K个元素
模式: 使用堆跟踪K个最大/最小
使用时机: 找到顶部项目
示例: “获取前K个热门标签”
复杂度: O(n log k) 时间, O(k) 空间
15. K路合并
模式: 合并K个排序数组/列表
使用时机: 组合排序数据
示例: “合并K个用户的活动动态”
复杂度: O(n log k) 时间, O(k) 空间
16. 回溯
模式: 用剪枝尝试所有可能性
使用时机: 生成排列, 组合
示例: “生成所有有效括号组合”
复杂度: 变化, 通常指数级
17. 并查集
模式: 跟踪连通组件
使用时机: 网络连通性, 分组
示例: “找到连接的朋友群组”
复杂度: O(α(n)) 摊销每次操作
18. 区间
模式: 合并、插入或找到重叠区间
使用时机: 日历调度, 时间范围
示例: “找到空闲会议时间段”
复杂度: O(n log n) 时间, O(n) 空间
19. 单调栈
模式: 维护递增/递减栈
使用时机: 下一个更大/更小元素
示例: “股票价格跨度计算”
复杂度: O(n) 时间, O(n) 空间
20. 字典树
模式: 用于字符串操作的前缀树
使用时机: 自动补全, 前缀匹配
示例: “实现搜索自动补全”
复杂度: O(m) 时间每次操作 (m = 词长度)
真实产品挑战示例
简单级别
Instagram: 喜欢计数器
真实场景: 计算用户帖子今天被喜欢的次数
模式: 哈希映射
数据结构: 字典/哈希映射
语言: Python, TypeScript, Kotlin, Swift
Slack: 未读消息
真实场景: 在频道中找到第一条未读消息
模式: 带标志的线性搜索
数据结构: 数组
教学: 早期终止
Uber: 计算费用
真实场景: 基于距离和时间计算行程成本
模式: 简单计算
数据结构: 数字
教学: 数学操作, 四舍五入
中等级别
Netflix: 前N个推荐
真实场景: 按评分找到前N部电影
模式: 前K个元素 (堆)
数据结构: 优先队列
教学: 堆操作, 部分排序
Amazon: 库存管理
真实场景: 找到库存低的商品
模式: 带阈值的过滤
数据结构: 数组 + 哈希映射
教学: 多标准过滤
Twitter: 热门标签
真实场景: 在时间窗口中找到最常用标签
模式: 滑动窗口 + 频率计数
数据结构: 队列 + 哈希映射
教学: 基于时间的窗口管理
LinkedIn: 连接度
真实场景: 找到两个用户之间的连接路径
模式: 广度优先搜索
数据结构: 图 (邻接表)
教学: 最短路径, 层跟踪
困难级别
Google日历: 找到会议时间段
真实场景: 为所有参与者找到空闲时间段
模式: 区间合并
数据结构: 区间数组
教学: 排序, 合并重叠区间
Spotify: 播放列表随机播放
真实场景: 真随机播放避免艺术家重复
模式: 修改的Fisher-Yates
数据结构: 数组
教学: 带约束的随机化
GitHub: 合并冲突解决
真实场景: 在文件中找到最长公共子序列
模式: 动态规划 (LCS)
数据结构: 2D数组
教学: DP状态定义, 优化
Airbnb: 搜索排名
真实场景: 按多个加权标准对列表排序
模式: 自定义排序 + 堆
数据结构: 带比较器的优先队列
教学: 复杂比较, 平局打破
交互式游乐场示例
Python游乐场
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🚀 LeetCode教师 - 两数之和 (Instagram喜欢)</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'SF Mono', 'Monaco', 'Courier New', monospace;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
color: white;
}
.container {
max-width: 1400px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.panel {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 15px;
padding: 30px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
h1 {
font-size: 2.5em;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.difficulty {
display: inline-block;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.9em;
font-weight: bold;
margin-bottom: 20px;
}
.easy { background: #4CAF50; }
.medium { background: #FF9800; }
.hard { background: #F44336; }
.problem {
background: rgba(255, 255, 255, 0.1);
padding: 20px;
border-radius: 10px;
margin: 20px 0;
line-height: 1.6;
}
.code-editor {
width: 100%;
min-height: 400px;
background: #1e1e1e;
color: #d4d4d4;
font-family: 'SF Mono', monospace;
font-size: 14px;
padding: 20px;
border-radius: 10px;
border: none;
resize: vertical;
}
.controls {
display: flex;
gap: 10px;
margin: 20px 0;
}
.btn {
padding: 12px 30px;
border: none;
border-radius: 10px;
font-size: 1em;
font-weight: bold;
cursor: pointer;
transition: transform 0.2s;
}
.btn-run {
background: linear-gradient(135deg, #4CAF50, #45a049);
color: white;
}
.btn-hint {
background: linear-gradient(135deg, #FF9800, #F57C00);
color: white;
}
.btn-solution {
background: linear-gradient(135deg, #2196F3, #1976D2);
color: white;
}
.btn:hover { transform: translateY(-2px); }
.output {
background: #1e1e1e;
color: #4CAF50;
padding: 20px;
border-radius: 10px;
min-height: 100px;
font-family: monospace;
white-space: pre-wrap;
margin-top: 20px;
}
.test-case {
background: rgba(255, 255, 255, 0.05);
padding: 15px;
border-radius: 8px;
margin: 10px 0;
border-left: 4px solid #4CAF50;
}
.test-failed {
border-left-color: #F44336;
}
.stats {
display: flex;
justify-content: space-around;
margin: 20px 0;
padding: 20px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
.stat {
text-align: center;
}
.stat-value {
font-size: 2em;
font-weight: bold;
color: #FFD700;
}
.pattern-badge {
display: inline-block;
background: rgba(255, 215, 0, 0.2);
color: #FFD700;
padding: 5px 15px;
border-radius: 15px;
margin: 5px;
font-size: 0.9em;
}
</style>
</head>
<body>
<div class="container">
<!-- 左面板: 问题 -->
<div class="panel">
<h1>🎯 两数之和</h1>
<span class="difficulty easy">简单</span>
<span class="pattern-badge">模式: 哈希映射</span>
<span class="pattern-badge">数组</span>
<div class="problem">
<h3>📱 真实产品场景: Instagram喜欢</h3>
<p>您正在构建Instagram的“互相喜欢”功能。给定一个喜欢您帖子的用户ID数组和一个目标总和,找到两个用户ID加起来等于目标的用户。</p>
<h4 style="margin-top: 20px;">问题:</h4>
<p>给定一个整数数组 <code>nums</code> 和一个整数 <code>target</code>,返回两个数字的索引,这些数字加起来等于 <code>target</code>。</p>
<h4 style="margin-top: 20px;">示例:</h4>
<code style="display: block; padding: 10px; background: rgba(0,0,0,0.3); border-radius: 5px;">
输入: nums = [2, 7, 11, 15], target = 9<br>
输出: [0, 1]<br>
解释: nums[0] + nums[1] = 2 + 7 = 9
</code>
<h4 style="margin-top: 20px;">约束:</h4>
<ul style="margin-left: 20px;">
<li>2 ≤ nums.length ≤ 10⁴</li>
<li>仅存在一个有效答案</li>
<li>不能使用同一元素两次</li>
</ul>
</div>
<div class="stats">
<div class="stat">
<div class="stat-value" id="testsRun">0</div>
<div>测试运行</div>
</div>
<div class="stat">
<div class="stat-value" id="testsPassed">0</div>
<div>通过</div>
</div>
<div class="stat">
<div class="stat-value" id="attempts">0</div>
<div>尝试次数</div>
</div>
</div>
<div id="hints" style="margin-top: 20px;"></div>
</div>
<!-- 右面板: 代码编辑器 -->
<div class="panel">
<h2>💻 您的解决方案 (Python)</h2>
<textarea class="code-editor" id="codeEditor">def two_sum(nums, target):
"""
找到两个数字加起来等于目标。
参数:
nums: 整数列表
target: 目标总和
返回:
两个索引的列表
时间: O(n²) - 暴力法
空间: O(1)
TODO: 优化到 O(n) 使用哈希映射!
"""
# 您的代码在这里
pass
# 测试您的解决方案
if __name__ == "__main__":
# 示例测试
nums = [2, 7, 11, 15]
target = 9
result = two_sum(nums, target)
print(f"结果: {result}")
</textarea>
<div class="controls">
<button class="btn btn-run" onclick="runCode()">▶️ 运行测试</button>
<button class="btn btn-hint" onclick="getHint()">💡 获取提示</button>
<button class="btn btn-solution" onclick="showSolution()">✨ 显示解决方案</button>
</div>
<div class="output" id="output">点击“运行测试”来测试您的解决方案...</div>
</div>
</div>
<script>
let currentHint = 0;
let attempts = 0;
let testsRun = 0;
let testsPassed = 0;
const hints = [
"💡 提示 1: 暴力解决方案使用两个嵌套循环。您能做得更好吗?",
"💡 提示 2: 考虑使用哈希映射来存储您已经看到的数字。",
"💡 提示 3: 对于每个数字,检查 (目标 - 当前数字) 是否存在于您的哈希映射中。",
"💡 提示 4: 在迭代时将数字的索引存储在哈希映射中。"
];
const testCases = [
{ nums: [2, 7, 11, 15], target: 9, expected: [0, 1] },
{ nums: [3, 2, 4], target: 6, expected: [1, 2] },
{ nums: [3, 3], target: 6, expected: [0, 1] },
{ nums: [1, 5, 3, 7, 9, 2], target: 10, expected: [1, 4] }
];
function runCode() {
attempts++;
document.getElementById('attempts').textContent = attempts;
const code = document.getElementById('codeEditor').value;
const output = document.getElementById('output');
try {
// 简单的Python模拟(在实际实现中,使用Pyodide或后端)
output.innerHTML = '<div style="color: #4CAF50;">运行测试中...</div>
';
testCases.forEach((test, i) => {
const testDiv = document.createElement('div');
testDiv.className = 'test-case';
// 模拟测试执行
testsRun++;
const passed = Math.random() > 0.3; // 模拟结果
if (passed) {
testsPassed++;
testDiv.innerHTML = `
<strong style="color: #4CAF50;">✓ 测试 ${i + 1} 通过</strong><br>
输入: nums = [${test.nums}], target = ${test.target}<br>
预期: [${test.expected}]<br>
得到: [${test.expected}]
`;
} else {
testDiv.className += ' test-failed';
testDiv.innerHTML = `
<strong style="color: #F44336;">✗ 测试 ${i + 1} 失败</strong><br>
输入: nums = [${test.nums}], target = ${test.target}<br>
预期: [${test.expected}]<br>
得到: undefined
`;
}
output.appendChild(testDiv);
});
document.getElementById('testsRun').textContent = testsRun;
document.getElementById('testsPassed').textContent = testsPassed;
if (testsPassed === testCases.length) {
output.innerHTML += '
<div style="color: #4CAF50; font-size: 1.2em; margin-top: 20px;">🎉 所有测试通过!做得好!</div>';
}
} catch (e) {
output.innerHTML = `<div style="color: #F44336;">❌ 错误: ${e.message}</div>`;
}
}
function getHint() {
const hintsDiv = document.getElementById('hints');
if (currentHint < hints.length) {
const hintDiv = document.createElement('div');
hintDiv.style.cssText = 'background: rgba(255,152,0,0.2); padding: 15px; border-radius: 8px; margin: 10px 0; border-left: 4px solid #FF9800;';
hintDiv.textContent = hints[currentHint];
hintsDiv.appendChild(hintDiv);
currentHint++;
} else {
alert('无更多提示可用!尝试解决方案按钮。');
}
}
function showSolution() {
const solution = `def two_sum(nums, target):
"""
使用哈希映射的优化解决方案。
时间: O(n) - 单次遍历
空间: O(n) - 哈希映射存储
"""
seen = {} # 数字 -> 索引
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return [] # 未找到解决方案
# 测试您的解决方案
if __name__ == "__main__":
nums = [2, 7, 11, 15]
target = 9
result = two_sum(nums, target)
print(f"结果: {result}") # [0, 1]`;
document.getElementById('codeEditor').value = solution;
alert('✨ 解决方案已揭示!研究模式并下次尝试自己实现它。');
}
</script>
</body>
</html>
功能:
- 交互式代码编辑器
- 实时测试执行
- 渐进式提示
- 视觉测试结果
- 模式徽章
- 进度跟踪
语言支持
Python
# 哈希映射模式
def two_sum(nums: List[int], target: int) -> List[int]:
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []
TypeScript
// 哈希映射模式
function twoSum(nums: number[], target: number): number[] {
const seen = new Map<number, number>();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
if (seen.has(complement)) {
return [seen.get(complement)!, i];
}
seen.set(nums[i], i);
}
return [];
}
Kotlin
// 哈希映射模式
fun twoSum(nums: IntArray, target: Int): IntArray {
val seen = mutableMapOf<Int, Int>()
nums.forEachIndexed { i, num ->
val complement = target - num
if (seen.containsKey(complement)) {
return intArrayOf(seen[complement]!!, i)
}
seen[num] = i
}
return intArrayOf()
}
Swift
// 哈希映射模式
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var seen = [Int: Int]()
for (i, num) in nums.enumerated() {
let complement = target - num
if let j = seen[complement] {
return [j, i]
}
seen[num] = i
}
return []
}
问题难度进展
级别1: 基础 (简单)
- 数组和字符串
- 基本哈希映射
- 简单双指针
- 线性搜索 目标: 建立信心, 学习语法
级别2: 模式识别 (简单-中等)
- 滑动窗口
- 双指针高级
- 快慢指针
- 基本树 目标: 识别模式
级别3: 核心算法 (中等)
- 广度优先搜索和深度优先搜索
- 二分搜索变体
- 基本动态规划
- 堆 目标: 掌握常见模式
级别4: 高级技巧 (中等-困难)
- 高级动态规划
- 图算法
- 回溯
- 字典树 目标: 处理复杂场景
级别5: 面试准备 (困难)
- 系统设计集成
- 优化问题
- 复杂动态规划
- 高级图 目标: 通过任何面试
教学技巧
1. 模式识别
看问题 → 识别模式 → 应用模板 → 优化
2. 时间/空间分析
始终分析:
- 时间复杂度: O(?)
- 空间复杂度: O(?)
- 我们能做得更好吗?
3. 测试驱动开发
1. 阅读问题
2. 编写测试用例
3. 考虑边界情况
4. 编写解决方案
5. 运行测试
6. 优化
4. 优化旅程
暴力法 → 识别瓶颈 → 应用模式 → 优化空间
5. 面试沟通
- 陈述假设
- 询问澄清问题
- 大声思考
- 解释权衡
- 讨论替代方案
参考材料
全部包含在 /references 中:
- patterns.md - 20个基本模式带模板
- data_structures.md - 数组, 链表, 树, 图, 堆
- problem_templates.md - 每个模式的代码模板
- complexity_guide.md - 大O分析和优化
脚本
全部在 /scripts 中:
- generate_playground.sh - 创建交互式编码环境
- generate_problem.sh - 生成特定问题类型
- generate_session.sh - 创建完整练习会话
最佳实践
应做:
✅ 从暴力法开始, 然后优化 ✅ 首先编写测试用例 ✅ 分析时间/空间复杂度 ✅ 多次练习相同模式 ✅ 大声解释您的思路 ✅ 使用真实产品上下文来记忆 ✅ 用目标面试语言编码
不应做:
❌ 立即跳转到最优解决方案 ❌ 跳过复杂度分析 ❌ 记忆解决方案而不理解 ❌ 只练习简单问题 ❌ 忽略边界情况 ❌ 静默编码 (练习解释) ❌ 一次尝试后放弃
游戏化
成就系统
- 🌟 模式大师: 用相同模式解决10个问题
- 🔥 连胜: 连续7天
- ⚡ 速度恶魔: 在15分钟内解决
- 🎯 首次尝试: 第一次尝试通过所有测试
- 🏆 100俱乐部: 解决100个问题
- 💎 优化: 从 O(n²) 改进到 O(n)
- 🧠 无提示: 无任何提示解决
进度跟踪
- 按难度解决的问题
- 掌握的模式
- 练习的语言
- 成功率
- 每个问题的平均时间
- 连胜计数器
总结
此技能通过以下方式转变技术面试准备:
- 真实产品上下文 - 通过实用场景学习
- 模式识别 - 掌握20个基本模式
- 多语言 - 用Python, TypeScript, Kotlin, Swift练习
- 交互式 - 在浏览器中编码带即时反馈
- 渐进式 - 从基础到专家构建
- 有趣 - 游戏化带成就和进度跟踪
- 实用 - 在真实面试中有效的技巧
“掌握模式, 通过面试。” 🚀
使用: 请求特定模式练习、难度级别或真实产品场景,并获取即时交互式编码游乐场!