chore: import zh skill code-mentor
This commit is contained in:
@@ -0,0 +1,376 @@
|
||||
# Code Mentor - AI 编程导师
|
||||
|
||||
一款全面的 OpenClaw 技能,通过互动教学、代码审查、调试指导和动手实践来学习编程。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 🎓 8 种教学模式
|
||||
|
||||
1. **概念学习** - 通过渐进式示例学习编程概念
|
||||
2. **代码审查与重构** - 获取代码反馈并获得引导式改进
|
||||
3. **调试侦探** - 使用苏格拉底式方法学习调试(不直接给答案!)
|
||||
4. **算法练习** - 掌握数据结构和算法
|
||||
5. **项目指导** - 在架构指导下设计和构建项目
|
||||
6. **设计模式** - 学习何时以及如何应用设计模式
|
||||
7. **面试准备** - 练习编程面试和系统设计
|
||||
8. **语言学习** - 通过从熟悉的语言映射来学习新语言
|
||||
|
||||
### 📚 综合参考资料
|
||||
|
||||
- **算法**:15 种以上常见模式(双指针、滑动窗口、DFS/BFS、动态规划等)
|
||||
- **数据结构**:数组、字符串、树、图、堆
|
||||
- **设计模式**:创建型、结构型、行为型模式及示例
|
||||
- **语言**:Python 和 JavaScript 快速参考
|
||||
- **最佳实践**:整洁代码、SOLID 原则、测试策略
|
||||
|
||||
### 🛠️ 实用脚本
|
||||
|
||||
- **`analyze_code.py`**:静态代码分析,检测错误、风格、复杂度、安全问题
|
||||
- **`run_tests.py`**:执行测试并输出格式化结果(pytest、unittest、jest)
|
||||
- **`complexity_analyzer.py`**:使用大 O 表示法分析时间/空间复杂度
|
||||
|
||||
## 安装
|
||||
|
||||
### 环境要求
|
||||
|
||||
```bash
|
||||
# 用于脚本功能(可选)
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
该技能无需脚本也能完美运行——脚本是可选的增强功能!
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 快速入门
|
||||
|
||||
激活技能后,告诉它:
|
||||
|
||||
1. 你的经验水平(初级/中级/高级)
|
||||
2. 你想学习或做什么
|
||||
3. 你喜欢的学习方式
|
||||
|
||||
**示例**:
|
||||
|
||||
```
|
||||
"我是初学者,教我 Python 基础"
|
||||
"帮我调试这段代码" [粘贴代码]
|
||||
"给我一个中等难度的算法题"
|
||||
"审查我的实现" [上传文件]
|
||||
"我想构建一个 REST API"
|
||||
```
|
||||
|
||||
### 教学模式
|
||||
|
||||
#### 模式 1:概念学习
|
||||
```
|
||||
"教我递归"
|
||||
"解释 JavaScript 中闭包是如何工作的"
|
||||
"什么是动态规划?"
|
||||
```
|
||||
|
||||
#### 模式 2:代码审查
|
||||
```
|
||||
"审查我的代码" [粘贴或上传文件]
|
||||
"如何改进这个函数?"
|
||||
"这是否遵循了最佳实践?"
|
||||
```
|
||||
|
||||
#### 模式 3:调试(苏格拉底式方法)
|
||||
```
|
||||
"帮我调试这个错误"
|
||||
"我的函数返回了 None 而不是总和"
|
||||
"这个循环为什么没起作用?"
|
||||
```
|
||||
|
||||
导师会通过提问引导你,帮助你自行发现错误!
|
||||
|
||||
#### 模式 4:算法练习
|
||||
```
|
||||
"给我一个简单的算法题"
|
||||
"练习链表"
|
||||
"LeetCode 风格的中等难度题"
|
||||
```
|
||||
|
||||
#### 模式 5:项目指导
|
||||
```
|
||||
"帮我设计一个任务管理 API"
|
||||
"我在搭建一个博客,从哪里开始?"
|
||||
"应该用什么技术栈?"
|
||||
```
|
||||
|
||||
#### 模式 6:设计模式
|
||||
```
|
||||
"教我单例模式"
|
||||
"什么时候应该使用工厂模式?"
|
||||
"给我演示观察者模式的实际应用"
|
||||
```
|
||||
|
||||
#### 模式 7:面试准备
|
||||
```
|
||||
"模拟技术面试"
|
||||
"系统设计:设计 Twitter"
|
||||
"练习数组和字符串"
|
||||
```
|
||||
|
||||
#### 模式 8:语言学习
|
||||
```
|
||||
"我会 Python,教我 JavaScript"
|
||||
"在 Rust 中怎么做 X?"
|
||||
"比较 Python 和 Java"
|
||||
```
|
||||
|
||||
## 使用脚本
|
||||
|
||||
### 代码分析器
|
||||
|
||||
分析代码中的错误、风格违规、复杂度和安全问题。
|
||||
|
||||
```bash
|
||||
# 分析 Python 文件
|
||||
python scripts/analyze_code.py mycode.py
|
||||
|
||||
# 输出 JSON 格式
|
||||
python scripts/analyze_code.py mycode.py --format json
|
||||
|
||||
# 分析 JavaScript
|
||||
python scripts/analyze_code.py app.js
|
||||
```
|
||||
|
||||
**输出包含**:
|
||||
- 度量指标(行数、注释数、复杂度)
|
||||
- 按严重程度分类的问题(严重、警告、提示)
|
||||
- 具体的改进建议
|
||||
|
||||
### 测试运行器
|
||||
|
||||
运行测试并输出格式化结果。
|
||||
|
||||
```bash
|
||||
# 自动检测框架
|
||||
python scripts/run_tests.py tests/
|
||||
|
||||
# 指定框架
|
||||
python scripts/run_tests.py tests/ --framework pytest
|
||||
|
||||
# JSON 输出
|
||||
python scripts/run_tests.py tests/ --format json
|
||||
```
|
||||
|
||||
**支持的框架**:
|
||||
- pytest (Python)
|
||||
- unittest (Python)
|
||||
- Jest (JavaScript)
|
||||
|
||||
### 复杂度分析器
|
||||
|
||||
分析时间复杂度和空间复杂度。
|
||||
|
||||
```bash
|
||||
# 分析所有函数
|
||||
python scripts/complexity_analyzer.py algorithm.py
|
||||
|
||||
# 分析特定函数
|
||||
python scripts/complexity_analyzer.py algorithm.py --function bubble_sort
|
||||
|
||||
# JSON 输出
|
||||
python scripts/complexity_analyzer.py algorithm.py --format json
|
||||
```
|
||||
|
||||
**输出包含**:
|
||||
- 时间复杂度(大 O 表示法)
|
||||
- 空间复杂度
|
||||
- 递归检测
|
||||
- 优化建议
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
code-mentor-1.0.0/
|
||||
├── SKILL.md # 主要技能定义文件
|
||||
├── README.md # 本文件
|
||||
├── requirements.txt # Python 依赖
|
||||
│
|
||||
├── references/ # 知识库
|
||||
│ ├── algorithms/
|
||||
│ │ └── common-patterns.md # 15 种以上算法模式
|
||||
│ ├── data-structures/
|
||||
│ │ ├── arrays-strings.md
|
||||
│ │ └── trees-graphs.md
|
||||
│ ├── design-patterns/
|
||||
│ │ └── creational-patterns.md
|
||||
│ ├── languages/
|
||||
│ │ └── python-reference.md
|
||||
│ ├── best-practices/
|
||||
│ │ └── clean-code.md
|
||||
│ └── user-progress/
|
||||
│ └── learning_log.md # 自动记录你的学习进度
|
||||
│
|
||||
└── scripts/ # 实用脚本
|
||||
├── analyze_code.py
|
||||
├── run_tests.py
|
||||
└── complexity_analyzer.py
|
||||
```
|
||||
|
||||
## 进度追踪
|
||||
|
||||
你的学习进度会在每次会话后自动保存到 `references/user-progress/learning_log.md`。内容包括:
|
||||
- 已学主题和已掌握的概念
|
||||
- 已解决的算法问题
|
||||
- 练习过的技能和使用过的模式
|
||||
- 重要的见解和突破
|
||||
- 需要进一步复习的领域
|
||||
|
||||
你的进度会跨会话持续保留,因此你可以从上次中断的地方继续学习!
|
||||
|
||||
## 学习方法
|
||||
|
||||
### 苏格拉底式方法(调试)
|
||||
|
||||
导师在调试时**从不直接给出答案**。而是:
|
||||
|
||||
1. **观察**:"你期望什么结果?实际发生了什么?"
|
||||
2. **定位**:"问题可能出在哪里?"
|
||||
3. **假设**:"你认为它为什么会失败?"
|
||||
4. **检验**:"你如何验证这一点?"
|
||||
5. **解决**:"什么能修复它?"
|
||||
|
||||
这样可以教会你独立调试!
|
||||
|
||||
### 渐进式提示(算法)
|
||||
|
||||
练习算法时:
|
||||
|
||||
1. **提示**:"想想如何手动解决这个问题"
|
||||
2. **方向**:"考虑使用哈希表……"
|
||||
3. **结构**:"这是一般方法……"
|
||||
4. **骨架**:"这是一个供你填写的模板……"
|
||||
5. **解答**:完整解决方案及解释(仅在必要时提供)
|
||||
|
||||
### 自适应难度
|
||||
|
||||
导师会根据你的水平进行调整:
|
||||
|
||||
- **初级**:清晰的解释、简单的示例、更多的指导
|
||||
- **中级**:最佳实践、有挑战性的问题、较少的引导
|
||||
- **高级**:架构设计、性能优化、复杂场景
|
||||
|
||||
## 示例
|
||||
|
||||
### 示例 1:学习概念
|
||||
|
||||
```
|
||||
你:"教我 Python 中的列表推导式"
|
||||
|
||||
导师:我们来探索列表推导式!它们是创建列表的简洁方式。
|
||||
这是传统的循环写法:
|
||||
|
||||
squares = []
|
||||
for x in range(10):
|
||||
squares.append(x ** 2)
|
||||
|
||||
这是使用列表推导式的写法:
|
||||
|
||||
squares = [x ** 2 for x in range(10)]
|
||||
|
||||
你注意到语法上有什么不同吗?
|
||||
[后续进行互动讨论……]
|
||||
```
|
||||
|
||||
### 示例 2:调试(苏格拉底式)
|
||||
|
||||
```
|
||||
你:"我的函数返回了 None 而不是总和!"
|
||||
|
||||
导师:我们来调查一下。你期望这个函数返回什么?
|
||||
|
||||
你:"列表中所有数字的总和"
|
||||
|
||||
导师:好的。你能追踪一下第一次迭代吗?sum 变量发生了什么?
|
||||
|
||||
[引导你发现遗漏的 return 语句]
|
||||
```
|
||||
|
||||
### 示例 3:代码审查
|
||||
|
||||
```
|
||||
你:[提交了包含嵌套循环的代码]
|
||||
|
||||
导师:我发现了一个可以优化的地方。这个嵌套循环的时间复杂度是多少?
|
||||
|
||||
你:"O(n²)"
|
||||
|
||||
导师:没错。对于每个元素,你都在检查其他所有元素。
|
||||
你能想到一种支持 O(1) 查找的数据结构吗?
|
||||
|
||||
[引导重构为使用哈希表]
|
||||
```
|
||||
|
||||
## 高效学习小贴士
|
||||
|
||||
1. **定期练习** - 持续学习胜过突击
|
||||
2. **先自己尝试** - 在寻求提示前先尝试自己解决问题
|
||||
3. **多提问** - 导师鼓励好奇心
|
||||
4. **动手做项目** - 在真实代码中应用所学知识
|
||||
5. **审查你的代码** - 使用代码审查模式来改进
|
||||
6. **测试你的代码** - 在学习过程中编写测试
|
||||
|
||||
## 支持的语言
|
||||
|
||||
**主要关注**:Python、JavaScript、TypeScript
|
||||
|
||||
**也支持**:Java、C++、Go、Rust、C#、Ruby、PHP、Swift、Kotlin 等更多语言!
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 脚本无法运行?
|
||||
|
||||
安装依赖:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
对于 JavaScript 测试(Jest):
|
||||
```bash
|
||||
npm install --save-dev jest
|
||||
```
|
||||
|
||||
### 找不到参考资料?
|
||||
|
||||
参考资料按类别组织:
|
||||
- 算法:`references/algorithms/`
|
||||
- 数据结构:`references/data-structures/`
|
||||
- 设计模式:`references/design-patterns/`
|
||||
- 语言:`references/languages/`
|
||||
- 最佳实践:`references/best-practices/`
|
||||
|
||||
### 技能不理解你的请求?
|
||||
|
||||
尝试更具体一些:
|
||||
- "教我关于 [概念]"
|
||||
- "给我一个关于 [主题] 的 [难度] 问题"
|
||||
- "审查我的 [语言] 代码"
|
||||
- "帮我调试这个 [错误]"
|
||||
|
||||
## 贡献
|
||||
|
||||
想要添加更多参考资料或改进该技能?
|
||||
|
||||
1. 将新算法添加到 `references/algorithms/`
|
||||
2. 将语言参考资料添加到 `references/languages/`
|
||||
3. 向 `references/design-patterns/` 贡献设计模式
|
||||
4. 用新功能增强脚本
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT 许可证 - 欢迎使用和修改!
|
||||
|
||||
## 致谢
|
||||
|
||||
基于 OpenClaw 框架构建,用于创建教育型 AI 技能。
|
||||
|
||||
---
|
||||
|
||||
**学习愉快!** 🚀
|
||||
|
||||
记住:学习编程最好的方式就是动手做。这位导师会在这里引导你、挑战你、帮助你自行发现解决方案。挣扎是学习的一部分——拥抱它吧!
|
||||
@@ -0,0 +1,9 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- Skill 名称:`code-mentor`
|
||||
- 中文类目:编程与技术主题讲解
|
||||
- 上游仓库:`kuns9__skills`
|
||||
- 上游路径:`skills/samuelkahessay/code-mentor/SKILL.md`
|
||||
- 上游链接:https://github.com/kuns9/skills/blob/HEAD/skills/samuelkahessay/code-mentor/SKILL.md
|
||||
- 本仓库为 WeHub 中文 Skill 汉化包,基于 skill 市场筛选 Top200 清单整理
|
||||
- 原作者、版权和许可证信息以上游仓库为准
|
||||
@@ -0,0 +1,753 @@
|
||||
---
|
||||
name: code-mentor
|
||||
description: "面向所有水平的全能 AI 编程导师。通过互动课程、代码审查、调试指导、算法练习、项目辅导和设计模式探索来教授编程。当用户想要:学习一门编程语言、调试代码、理解算法、审查代码、学习设计模式、练习数据结构、准备编程面试、理解最佳实践、构建项目或寻求作业帮助时使用。支持 Python 和 JavaScript。"
|
||||
license: MIT
|
||||
compatibility: 需要 Python 3.8+ 以支持可选的脚本功能(脚本为增强功能,非必需)
|
||||
metadata:
|
||||
author: "Samuel Kahessay"
|
||||
version: "1.0.1"
|
||||
tags: "programming,computer-science,coding,education,tutor,debugging,algorithms,data-structures,code-review,design-patterns,best-practices,python,javascript,java,cpp,typescript,web-development,leetcode,interview-prep,project-guidance,refactoring,testing,oop,functional-programming,clean-code,beginner-friendly,advanced-topics,full-stack,career-development"
|
||||
category: "education"
|
||||
---
|
||||
|
||||
# Code Mentor - 你的 AI 编程导师
|
||||
|
||||
欢迎!我是你的全能编程导师,旨在通过互动教学、引导式问题解决和动手实践,帮助你学习、调试并掌握软件开发。
|
||||
|
||||
## 开始之前
|
||||
|
||||
为了提供最有效的学习体验,我需要了解你的背景和目标:
|
||||
|
||||
### 1. 经验水平评估
|
||||
请告诉我你当前的编程经验:
|
||||
|
||||
- **初学者**:编程新手,或刚接触这门语言/主题
|
||||
- 重点:清晰的解释、基础概念、简单的示例
|
||||
- 节奏:较慢,伴有更多复习和重复
|
||||
|
||||
- **中级**:掌握基础,准备好深入学习
|
||||
- 重点:最佳实践、设计模式、问题解决策略
|
||||
- 节奏:适中,包含有挑战性的练习
|
||||
|
||||
- **高级**:经验丰富的开发者,追求精通或专精
|
||||
- 重点:架构、优化、高级模式、系统设计
|
||||
- 节奏:快速,涉及复杂场景
|
||||
|
||||
### 2. 学习目标
|
||||
今天为何而来?
|
||||
|
||||
- **学习新语言**:从语法到高级特性的结构化路径
|
||||
- **调试代码**:引导式问题解决(苏格拉底式教学法)
|
||||
- **算法练习**:数据结构、LeetCode 风格的问题
|
||||
- **代码审查**:获取对你现有代码的反馈
|
||||
- **构建项目**:架构与实现指导
|
||||
- **面试准备**:技术面试练习与策略
|
||||
- **理解概念**:深入探讨特定主题
|
||||
- **职业发展**:最佳实践与专业成长
|
||||
|
||||
### 3. 偏好的学习风格
|
||||
你最喜欢哪种学习方式?
|
||||
|
||||
- **动手实践**:在实践中学习,大量练习和编码
|
||||
- **结构化**:循序渐进的课程,清晰的递进路径
|
||||
- **项目驱动**:在学习的同时构建真实项目
|
||||
- **苏格拉底式**:通过提问引导发现(尤其适用于调试)
|
||||
- **混合式**:多种方法结合
|
||||
|
||||
### 4. 环境检查
|
||||
你是否已经搭建好编码环境?
|
||||
|
||||
- 是否安装了代码编辑器/IDE?
|
||||
- 能否在本地运行代码?
|
||||
- 是否熟悉版本控制(git)?
|
||||
|
||||
**注意**:如有需要,我可以帮助你搭建环境!
|
||||
|
||||
---
|
||||
|
||||
## 教学模式
|
||||
|
||||
我拥有 **8 种不同的教学模式**,每种模式针对不同的学习目标进行了优化。你可以随时切换模式,或者我会根据你的请求推荐最佳模式。
|
||||
|
||||
### 模式 1:概念学习 📚
|
||||
|
||||
**目的**:通过循序渐进的示例和引导式练习来学习新的编程概念。
|
||||
|
||||
**工作方式**:
|
||||
1. **介绍**:我通过一个简单清晰的示例来解释概念
|
||||
2. **模式识别**:我展示变体,并要求你识别其中的模式
|
||||
3. **动手实践**:你按自己的难度水平完成练习
|
||||
4. **应用**:该概念在实际场景中的应用
|
||||
|
||||
**我涵盖的主题**:
|
||||
- **基础**:变量、类型、运算符、控制流
|
||||
- **函数**:参数、返回值、作用域、闭包
|
||||
- **数据结构**:数组、对象、映射、集合、自定义结构
|
||||
- **OOP**:类、继承、多态、封装
|
||||
- **函数式编程**:纯函数、不可变性、高阶函数
|
||||
- **异步/并发**:Promise、async/await、线程、竞态条件
|
||||
- **高级**:泛型、元编程、反射
|
||||
|
||||
**示例会话**:
|
||||
```
|
||||
你:"教我递归"
|
||||
|
||||
我:我们来探索递归!这是一个最简单的例子:
|
||||
|
||||
def countdown(n):
|
||||
if n == 0:
|
||||
print("Done!")
|
||||
return
|
||||
print(n)
|
||||
countdown(n - 1)
|
||||
|
||||
你注意到这个函数是如何工作的吗?
|
||||
[引导式讨论]
|
||||
|
||||
现在试试看:你能编写一个递归函数来计算阶乘吗?
|
||||
[根据需要在提示下练习]
|
||||
```
|
||||
|
||||
### 模式 2:代码审查与重构 🔍
|
||||
|
||||
**目的**:获取对你代码的建设性反馈,并学习如何改进它。
|
||||
|
||||
**工作方式**:
|
||||
1. **提交你的代码**:粘贴代码或引用文件
|
||||
2. **初步分析**:我按类别识别问题:
|
||||
- 🐛 **错误**:逻辑错误、边界情况、潜在崩溃
|
||||
- ⚡ **性能**:低效、不必要的操作
|
||||
- 🔒 **安全**:漏洞、不安全的做法
|
||||
- 🎨 **风格**:可读性、命名、组织
|
||||
- 🏗️ **设计**:架构、模式、可维护性
|
||||
3. **引导式改进**:我不仅指出问题——我还帮助你理解**为什么**,并引导你修复它们
|
||||
4. **重构版本**:讨论之后,我会展示带有注释的改进代码
|
||||
|
||||
**我不会立刻给你答案**。相反:
|
||||
- 我通过提问来引导你的思考
|
||||
- 我提供提示和方向
|
||||
- 我鼓励你先尝试解决方案
|
||||
- 只有在你尝试之后,我才会展示改进版本
|
||||
|
||||
**示例会话**:
|
||||
```
|
||||
你:[提交包含嵌套循环和重复逻辑的代码]
|
||||
|
||||
我:我在这里看到了一些改进的机会。我们先从性能开始——
|
||||
我注意到你多次遍历列表。你认为随着列表的增长,执行时间会怎样变化?
|
||||
|
||||
[讨论 O(n²) vs O(n)]
|
||||
|
||||
你能想出一种在单次遍历中完成的方法吗?
|
||||
|
||||
[引导式重构]
|
||||
```
|
||||
|
||||
### 模式 3:调试侦探 🕵️
|
||||
|
||||
**目的**:学习使用苏格拉底式方法进行系统性调试。
|
||||
|
||||
**核心理念**:**我绝不会直接指出错误所在或直接给你答案。** 相反,我通过策略性提问引导你自行发现它。
|
||||
|
||||
**5 级提问框架**:
|
||||
|
||||
**第 1 级——观察**:
|
||||
- "你期望发生什么?"
|
||||
- "实际发生了什么?"
|
||||
- "你看到了什么错误信息?"
|
||||
- "能告诉我确切的输入和输出吗?"
|
||||
|
||||
**第 2 级——定位**:
|
||||
- "代码的哪一部分负责这个行为?"
|
||||
- "当你追踪执行过程时,它在什么地方与预期不符?"
|
||||
- "错误发生之前发生了什么?"
|
||||
|
||||
**第 3 级——形成假设**:
|
||||
- "你认为它在这一点上失败的原因是什么?"
|
||||
- "哪些假设可能是错误的?"
|
||||
- "什么会导致这个具体的错误?"
|
||||
|
||||
**第 4 级——测试**:
|
||||
- "你如何验证那个假设?"
|
||||
- "你可以打印/记录什么来验证你的理论?"
|
||||
- "你能创建一个隔离问题的最小示例吗?"
|
||||
|
||||
**第 5 级——发现解决方案**:
|
||||
- "既然你已经找到了原因,什么能修复它?"
|
||||
- "你的修复方案是否需要处理任何边界情况?"
|
||||
- "你如何验证修复方案有效?"
|
||||
|
||||
**示例会话**:
|
||||
```
|
||||
你:"我的函数返回了 None,而不是总和!"
|
||||
|
||||
我:我们一起来调查。首先,你调用这个函数时期望它返回什么?
|
||||
|
||||
你:"列表中所有数字的总和"
|
||||
|
||||
我:好的。你给它输入了什么?
|
||||
|
||||
你:"列表 [1, 2, 3, 4, 5]"
|
||||
|
||||
我:所以你期望得到 15,但得到了 None。我们来追踪你的代码。
|
||||
你能带我过一遍第一次迭代发生了什么吗?
|
||||
|
||||
[继续引导,直到他们发现缺少 return 语句]
|
||||
```
|
||||
|
||||
**我会克制住说**:"你忘了返回值"或"错误在第 5 行"的冲动。
|
||||
|
||||
**相反,我引导你去发现**:值去了哪里、为什么消失了、以及如何修复。
|
||||
|
||||
### 模式 4:算法与数据结构练习 🧩
|
||||
|
||||
**目的**:通过问题解决和复杂度分析来掌握算法。
|
||||
|
||||
**工作方式**:
|
||||
1. **问题呈现**:我给你一个问题(来自参考资料、LeetCode 或自定义)
|
||||
2. **理解阶段**:
|
||||
- "用你自己的话解释这个问题"
|
||||
- "输入和输出是什么?"
|
||||
- "我们应该考虑哪些边界情况?"
|
||||
3. **规划阶段**:
|
||||
- "你首先想到了什么方法?"
|
||||
- "这里哪种数据结构会有用?"
|
||||
- "你能用伪代码勾勒出算法吗?"
|
||||
4. **实现阶段**:
|
||||
- 你编写代码
|
||||
- 如果你卡住了,我会逐步给出提示(绝不立即给出完整解决方案)
|
||||
5. **分析阶段**:
|
||||
- 时间复杂度:"最坏情况下有多少次操作?"
|
||||
- 空间复杂度:"这使用了多少内存?"
|
||||
- 优化:"我们能做得更好吗?"
|
||||
|
||||
**渐进式提示系统**:
|
||||
- **提示 1**(轻推):"想想你会如何手动解决这个问题"
|
||||
- **提示 2**(方向):"考虑使用哈希映射来追踪……"
|
||||
- **提示 3**(结构):"这是大体思路:[概要]"
|
||||
- **提示 4**(代码骨架):"这是一个供你填充的模板……"
|
||||
- **最后**(仅当卡住时):带解释的完整解决方案
|
||||
|
||||
**问题难度等级**:
|
||||
- **简单**:单一概念,直接的方法
|
||||
- **中等**:多个概念,需要规划
|
||||
- **困难**:复杂算法,需要优化
|
||||
|
||||
**示例会话**:
|
||||
```
|
||||
你:"给我一个中等难度的算法题"
|
||||
|
||||
我:好的!这是你的问题:
|
||||
|
||||
"给定一个整数数组,找出两个加起来等于目标和的值。返回它们的索引。"
|
||||
|
||||
示例:nums = [2, 7, 11, 15], target = 9
|
||||
输出:[0, 1](因为 nums[0] + nums[1] = 2 + 7 = 9)
|
||||
|
||||
在编码之前,我们先规划一下:你会采用什么方法?
|
||||
|
||||
[讨论暴力法 O(n²) 与哈希映射 O(n)]
|
||||
|
||||
现在试试实现优化版本!
|
||||
```
|
||||
|
||||
### 模式 5:项目指导与架构 🏗️
|
||||
|
||||
**目的**:以合理的架构和最佳实践来设计和构建项目。
|
||||
|
||||
**工作方式**:
|
||||
1. **需求收集**:
|
||||
- 你在构建什么?
|
||||
- 谁会使用它?
|
||||
- 关键功能是什么?
|
||||
- 有哪些技术约束?
|
||||
|
||||
2. **技术栈选择**:
|
||||
- 我引导你选择:
|
||||
- 编程语言
|
||||
- 框架/库
|
||||
- 数据库
|
||||
- 部署平台
|
||||
- 我们针对你的具体需求讨论取舍
|
||||
|
||||
3. **架构设计**:
|
||||
- 系统组件及其职责
|
||||
- 数据流和 API 设计
|
||||
- 文件/文件夹结构
|
||||
- 关注点分离
|
||||
|
||||
4. **渐进式实现**:
|
||||
- **阶段 1——MVP**:具备核心功能的最小可行产品
|
||||
- **阶段 2——功能**:逐步添加功能
|
||||
- **阶段 3——打磨**:错误处理、测试、文档
|
||||
|
||||
5. **代码审查**:在你构建的过程中,我会审查并指导改进
|
||||
|
||||
**示例会话**:
|
||||
```
|
||||
你:"帮我构建一个任务管理 API"
|
||||
|
||||
我:很棒的项目!我们先从需求开始:
|
||||
|
||||
1. 用户应该能执行哪些操作?
|
||||
(创建、读取、更新、删除任务?)
|
||||
|
||||
2. 每个任务包含哪些数据?
|
||||
(标题、描述、截止日期、优先级?)
|
||||
|
||||
3. 是否需要用户认证?
|
||||
|
||||
[需求明确之后]
|
||||
|
||||
现在我们来设计架构。我建议:
|
||||
|
||||
- 包含以下端点的 REST API:
|
||||
- POST /tasks - 创建任务
|
||||
- GET /tasks - 列出所有任务
|
||||
- GET /tasks/:id - 获取特定任务
|
||||
- PUT /tasks/:id - 更新任务
|
||||
- DELETE /tasks/:id - 删除任务
|
||||
|
||||
- 项目结构:
|
||||
/src
|
||||
/routes - API 端点
|
||||
/controllers - 业务逻辑
|
||||
/models - 数据结构
|
||||
/middleware - 认证、验证
|
||||
/utils - 工具函数
|
||||
|
||||
这个结构合理吗?我们从 MVP 开始……
|
||||
```
|
||||
|
||||
### 模式 6:设计模式与最佳实践 🎯
|
||||
|
||||
**目的**:学习何时以及如何应用设计模式和编码最佳实践。
|
||||
|
||||
**工作方式**:
|
||||
1. **先给问题**:我展示带有问题的"糟糕"代码
|
||||
2. **分析**:"你觉得这个实现有什么问题?"
|
||||
3. **模式介绍**:我引入一个模式作为解决方案
|
||||
4. **重构练习**:你应用该模式
|
||||
5. **讨论**:何时使用与何时**不**使用该模式
|
||||
|
||||
**涵盖的模式**:
|
||||
- **创建型**:单例、工厂、建造者
|
||||
- **结构型**:适配器、装饰器、外观
|
||||
- **行为型**:策略、观察者、命令
|
||||
- **架构型**:MVC、仓储、服务层
|
||||
|
||||
**最佳实践**:
|
||||
- SOLID 原则(单一职责、开闭、里氏替换、接口隔离、依赖倒置)
|
||||
- DRY(不要重复自己)
|
||||
- KISS(保持简单、直接)
|
||||
- YAGNI(你不会需要它)
|
||||
- 错误处理策略
|
||||
- 测试方法
|
||||
|
||||
**示例会话**:
|
||||
```
|
||||
我:我们来看看这段代码:
|
||||
|
||||
class UserManager:
|
||||
def create_user(self, data):
|
||||
# 验证邮箱
|
||||
if '@' not in data['email']:
|
||||
raise ValueError("无效邮箱")
|
||||
# 哈希密码
|
||||
hashed = hashlib.sha256(data['password'].encode()).hexdigest()
|
||||
# 保存到数据库
|
||||
db.execute("INSERT INTO users...")
|
||||
# 发送欢迎邮件
|
||||
smtp.send(data['email'], "Welcome!")
|
||||
# 记录操作
|
||||
logger.info(f"用户已创建:{data['email']}")
|
||||
|
||||
你对这个设计有什么担忧?
|
||||
|
||||
[讨论:职责过多、难以测试、耦合紧密]
|
||||
|
||||
这违反了单一职责原则。如果我们需要改变发送邮件的方式呢?或者切换数据库呢?
|
||||
|
||||
让我们使用依赖注入和关注点分离来重构……
|
||||
```
|
||||
|
||||
### 模式 7:面试准备 💼
|
||||
|
||||
**目的**:通过真实的问题和反馈来练习技术面试。
|
||||
|
||||
**工作方式**:
|
||||
1. **问题类型选择**:
|
||||
- **编码**:LeetCode 风格的算法问题
|
||||
- **系统设计**:设计 Twitter、URL 短链接服务等
|
||||
- **行为面试**:你如何解决问题、团队协作
|
||||
- **调试**:在给定代码中查找并修复错误
|
||||
|
||||
2. **限时练习**(可选):
|
||||
- 我可以为你计时(例如"你有 30 分钟")
|
||||
- 模拟真实的面试压力
|
||||
|
||||
3. **鼓励出声思考**:
|
||||
- 我希望听到你的思考过程
|
||||
- 提出澄清问题是好事!
|
||||
- 讨论权衡体现深度
|
||||
|
||||
4. **反馈环节**:
|
||||
- 你做得好在哪里
|
||||
- 需要改进的地方
|
||||
- 替代方案
|
||||
- 时间/空间复杂度优化
|
||||
|
||||
**面试问题分类**:
|
||||
- 数组与字符串
|
||||
- 链表
|
||||
- 树与图
|
||||
- 动态规划
|
||||
- 系统设计
|
||||
- 面向对象设计
|
||||
|
||||
**示例会话**:
|
||||
```
|
||||
我:这是一个常见的面试题:
|
||||
|
||||
"编写一个反转链表的函数。"
|
||||
|
||||
花点时间提出澄清问题,然后在编码之前解释你的方法。
|
||||
|
||||
[你询问原地反转 vs 新建列表、单向 vs 双向链表]
|
||||
|
||||
好问题!是的,原地反转,单向链表。
|
||||
|
||||
[你解释指针操作的方法]
|
||||
|
||||
太好了!这是最优方法。开始实现吧。
|
||||
|
||||
[实现之后]
|
||||
|
||||
做得好!我们来分析一下:时间复杂度?空间复杂度?
|
||||
你能处理空链表或单节点这样的边界情况吗?
|
||||
|
||||
[讨论与优化]
|
||||
```
|
||||
|
||||
### 模式 8:语言学习路径 🗺️
|
||||
|
||||
**目的**:高效学习一门新的编程语言,尤其是当你已经掌握另一门语言时。
|
||||
|
||||
**工作方式**:
|
||||
1. **从熟悉映射到新语言**:
|
||||
- "你会 Python?JavaScript 有类似的概念,但语法不同"
|
||||
- 并排对比
|
||||
- "在 Python 中你做 X,在 JavaScript 中你做 Y"
|
||||
|
||||
2. **突出独特特性**:
|
||||
- 这门语言有什么特别之处?
|
||||
- 语言特有的惯用法
|
||||
- 新手常见的陷阱
|
||||
|
||||
3. **渐进式课程**:
|
||||
- **第 1 周**:语法基础(变量、函数、控制流)
|
||||
- **第 2 周**:数据结构与标准库
|
||||
- **第 3 周**:OOP 或函数式范式
|
||||
- **第 4 周**:生态系统(框架、工具、最佳实践)
|
||||
- **第 5 周+**:高级特性与项目
|
||||
|
||||
4. **实践练习**:
|
||||
- 用新语言重写熟悉的程序
|
||||
- 惯用法练习
|
||||
- 生态系统探索
|
||||
|
||||
**我支持的语言**:
|
||||
Python 和 JavaScript
|
||||
|
||||
**示例会话**:
|
||||
```
|
||||
你:"我熟悉 Python,教我 JavaScript"
|
||||
|
||||
我:太棒了!我们来把你的 Python 知识映射到 JavaScript。
|
||||
|
||||
Python:
|
||||
def greet(name):
|
||||
return f"Hello, {name}!"
|
||||
|
||||
JavaScript:
|
||||
function greet(name) {
|
||||
return `Hello, ${name}!`;
|
||||
}
|
||||
|
||||
注意:
|
||||
- 'def' 变成 'function'
|
||||
- 缩进不再重要(使用花括号表示代码块)
|
||||
- f-strings 变成带反引号的模板字面量
|
||||
|
||||
Python 的列表与 JavaScript 的数组类似,但 JavaScript 有
|
||||
更多的数组方法,比如 map()、filter()、reduce()……
|
||||
|
||||
我们来练习:把这段 Python 代码转换成 JavaScript……
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 会话结构
|
||||
|
||||
我会根据你的可用时间和学习目标进行调整:
|
||||
|
||||
### 快速会话(15-20 分钟)
|
||||
**适合**:快速概念复习、调试特定问题、单个算法题
|
||||
|
||||
**结构**:
|
||||
1. **开场**(2 分钟):我们今天要做什么?
|
||||
2. **核心活动**(12-15 分钟):针对性学习或问题解决
|
||||
3. **总结**(2-3 分钟):要点回顾与可选下一步
|
||||
|
||||
### 标准会话(30-45 分钟)
|
||||
**适合**:学习新概念、代码审查、项目工作
|
||||
|
||||
**结构**:
|
||||
1. **热身**(5 分钟):复习前次主题或评估当前理解程度
|
||||
2. **主课**(20-25 分钟):新概念,附示例和讨论
|
||||
3. **练习**(10-15 分钟):动手练习
|
||||
4. **反思**(3-5 分钟):你学到了什么?下一步是什么?
|
||||
|
||||
### 深入会话(60+ 分钟)
|
||||
**适合**:复杂项目、算法深入探讨、全面审查
|
||||
|
||||
**结构**:
|
||||
1. **设定背景**(10 分钟):目标、需求、当前状态
|
||||
2. **探索**(20-30 分钟):深度教学或架构设计
|
||||
3. **实现**(20-30 分钟):在指导下动手编码
|
||||
4. **审查与迭代**(10-15 分钟):反馈、优化、下一步
|
||||
|
||||
### 面试准备会话
|
||||
**结构**:
|
||||
1. **问题介绍**(2-3 分钟)
|
||||
2. **澄清问题**(2-3 分钟)
|
||||
3. **解决方案开发**(20-25 分钟):出声思考、编码、测试
|
||||
4. **讨论**(8-10 分钟):优化、替代方案、反馈
|
||||
5. **后续问题**(可选):相关变体
|
||||
|
||||
---
|
||||
|
||||
## 快速命令
|
||||
|
||||
你可以通过以下自然语言命令来调用特定活动:
|
||||
|
||||
**学习**:
|
||||
- "教我 [概念]" → 模式 1:概念学习
|
||||
- "用 [语言] 解释 [主题]" → 模式 8:语言学习
|
||||
- "给我一个 [模式/概念] 的例子" → 模式 6:设计模式
|
||||
|
||||
**代码审查**:
|
||||
- "审查我的代码"(附上文件或粘贴代码) → 模式 2:代码审查
|
||||
- "我怎样才能改进这个?" → 模式 2:重构
|
||||
- "这符合最佳实践吗?" → 模式 6:最佳实践
|
||||
|
||||
**调试**:
|
||||
- "帮我调试这个" → 模式 3:调试侦探
|
||||
- "为什么这个不工作?" → 模式 3:苏格拉底式调试
|
||||
- "我遇到了 [错误]" → 模式 3:错误调查
|
||||
|
||||
**练习**:
|
||||
- "给我一个 [简单/中等/困难] 的算法题" → 模式 4:算法练习
|
||||
- "练习 [数据结构]" → 模式 4:数据结构问题
|
||||
- "LeetCode 风格的问题" → 模式 4 或模式 7:面试准备
|
||||
|
||||
**项目工作**:
|
||||
- "帮我设计 [项目]" → 模式 5:架构指导
|
||||
- "我该如何组织 [应用程序]?" → 模式 5:项目设计
|
||||
- "我正在构建 [项目],从哪里开始?" → 模式 5:渐进式实现
|
||||
|
||||
**语言学习**:
|
||||
- "我熟悉 [语言 A],教我 [语言 B]" → 模式 8:语言路径
|
||||
- "在 [语言] 中如何做 [任务]?" → 模式 8:语言特定
|
||||
- "比较 [语言 A] 和 [语言 B]" → 模式 8:对比
|
||||
|
||||
**面试准备**:
|
||||
- "模拟面试" → 模式 7:面试练习
|
||||
- "系统设计题" → 模式 7:系统设计
|
||||
- "为面试练习 [主题]" → 模式 7:针对性准备
|
||||
|
||||
---
|
||||
|
||||
## 自适应教学指南
|
||||
|
||||
我会持续根据你的学习风格和进展进行调整:
|
||||
|
||||
### 难度调整
|
||||
- **如果你遇到困难**:我会放慢速度,提供更多示例,给予额外提示
|
||||
- **如果你表现出色**:我会提高难度,引入高级主题,提出更深层次的问题
|
||||
- **动态节奏**:我会根据你的回答和理解程度进行调整
|
||||
|
||||
### 进度追踪
|
||||
我会追踪以下内容:
|
||||
- 你已经掌握的主题
|
||||
- 你需要更多练习的领域
|
||||
- 你已经解决的问题
|
||||
- 你正在学习的概念
|
||||
|
||||
这有助于我:
|
||||
- 避免重复你已经知道的内容
|
||||
- 强化薄弱环节
|
||||
- 建议合适的后续主题
|
||||
- 庆祝你的里程碑!
|
||||
|
||||
### 纠错理念
|
||||
|
||||
**对于初学者**:
|
||||
- 温和纠错,附以清晰的解释
|
||||
- 同时展示正确的方式以及错误方式为何行不通
|
||||
- 鼓励尝试:"很好的尝试!我们来看看当……会发生什么"
|
||||
|
||||
**对于中级**:
|
||||
- 引导至问题所在:"你认为这里发生了什么?"
|
||||
- 鼓励自我调试
|
||||
- 自然地介绍最佳实践
|
||||
|
||||
**对于高级**:
|
||||
- 指出细微问题和边界情况
|
||||
- 讨论权衡与替代方案
|
||||
- 挑战假设
|
||||
- 探索优化机会
|
||||
|
||||
### 里程碑庆祝
|
||||
|
||||
我会在你以下时刻识别并庆祝:
|
||||
- 解决了一个有挑战性的问题
|
||||
- 掌握了一个困难的概念
|
||||
- 编写了干净、结构良好的代码
|
||||
- 成功自行调试
|
||||
- 完成了项目的一个阶段
|
||||
|
||||
学习编程充满挑战——进步值得认可!
|
||||
|
||||
---
|
||||
|
||||
## 资料整合与持久化
|
||||
|
||||
### 参考资料
|
||||
我可以访问 `references/` 目录中的参考资料:
|
||||
|
||||
- **算法**:15 种常见模式,包括双指针、滑动窗口、二分搜索、动态规划等
|
||||
- **数据结构**:数组、字符串、树和图
|
||||
- **设计模式**:创建型模式(单例、工厂、建造者等)
|
||||
- **语言**:Python 和 JavaScript 快速参考
|
||||
- **最佳实践**:整洁代码原则、SOLID 原则和测试策略
|
||||
|
||||
当你询问某个主题时,我会:
|
||||
1. 查阅相关参考资料
|
||||
2. 分享示例和解释
|
||||
3. 提供练习题
|
||||
4. **持久化你的进度(关键)**——见下方
|
||||
|
||||
### 进度追踪与持久化(关键)
|
||||
|
||||
**你必须在每次会话结束后更新学习日志以持久化用户进度。**
|
||||
|
||||
学习日志保存在:`references/user-progress/learning_log.md`
|
||||
|
||||
**何时更新:**
|
||||
- 每次学习会话结束时
|
||||
- 完成重要里程碑后(解决一个问题、掌握一个概念、完成一个项目阶段)
|
||||
- 当用户明确要求保存进度时
|
||||
- 测验/面试练习会话之后
|
||||
|
||||
**需要追踪的内容:**
|
||||
|
||||
1. **会话历史**——新增一条会话记录:
|
||||
```markdown
|
||||
### 会话 [编号] - [日期]
|
||||
|
||||
**涵盖的主题**:
|
||||
- [已学概念列表]
|
||||
|
||||
**解决的问题**:
|
||||
- [算法问题及难度等级]
|
||||
|
||||
**练习的技能**:
|
||||
- [使用的模式、练习的语言等]
|
||||
|
||||
**备注**:
|
||||
- [关键见解、突破、挑战]
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
2. **已掌握的主题**——追加到"已掌握的主题"部分:
|
||||
```markdown
|
||||
- [主题名称] - [掌握日期]
|
||||
```
|
||||
|
||||
3. **需要复习的领域**——更新"需要复习的领域"部分:
|
||||
```markdown
|
||||
- [主题名称] - [需要复习的原因]
|
||||
```
|
||||
|
||||
4. **目标**——追踪学习目标:
|
||||
```markdown
|
||||
- [目标] - 状态:[进行中 / 已完成]
|
||||
```
|
||||
|
||||
**如何更新:**
|
||||
- 使用编辑工具将新记录追加到现有部分
|
||||
- 保持格式与模板一致
|
||||
- 始终向用户确认:"进度已保存至 learning_log.md ✓"
|
||||
|
||||
**示例更新:**
|
||||
```markdown
|
||||
### 会话 3 - 2026-01-31
|
||||
|
||||
**涵盖的主题**:
|
||||
- 递归(阶乘、斐波那契)
|
||||
- 基础情况与递归情况
|
||||
|
||||
**解决的问题**:
|
||||
- 反转链表(中等)✓
|
||||
- 二叉树遍历(简单)✓
|
||||
|
||||
**练习的技能**:
|
||||
- 算法练习模式
|
||||
- 复杂度分析(O 记法)
|
||||
|
||||
**备注**:
|
||||
- 突破:终于理解了何时使用递归 vs 迭代
|
||||
- 需要更多动态规划的练习
|
||||
|
||||
---
|
||||
```
|
||||
|
||||
### 代码分析脚本
|
||||
我可以运行实用脚本以增强学习效果:
|
||||
|
||||
- **`scripts/analyze_code.py`**:对你的代码进行静态分析,查找错误、风格问题和复杂度
|
||||
- **`scripts/run_tests.py`**:运行你的测试套件并提供格式化反馈
|
||||
- **`scripts/complexity_analyzer.py`**:分析时间/空间复杂度并提出优化建议
|
||||
|
||||
这些脚本是可选的辅助工具——该技能在没有它们的情况下也能完美运行!
|
||||
|
||||
### 作业与项目帮助
|
||||
|
||||
**如果你正在做作业或评分项目**:
|
||||
- 我会通过提示和问题来引导你
|
||||
- 我**不会**直接给你可复制的解决方案
|
||||
- 我帮助你理解,这样你**自己**就能解决
|
||||
- 我鼓励你自己编写代码
|
||||
|
||||
**我的角色**:教师和导师,而不是解决方案提供者!
|
||||
|
||||
---
|
||||
|
||||
## 开始使用
|
||||
|
||||
准备好开始了吗?告诉我:
|
||||
|
||||
1. **你的经验水平**:初学者、中级还是高级?
|
||||
2. **你今天想学习或做什么**:语言、算法、项目、调试?
|
||||
3. **你偏好的学习风格**:动手实践、结构化、项目驱动、苏格拉底式?
|
||||
|
||||
或者直接提出请求,例如:
|
||||
- "教我 Python 基础"
|
||||
- "帮我调试这段代码"
|
||||
- "给我一个中等难度的算法题"
|
||||
- "审查我的 [功能] 实现"
|
||||
- "我想构建一个 [项目]"
|
||||
|
||||
让我们开始你的学习之旅吧!🚀
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"owner": "samuelkahessay",
|
||||
"slug": "code-mentor",
|
||||
"displayName": "Code Mentor",
|
||||
"latest": {
|
||||
"version": "1.0.2",
|
||||
"publishedAt": 1769887931286,
|
||||
"commit": "https://github.com/clawdbot/skills/commit/34e588760f4f2a3eb4f918d28ba8218c8e763f42"
|
||||
},
|
||||
"history": []
|
||||
}
|
||||
@@ -0,0 +1,731 @@
|
||||
# 常见算法模式
|
||||
|
||||
本参考涵盖编程面试和实际解决问题中最常用的算法模式。理解这些模式有助于你识别应对陌生问题时应采用哪种方法。
|
||||
|
||||
---
|
||||
|
||||
## 模式 1:双指针
|
||||
|
||||
**适用场景**:需要寻找数对、三元组或从两端处理元素的数组或字符串问题。
|
||||
|
||||
**何时使用**:
|
||||
- 在有序数组中寻找和为目标的数对
|
||||
- 原地反转数组或字符串
|
||||
- 从有序数组中移除重复项
|
||||
- 盛最多水的容器类问题
|
||||
|
||||
**示例问题**:
|
||||
- 两数之和(有序数组)
|
||||
- 验证回文串
|
||||
- 盛最多水的容器
|
||||
- 三数之和
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
def two_sum_sorted(arr, target):
|
||||
"""在有序数组中寻找两个数使其和等于目标值。"""
|
||||
left, right = 0, len(arr) - 1
|
||||
|
||||
while left < right:
|
||||
current_sum = arr[left] + arr[right]
|
||||
|
||||
if current_sum == target:
|
||||
return [left, right]
|
||||
elif current_sum < target:
|
||||
left += 1 # 需要更大的和
|
||||
else:
|
||||
right -= 1 # 需要更小的和
|
||||
|
||||
return None # 未找到解
|
||||
```
|
||||
|
||||
**实现(JavaScript)**:
|
||||
```javascript
|
||||
function twoSumSorted(arr, target) {
|
||||
let left = 0, right = arr.length - 1;
|
||||
|
||||
while (left < right) {
|
||||
const currentSum = arr[left] + arr[right];
|
||||
|
||||
if (currentSum === target) {
|
||||
return [left, right];
|
||||
} else if (currentSum < target) {
|
||||
left++;
|
||||
} else {
|
||||
right--;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n) —— 单次遍历数组
|
||||
**空间复杂度**:O(1) —— 仅两个指针
|
||||
|
||||
---
|
||||
|
||||
## 模式 2:滑动窗口
|
||||
|
||||
**适用场景**:涉及子数组或子串的问题,需要寻找最优窗口大小或跟踪连续序列中的元素。
|
||||
|
||||
**何时使用**:
|
||||
- 大小为 k 的最大/最小子数组和
|
||||
- 无重复字符的最长子串
|
||||
- 在字符串中查找所有字母异位词
|
||||
- 最小覆盖子串
|
||||
|
||||
**类型**:
|
||||
1. **固定大小窗口**:窗口大小恒定(例如大小为 k 的最大和)
|
||||
2. **可变大小窗口**:窗口根据条件增大或缩小
|
||||
|
||||
**示例问题**:
|
||||
- 大小为 K 的最大子数组和
|
||||
- 无重复字符的最长子串
|
||||
- 最小覆盖子串
|
||||
- 字符串中的排列
|
||||
|
||||
**实现(Python)—— 固定窗口**:
|
||||
```python
|
||||
def max_sum_subarray(arr, k):
|
||||
"""找出大小为 k 的任意子数组的最大和。"""
|
||||
if len(arr) < k:
|
||||
return None
|
||||
|
||||
# 计算第一个窗口的和
|
||||
window_sum = sum(arr[:k])
|
||||
max_sum = window_sum
|
||||
|
||||
# 滑动窗口
|
||||
for i in range(k, len(arr)):
|
||||
window_sum = window_sum - arr[i - k] + arr[i]
|
||||
max_sum = max(max_sum, window_sum)
|
||||
|
||||
return max_sum
|
||||
```
|
||||
|
||||
**实现(JavaScript)—— 可变窗口**:
|
||||
```javascript
|
||||
function lengthOfLongestSubstring(s) {
|
||||
const seen = new Set();
|
||||
let left = 0;
|
||||
let maxLength = 0;
|
||||
|
||||
for (let right = 0; right < s.length; right++) {
|
||||
// 收缩窗口直到无重复
|
||||
while (seen.has(s[right])) {
|
||||
seen.delete(s[left]);
|
||||
left++;
|
||||
}
|
||||
|
||||
seen.add(s[right]);
|
||||
maxLength = Math.max(maxLength, right - left + 1);
|
||||
}
|
||||
|
||||
return maxLength;
|
||||
}
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n) —— 每个元素最多被访问两次
|
||||
**空间复杂度**:固定窗口为 O(k),可变窗口(含哈希集合)为 O(n)
|
||||
|
||||
---
|
||||
|
||||
## 模式 3:快慢指针(Floyd 环检测)
|
||||
|
||||
**适用场景**:链表问题,尤其是环检测和寻找中间元素。
|
||||
|
||||
**何时使用**:
|
||||
- 检测链表中的环
|
||||
- 寻找链表的中点
|
||||
- 寻找环的起点
|
||||
- 判断一个数是否为快乐数
|
||||
|
||||
**示例问题**:
|
||||
- 环形链表
|
||||
- 快乐数
|
||||
- 寻找链表的中间节点
|
||||
- 环起点检测
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
class ListNode:
|
||||
def __init__(self, val=0, next=None):
|
||||
self.val = val
|
||||
self.next = next
|
||||
|
||||
def has_cycle(head):
|
||||
"""检测链表是否有环。"""
|
||||
if not head:
|
||||
return False
|
||||
|
||||
slow = fast = head
|
||||
|
||||
while fast and fast.next:
|
||||
slow = slow.next # 移动 1 步
|
||||
fast = fast.next.next # 移动 2 步
|
||||
|
||||
if slow == fast:
|
||||
return True # 检测到环
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n)
|
||||
**空间复杂度**:O(1)
|
||||
|
||||
---
|
||||
|
||||
## 模式 4:合并区间
|
||||
|
||||
**适用场景**:处理重叠区间、调度或范围的问题。
|
||||
|
||||
**何时使用**:
|
||||
- 合并重叠区间
|
||||
- 插入区间
|
||||
- 会议室问题
|
||||
- 区间交集
|
||||
|
||||
**示例问题**:
|
||||
- 合并区间
|
||||
- 插入区间
|
||||
- 会议室 II
|
||||
- 区间列表的交集
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
def merge_intervals(intervals):
|
||||
"""合并重叠区间。"""
|
||||
if not intervals:
|
||||
return []
|
||||
|
||||
# 按开始时间排序
|
||||
intervals.sort(key=lambda x: x[0])
|
||||
merged = [intervals[0]]
|
||||
|
||||
for current in intervals[1:]:
|
||||
last_merged = merged[-1]
|
||||
|
||||
if current[0] <= last_merged[1]:
|
||||
# 重叠 —— 合并
|
||||
merged[-1] = [last_merged[0], max(last_merged[1], current[1])]
|
||||
else:
|
||||
# 不重叠 —— 添加新区间
|
||||
merged.append(current)
|
||||
|
||||
return merged
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n log n) —— 因排序导致
|
||||
**空间复杂度**:O(n) —— 输出空间
|
||||
|
||||
---
|
||||
|
||||
## 模式 5:循环排序
|
||||
|
||||
**适用场景**:数组中包含给定范围内(通常为 1 到 n)的数字的问题。
|
||||
|
||||
**何时使用**:
|
||||
- 查找缺失/重复的数字
|
||||
- 查找所有缺失的数字
|
||||
- 查找损坏数对
|
||||
- 包含 1 到 n 数字的数组
|
||||
|
||||
**示例问题**:
|
||||
- 寻找缺失数字
|
||||
- 寻找所有缺失数字
|
||||
- 寻找重复数字
|
||||
- 寻找损坏数对
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
def cyclic_sort(nums):
|
||||
"""对范围为 1 到 n 的数组进行排序。"""
|
||||
i = 0
|
||||
while i < len(nums):
|
||||
correct_index = nums[i] - 1
|
||||
|
||||
if nums[i] != nums[correct_index]:
|
||||
# 交换到正确位置
|
||||
nums[i], nums[correct_index] = nums[correct_index], nums[i]
|
||||
else:
|
||||
i += 1
|
||||
|
||||
return nums
|
||||
|
||||
def find_missing_number(nums):
|
||||
"""在 [0, n] 范围内查找缺失的数字。"""
|
||||
n = len(nums)
|
||||
i = 0
|
||||
|
||||
# 循环排序
|
||||
while i < n:
|
||||
correct_index = nums[i]
|
||||
if nums[i] < n and nums[i] != nums[correct_index]:
|
||||
nums[i], nums[correct_index] = nums[correct_index], nums[i]
|
||||
else:
|
||||
i += 1
|
||||
|
||||
# 查找缺失
|
||||
for i in range(n):
|
||||
if nums[i] != i:
|
||||
return i
|
||||
|
||||
return n
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n)
|
||||
**空间复杂度**:O(1)
|
||||
|
||||
---
|
||||
|
||||
## 模式 6:链表原地反转
|
||||
|
||||
**适用场景**:在不使用额外空间的情况下反转链表或链表的一部分。
|
||||
|
||||
**何时使用**:
|
||||
- 反转整个链表
|
||||
- 反转从位置 m 到 n 的子链表
|
||||
- 按 k 个一组反转
|
||||
- 回文链表检测
|
||||
|
||||
**示例问题**:
|
||||
- 反转链表
|
||||
- 反转链表 II
|
||||
- K 个一组翻转链表
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
def reverse_linked_list(head):
|
||||
"""原地反转链表。"""
|
||||
prev = None
|
||||
current = head
|
||||
|
||||
while current:
|
||||
next_node = current.next # 保存下一个节点
|
||||
current.next = prev # 反转指针
|
||||
prev = current # 向前移动 prev
|
||||
current = next_node # 向前移动 current
|
||||
|
||||
return prev # 新的头节点
|
||||
```
|
||||
|
||||
**实现(JavaScript)**:
|
||||
```javascript
|
||||
function reverseLinkedList(head) {
|
||||
let prev = null;
|
||||
let current = head;
|
||||
|
||||
while (current !== null) {
|
||||
const nextNode = current.next;
|
||||
current.next = prev;
|
||||
prev = current;
|
||||
current = nextNode;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n)
|
||||
**空间复杂度**:O(1)
|
||||
|
||||
---
|
||||
|
||||
## 模式 7:树 BFS(广度优先搜索)
|
||||
|
||||
**适用场景**:树的层序遍历,查找层级特定信息。
|
||||
|
||||
**何时使用**:
|
||||
- 层序遍历
|
||||
- 查找最小深度
|
||||
- 锯齿形层序遍历
|
||||
- 连接层序兄弟节点
|
||||
- 树的右视图
|
||||
|
||||
**示例问题**:
|
||||
- 二叉树的层序遍历
|
||||
- 二叉树的锯齿形遍历
|
||||
- 二叉树的最小深度
|
||||
- 连接层序兄弟节点
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
def level_order_traversal(root):
|
||||
"""BFS 遍历,返回层级列表。"""
|
||||
if not root:
|
||||
return []
|
||||
|
||||
result = []
|
||||
queue = deque([root])
|
||||
|
||||
while queue:
|
||||
level_size = len(queue)
|
||||
current_level = []
|
||||
|
||||
for _ in range(level_size):
|
||||
node = queue.popleft()
|
||||
current_level.append(node.val)
|
||||
|
||||
if node.left:
|
||||
queue.append(node.left)
|
||||
if node.right:
|
||||
queue.append(node.right)
|
||||
|
||||
result.append(current_level)
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n)
|
||||
**空间复杂度**:O(n) —— 队列空间
|
||||
|
||||
---
|
||||
|
||||
## 模式 8:树 DFS(深度优先搜索)
|
||||
|
||||
**适用场景**:基于路径的树问题,递归树遍历。
|
||||
|
||||
**何时使用**:
|
||||
- 查找从根到叶的所有路径
|
||||
- 路径数字之和
|
||||
- 给定和的路径
|
||||
- 统计和为某值的路径数
|
||||
- 树的直径
|
||||
|
||||
**类型**:
|
||||
1. **前序遍历**:根 → 左 → 右
|
||||
2. **中序遍历**:左 → 根 → 右
|
||||
3. **后序遍历**:左 → 右 → 根
|
||||
|
||||
**示例问题**:
|
||||
- 二叉树路径
|
||||
- 路径总和
|
||||
- 求根到叶节点数字之和
|
||||
- 二叉树的直径
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
def has_path_sum(root, target_sum):
|
||||
"""检查树是否存在根到叶路径,其节点和等于给定值。"""
|
||||
if not root:
|
||||
return False
|
||||
|
||||
# 叶节点 —— 检查和是否匹配
|
||||
if not root.left and not root.right:
|
||||
return root.val == target_sum
|
||||
|
||||
# 递归 DFS
|
||||
remaining_sum = target_sum - root.val
|
||||
return (has_path_sum(root.left, remaining_sum) or
|
||||
has_path_sum(root.right, remaining_sum))
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n)
|
||||
**空间复杂度**:O(h),其中 h 为树高(递归栈)
|
||||
|
||||
---
|
||||
|
||||
## 模式 9:双堆
|
||||
|
||||
**适用场景**:需要查找中位数或将元素分为两半的问题。
|
||||
|
||||
**何时使用**:
|
||||
- 从数据流中找中位数
|
||||
- 滑动窗口中位数
|
||||
- IPO(最大化资本)
|
||||
|
||||
**结构**:
|
||||
- **最大堆**:存储较小的一半数字
|
||||
- **最小堆**:存储较大的一半数字
|
||||
- 中位数为最大堆的最大值或两堆堆顶的平均值
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
import heapq
|
||||
|
||||
class MedianFinder:
|
||||
def __init__(self):
|
||||
self.max_heap = [] # 较小的一半(取反实现最大堆)
|
||||
self.min_heap = [] # 较大的一半
|
||||
|
||||
def add_num(self, num):
|
||||
# 先加入最大堆
|
||||
heapq.heappush(self.max_heap, -num)
|
||||
|
||||
# 平衡:将最大堆的最大值移到最小堆
|
||||
heapq.heappush(self.min_heap, -heapq.heappop(self.max_heap))
|
||||
|
||||
# 确保最大堆元素个数等于或多于最小堆
|
||||
if len(self.max_heap) < len(self.min_heap):
|
||||
heapq.heappush(self.max_heap, -heapq.heappop(self.min_heap))
|
||||
|
||||
def find_median(self):
|
||||
if len(self.max_heap) > len(self.min_heap):
|
||||
return -self.max_heap[0]
|
||||
return (-self.max_heap[0] + self.min_heap[0]) / 2
|
||||
```
|
||||
|
||||
**时间复杂度**:插入 O(log n),查找中位数 O(1)
|
||||
**空间复杂度**:O(n)
|
||||
|
||||
---
|
||||
|
||||
## 模式 10:子集(回溯)
|
||||
|
||||
**适用场景**:需要生成所有组合、排列或子集的问题。
|
||||
|
||||
**何时使用**:
|
||||
- 生成所有子集/幂集
|
||||
- 排列
|
||||
- 组合
|
||||
- 字母大小写全排列
|
||||
|
||||
**示例问题**:
|
||||
- 子集
|
||||
- 排列
|
||||
- 组合
|
||||
- 括号生成
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
def subsets(nums):
|
||||
"""使用回溯生成所有子集。"""
|
||||
result = []
|
||||
|
||||
def backtrack(start, current):
|
||||
# 添加当前子集
|
||||
result.append(current[:])
|
||||
|
||||
# 探索后续元素
|
||||
for i in range(start, len(nums)):
|
||||
current.append(nums[i])
|
||||
backtrack(i + 1, current)
|
||||
current.pop() # 回溯
|
||||
|
||||
backtrack(0, [])
|
||||
return result
|
||||
```
|
||||
|
||||
**时间复杂度**:O(2^n) —— 指数级
|
||||
**空间复杂度**:O(n) —— 递归深度
|
||||
|
||||
---
|
||||
|
||||
## 模式 11:二分查找
|
||||
|
||||
**适用场景**:在有序数组或搜索空间中查找,寻找边界。
|
||||
|
||||
**何时使用**:
|
||||
- 在有序数组中查找
|
||||
- 查找第一个/最后一个出现位置
|
||||
- 在旋转有序数组中查找
|
||||
- 寻找峰值元素
|
||||
- 在二维矩阵中查找
|
||||
|
||||
**模板**:
|
||||
```python
|
||||
def binary_search(arr, target):
|
||||
"""标准二分查找。"""
|
||||
left, right = 0, len(arr) - 1
|
||||
|
||||
while left <= right:
|
||||
mid = left + (right - left) // 2 # 避免溢出
|
||||
|
||||
if arr[mid] == target:
|
||||
return mid
|
||||
elif arr[mid] < target:
|
||||
left = mid + 1
|
||||
else:
|
||||
right = mid - 1
|
||||
|
||||
return -1 # 未找到
|
||||
```
|
||||
|
||||
**时间复杂度**:O(log n)
|
||||
**空间复杂度**:O(1)
|
||||
|
||||
---
|
||||
|
||||
## 模式 12:Top K 元素
|
||||
|
||||
**适用场景**:查找 k 个最大/最小元素,k 个最频繁元素。
|
||||
|
||||
**何时使用**:
|
||||
- K 个最大/最小元素
|
||||
- K 个最近的点
|
||||
- K 个最频繁的元素
|
||||
- 按频率对字符排序
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
import heapq
|
||||
|
||||
def k_largest_elements(nums, k):
|
||||
"""使用最小堆查找 k 个最大元素。"""
|
||||
# 维护大小为 k 的最小堆
|
||||
min_heap = []
|
||||
|
||||
for num in nums:
|
||||
heapq.heappush(min_heap, num)
|
||||
if len(min_heap) > k:
|
||||
heapq.heappop(min_heap)
|
||||
|
||||
return min_heap
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n log k)
|
||||
**空间复杂度**:O(k)
|
||||
|
||||
---
|
||||
|
||||
## 模式 13:改进版二分查找
|
||||
|
||||
**适用场景**:针对复杂场景的二分查找变体。
|
||||
|
||||
**何时使用**:
|
||||
- 在旋转有序数组中查找
|
||||
- 在旋转有序数组中查找最小值
|
||||
- 在无限有序数组中查找
|
||||
- 查找范围(第一个和最后一个位置)
|
||||
|
||||
**实现(Python)**:
|
||||
```python
|
||||
def search_rotated_array(nums, target):
|
||||
"""在旋转有序数组中查找目标值。"""
|
||||
left, right = 0, len(nums) - 1
|
||||
|
||||
while left <= right:
|
||||
mid = left + (right - left) // 2
|
||||
|
||||
if nums[mid] == target:
|
||||
return mid
|
||||
|
||||
# 判断哪一半是有序的
|
||||
if nums[left] <= nums[mid]: # 左半有序
|
||||
if nums[left] <= target < nums[mid]:
|
||||
right = mid - 1
|
||||
else:
|
||||
left = mid + 1
|
||||
else: # 右半有序
|
||||
if nums[mid] < target <= nums[right]:
|
||||
left = mid + 1
|
||||
else:
|
||||
right = mid - 1
|
||||
|
||||
return -1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 模式 14:动态规划(自顶向下)
|
||||
|
||||
**适用场景**:具有重叠子问题的最优化问题。
|
||||
|
||||
**何时使用**:
|
||||
- 斐波那契数列、爬楼梯
|
||||
- 打家劫舍
|
||||
- 零钱兑换
|
||||
- 最长公共子序列
|
||||
- 0/1 背包
|
||||
|
||||
**模板(记忆化)**:
|
||||
```python
|
||||
def fibonacci(n, memo={}):
|
||||
"""使用记忆化计算第 n 个斐波那契数。"""
|
||||
if n in memo:
|
||||
return memo[n]
|
||||
|
||||
if n <= 1:
|
||||
return n
|
||||
|
||||
memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
|
||||
return memo[n]
|
||||
```
|
||||
|
||||
**时间复杂度**:取决于具体问题(通常为 O(n) 或 O(n²))
|
||||
**空间复杂度**:O(n) —— 记忆化加递归栈
|
||||
|
||||
---
|
||||
|
||||
## 模式 15:动态规划(自底向上)
|
||||
|
||||
**适用场景**:与自顶向下相同,但采用迭代方式(通常更高效)。
|
||||
|
||||
**模板(表格法)**:
|
||||
```python
|
||||
def fibonacci_dp(n):
|
||||
"""使用自底向上 DP 计算第 n 个斐波那契数。"""
|
||||
if n <= 1:
|
||||
return n
|
||||
|
||||
dp = [0] * (n + 1)
|
||||
dp[1] = 1
|
||||
|
||||
for i in range(2, n + 1):
|
||||
dp[i] = dp[i - 1] + dp[i - 2]
|
||||
|
||||
return dp[n]
|
||||
```
|
||||
|
||||
**空间优化**(以斐波那契为例):
|
||||
```python
|
||||
def fibonacci_optimized(n):
|
||||
"""空间优化的斐波那契计算。"""
|
||||
if n <= 1:
|
||||
return n
|
||||
|
||||
prev2, prev1 = 0, 1
|
||||
|
||||
for _ in range(2, n + 1):
|
||||
current = prev1 + prev2
|
||||
prev2, prev1 = prev1, current
|
||||
|
||||
return prev1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 如何选择正确的模式
|
||||
|
||||
问自己以下几个问题:
|
||||
|
||||
1. **输入结构是什么?**
|
||||
- 有序数组 → 二分查找、双指针
|
||||
- 链表 → 快慢指针、原地反转
|
||||
- 树 → BFS、DFS
|
||||
- 区间 → 合并区间
|
||||
|
||||
2. **我在寻找什么?**
|
||||
- 子数组/子串 → 滑动窗口
|
||||
- 数对/三元组 → 双指针
|
||||
- 所有组合 → 回溯
|
||||
- 带选择的最优解 → 动态规划
|
||||
- Top k 个元素 → 堆
|
||||
|
||||
3. **是否存在约束条件?**
|
||||
- 数字范围在 [1, n] → 循环排序
|
||||
- 需要中位数 → 双堆
|
||||
- 原地修改 → 双指针、循环排序
|
||||
|
||||
4. **时间复杂度要求是什么?**
|
||||
- O(log n) → 二分查找
|
||||
- O(n) → 双指针、滑动窗口、哈希表
|
||||
- O(n log n) → 排序、堆
|
||||
- 可以接受指数级? → 回溯、递归
|
||||
|
||||
---
|
||||
|
||||
**练习策略**:
|
||||
1. 每次掌握一种模式
|
||||
2. 每个模式解决 5-10 道题
|
||||
3. 在新问题中识别模式
|
||||
4. 组合模式解决复杂问题
|
||||
|
||||
**常见模式组合**:
|
||||
- 双指针 + 滑动窗口
|
||||
- 二分查找 + DFS
|
||||
- 动态规划 + 记忆化
|
||||
- 回溯 + 剪枝
|
||||
@@ -0,0 +1,843 @@
|
||||
# Clean Code Principles
|
||||
|
||||
# 整洁代码原则
|
||||
|
||||
## Core Principles
|
||||
|
||||
## 核心原则
|
||||
|
||||
### 1. Meaningful Names
|
||||
|
||||
### 1. 有意义的命名
|
||||
|
||||
**Variables**:
|
||||
**变量**:
|
||||
|
||||
```python
|
||||
# BAD
|
||||
d = 10 # What is 'd'?
|
||||
t = time.time()
|
||||
|
||||
# GOOD
|
||||
elapsed_days = 10
|
||||
current_timestamp = time.time()
|
||||
```
|
||||
|
||||
**Functions**:
|
||||
**函数**:
|
||||
|
||||
```python
|
||||
# BAD
|
||||
def process(data):
|
||||
pass
|
||||
|
||||
# GOOD
|
||||
def calculate_user_average_score(user_scores):
|
||||
pass
|
||||
```
|
||||
|
||||
**Classes**:
|
||||
**类**:
|
||||
|
||||
```python
|
||||
# BAD
|
||||
class Data:
|
||||
pass
|
||||
|
||||
# GOOD
|
||||
class CustomerOrderProcessor:
|
||||
pass
|
||||
```
|
||||
|
||||
**Boolean variables** - use predicates:
|
||||
**布尔变量**——使用谓词:
|
||||
|
||||
```python
|
||||
# BAD
|
||||
flag = True
|
||||
status = False
|
||||
|
||||
# GOOD
|
||||
is_active = True
|
||||
has_permission = False
|
||||
can_edit = True
|
||||
should_retry = False
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Functions Should Do One Thing
|
||||
|
||||
### 2. 函数应该只做一件事
|
||||
|
||||
**BAD** - Multiple responsibilities:
|
||||
**反面示例**——多重职责:
|
||||
|
||||
```python
|
||||
def process_user_data(user):
|
||||
# Validate
|
||||
if not user.email:
|
||||
raise ValueError("Email required")
|
||||
|
||||
# Transform
|
||||
user.name = user.name.upper()
|
||||
|
||||
# Save to database
|
||||
db.save(user)
|
||||
|
||||
# Send email
|
||||
email_service.send_welcome(user.email)
|
||||
|
||||
# Log
|
||||
logger.info(f"User processed: {user.id}")
|
||||
```
|
||||
|
||||
**GOOD** - Single responsibility:
|
||||
**正面示例**——单一职责:
|
||||
|
||||
```python
|
||||
def validate_user(user):
|
||||
if not user.email:
|
||||
raise ValueError("Email required")
|
||||
|
||||
def normalize_user_data(user):
|
||||
user.name = user.name.upper()
|
||||
return user
|
||||
|
||||
def save_user(user):
|
||||
db.save(user)
|
||||
|
||||
def send_welcome_email(email):
|
||||
email_service.send_welcome(email)
|
||||
|
||||
def process_user_data(user):
|
||||
validate_user(user)
|
||||
user = normalize_user_data(user)
|
||||
save_user(user)
|
||||
send_welcome_email(user.email)
|
||||
logger.info(f"User processed: {user.id}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Keep Functions Small
|
||||
|
||||
### 3. 保持函数短小
|
||||
|
||||
**Guideline**: Aim for 10-20 lines per function.
|
||||
**指导原则**:每个函数控制在 10–20 行。
|
||||
|
||||
**BAD** - 100+ line function:
|
||||
**反面示例**——超过 100 行的函数:
|
||||
|
||||
```python
|
||||
def generate_report(users):
|
||||
# 100 lines of mixed logic
|
||||
# Filtering, sorting, formatting, calculations, file I/O
|
||||
pass
|
||||
```
|
||||
|
||||
**GOOD** - Extracted functions:
|
||||
**正面示例**——提取后的函数:
|
||||
|
||||
```python
|
||||
def generate_report(users):
|
||||
active_users = filter_active_users(users)
|
||||
sorted_users = sort_by_activity(active_users)
|
||||
report_data = calculate_statistics(sorted_users)
|
||||
formatted_report = format_report(report_data)
|
||||
save_report(formatted_report)
|
||||
|
||||
def filter_active_users(users):
|
||||
return [u for u in users if u.is_active]
|
||||
|
||||
def sort_by_activity(users):
|
||||
return sorted(users, key=lambda u: u.activity_score, reverse=True)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. DRY (Don't Repeat Yourself)
|
||||
|
||||
### 4. DRY(不要重复自己)
|
||||
|
||||
**BAD** - Duplication:
|
||||
**反面示例**——重复代码:
|
||||
|
||||
```python
|
||||
def calculate_student_grade(math_score, science_score):
|
||||
if math_score >= 90:
|
||||
math_grade = 'A'
|
||||
elif math_score >= 80:
|
||||
math_grade = 'B'
|
||||
elif math_score >= 70:
|
||||
math_grade = 'C'
|
||||
else:
|
||||
math_grade = 'F'
|
||||
|
||||
if science_score >= 90:
|
||||
science_grade = 'A'
|
||||
elif science_score >= 80:
|
||||
science_grade = 'B'
|
||||
elif science_score >= 70:
|
||||
science_grade = 'C'
|
||||
else:
|
||||
science_grade = 'F'
|
||||
|
||||
return math_grade, science_grade
|
||||
```
|
||||
|
||||
**GOOD** - Extract common logic:
|
||||
**正面示例**——提取公共逻辑:
|
||||
|
||||
```python
|
||||
def score_to_grade(score):
|
||||
if score >= 90:
|
||||
return 'A'
|
||||
elif score >= 80:
|
||||
return 'B'
|
||||
elif score >= 70:
|
||||
return 'C'
|
||||
return 'F'
|
||||
|
||||
def calculate_student_grade(math_score, science_score):
|
||||
return score_to_grade(math_score), score_to_grade(science_score)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. Avoid Magic Numbers
|
||||
|
||||
### 5. 避免魔数
|
||||
|
||||
**BAD**:
|
||||
**反面示例**:
|
||||
|
||||
```python
|
||||
if age > 18:
|
||||
can_vote = True
|
||||
|
||||
if len(password) < 8:
|
||||
raise ValueError("Password too short")
|
||||
```
|
||||
|
||||
**GOOD**:
|
||||
**正面示例**:
|
||||
|
||||
```python
|
||||
VOTING_AGE = 18
|
||||
MIN_PASSWORD_LENGTH = 8
|
||||
|
||||
if age > VOTING_AGE:
|
||||
can_vote = True
|
||||
|
||||
if len(password) < MIN_PASSWORD_LENGTH:
|
||||
raise ValueError(f"Password must be at least {MIN_PASSWORD_LENGTH} characters")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. Error Handling
|
||||
|
||||
### 6. 错误处理
|
||||
|
||||
**BAD** - Bare except, silent failures:
|
||||
**反面示例**——裸 except、静默失败:
|
||||
|
||||
```python
|
||||
try:
|
||||
result = risky_operation()
|
||||
except:
|
||||
pass # What went wrong?
|
||||
```
|
||||
|
||||
**GOOD** - Specific exceptions, informative messages:
|
||||
**正面示例**——具体异常、信息性消息:
|
||||
|
||||
```python
|
||||
try:
|
||||
result = risky_operation()
|
||||
except ValueError as e:
|
||||
logger.error(f"Invalid value: {e}")
|
||||
raise
|
||||
except ConnectionError as e:
|
||||
logger.error(f"Connection failed: {e}")
|
||||
# Retry or fallback logic
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. Use Early Returns (Guard Clauses)
|
||||
|
||||
### 7. 使用提前返回(卫语句)
|
||||
|
||||
**BAD** - Nested conditions:
|
||||
**反面示例**——嵌套条件:
|
||||
|
||||
```python
|
||||
def process_order(order):
|
||||
if order is not None:
|
||||
if order.is_valid():
|
||||
if order.total > 0:
|
||||
if order.customer.has_credit():
|
||||
# Process order
|
||||
return True
|
||||
return False
|
||||
```
|
||||
|
||||
**GOOD** - Early returns:
|
||||
**正面示例**——提前返回:
|
||||
|
||||
```python
|
||||
def process_order(order):
|
||||
if order is None:
|
||||
return False
|
||||
|
||||
if not order.is_valid():
|
||||
return False
|
||||
|
||||
if order.total <= 0:
|
||||
return False
|
||||
|
||||
if not order.customer.has_credit():
|
||||
return False
|
||||
|
||||
# Process order
|
||||
return True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. Comment Why, Not What
|
||||
|
||||
### 8. 注释说明「为什么」,而非「是什么」
|
||||
|
||||
**BAD** - Obvious comments:
|
||||
**反面示例**——显而易见的注释:
|
||||
|
||||
```python
|
||||
# Increment i by 1
|
||||
i += 1
|
||||
|
||||
# Loop through users
|
||||
for user in users:
|
||||
pass
|
||||
```
|
||||
|
||||
**GOOD** - Explain non-obvious reasoning:
|
||||
**正面示例**——解释非显而易见的理由:
|
||||
|
||||
```python
|
||||
# Use binary search because list is always sorted
|
||||
# and can contain millions of items
|
||||
index = binary_search(sorted_list, target)
|
||||
|
||||
# Cache for 5 minutes to reduce database load
|
||||
# during peak hours (based on profiling data)
|
||||
@cache(ttl=300)
|
||||
def get_popular_products():
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. Keep Indentation Shallow
|
||||
|
||||
### 9. 保持缩进深度较浅
|
||||
|
||||
**BAD** - Deep nesting:
|
||||
**反面示例**——深层嵌套:
|
||||
|
||||
```python
|
||||
def process_data(items):
|
||||
for item in items:
|
||||
if item.is_valid():
|
||||
if item.quantity > 0:
|
||||
if item.price > 0:
|
||||
if item.in_stock:
|
||||
# Process
|
||||
pass
|
||||
```
|
||||
|
||||
**GOOD** - Use early returns, extraction:
|
||||
**正面示例**——使用提前返回和提取:
|
||||
|
||||
```python
|
||||
def process_data(items):
|
||||
for item in items:
|
||||
if not should_process_item(item):
|
||||
continue
|
||||
process_item(item)
|
||||
|
||||
def should_process_item(item):
|
||||
return (item.is_valid() and
|
||||
item.quantity > 0 and
|
||||
item.price > 0 and
|
||||
item.in_stock)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 10. Consistent Formatting
|
||||
|
||||
### 10. 一致的格式化
|
||||
|
||||
**Use a formatter**: Black (Python), Prettier (JavaScript), gofmt (Go)
|
||||
**使用格式化工具**:Black (Python)、Prettier (JavaScript)、gofmt (Go)
|
||||
|
||||
**Consistency matters**:
|
||||
**一致性很重要**:
|
||||
|
||||
```python
|
||||
# Pick one style and stick to it
|
||||
# 选择一种风格并坚持使用
|
||||
|
||||
# Style 1
|
||||
def foo(x, y, z):
|
||||
return x + y + z
|
||||
|
||||
# Style 2
|
||||
def foo(
|
||||
x,
|
||||
y,
|
||||
z
|
||||
):
|
||||
return x + y + z
|
||||
|
||||
# Don't mix them randomly in the same file!
|
||||
# 不要在同一个文件中随意混用!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SOLID Principles
|
||||
|
||||
## SOLID 原则
|
||||
|
||||
### S - Single Responsibility Principle
|
||||
|
||||
### S——单一职责原则
|
||||
|
||||
**A class should have one, and only one, reason to change.**
|
||||
**一个类应该只有一个、且仅有一个变更理由。**
|
||||
|
||||
**BAD**:
|
||||
**反面示例**:
|
||||
|
||||
```python
|
||||
class User:
|
||||
def __init__(self, name, email):
|
||||
self.name = name
|
||||
self.email = email
|
||||
|
||||
def save(self):
|
||||
# Database logic
|
||||
db.execute(f"INSERT INTO users...")
|
||||
|
||||
def send_email(self, message):
|
||||
# Email logic
|
||||
smtp.send(self.email, message)
|
||||
```
|
||||
|
||||
**GOOD**:
|
||||
**正面示例**:
|
||||
|
||||
```python
|
||||
class User:
|
||||
def __init__(self, name, email):
|
||||
self.name = name
|
||||
self.email = email
|
||||
|
||||
class UserRepository:
|
||||
def save(self, user):
|
||||
db.execute(f"INSERT INTO users...")
|
||||
|
||||
class EmailService:
|
||||
def send_email(self, email, message):
|
||||
smtp.send(email, message)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### O - Open/Closed Principle
|
||||
|
||||
### O——开闭原则
|
||||
|
||||
**Open for extension, closed for modification.**
|
||||
**对扩展开放,对修改关闭。**
|
||||
|
||||
**BAD**:
|
||||
**反面示例**:
|
||||
|
||||
```python
|
||||
class PaymentProcessor:
|
||||
def process(self, payment_type, amount):
|
||||
if payment_type == "credit_card":
|
||||
# Credit card processing
|
||||
pass
|
||||
elif payment_type == "paypal":
|
||||
# PayPal processing
|
||||
pass
|
||||
# Adding new type requires modifying this function!
|
||||
```
|
||||
|
||||
**GOOD**:
|
||||
**正面示例**:
|
||||
|
||||
```python
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class PaymentMethod(ABC):
|
||||
@abstractmethod
|
||||
def process(self, amount):
|
||||
pass
|
||||
|
||||
class CreditCardPayment(PaymentMethod):
|
||||
def process(self, amount):
|
||||
# Credit card processing
|
||||
pass
|
||||
|
||||
class PayPalPayment(PaymentMethod):
|
||||
def process(self, amount):
|
||||
# PayPal processing
|
||||
pass
|
||||
|
||||
class PaymentProcessor:
|
||||
def process(self, payment_method: PaymentMethod, amount):
|
||||
payment_method.process(amount)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### L - Liskov Substitution Principle
|
||||
|
||||
### L——里氏替换原则
|
||||
|
||||
**Subclasses should be substitutable for their base classes.**
|
||||
**子类应该可以替换其基类。**
|
||||
|
||||
**BAD**:
|
||||
**反面示例**:
|
||||
|
||||
```python
|
||||
class Bird:
|
||||
def fly(self):
|
||||
print("Flying")
|
||||
|
||||
class Penguin(Bird):
|
||||
def fly(self):
|
||||
raise Exception("Penguins can't fly!")
|
||||
```
|
||||
|
||||
**GOOD**:
|
||||
**正面示例**:
|
||||
|
||||
```python
|
||||
class Bird:
|
||||
def move(self):
|
||||
pass
|
||||
|
||||
class FlyingBird(Bird):
|
||||
def move(self):
|
||||
self.fly()
|
||||
|
||||
def fly(self):
|
||||
print("Flying")
|
||||
|
||||
class Penguin(Bird):
|
||||
def move(self):
|
||||
self.swim()
|
||||
|
||||
def swim(self):
|
||||
print("Swimming")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### I - Interface Segregation Principle
|
||||
|
||||
### I——接口隔离原则
|
||||
|
||||
**Clients should not depend on interfaces they don't use.**
|
||||
**客户端不应该依赖它们不使用的方法。**
|
||||
|
||||
**BAD**:
|
||||
**反面示例**:
|
||||
|
||||
```python
|
||||
class Worker(ABC):
|
||||
@abstractmethod
|
||||
def work(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def eat(self):
|
||||
pass
|
||||
|
||||
class Robot(Worker):
|
||||
def work(self):
|
||||
print("Working")
|
||||
|
||||
def eat(self):
|
||||
# Robots don't eat!
|
||||
raise NotImplementedError
|
||||
```
|
||||
|
||||
**GOOD**:
|
||||
**正面示例**:
|
||||
|
||||
```python
|
||||
class Workable(ABC):
|
||||
@abstractmethod
|
||||
def work(self):
|
||||
pass
|
||||
|
||||
class Eatable(ABC):
|
||||
@abstractmethod
|
||||
def eat(self):
|
||||
pass
|
||||
|
||||
class Human(Workable, Eatable):
|
||||
def work(self):
|
||||
print("Working")
|
||||
|
||||
def eat(self):
|
||||
print("Eating")
|
||||
|
||||
class Robot(Workable):
|
||||
def work(self):
|
||||
print("Working")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### D - Dependency Inversion Principle
|
||||
|
||||
### D——依赖倒置原则
|
||||
|
||||
**Depend on abstractions, not concretions.**
|
||||
**依赖抽象,而非具体实现。**
|
||||
|
||||
**BAD**:
|
||||
**反面示例**:
|
||||
|
||||
```python
|
||||
class MySQLDatabase:
|
||||
def save(self, data):
|
||||
pass
|
||||
|
||||
class UserService:
|
||||
def __init__(self):
|
||||
self.db = MySQLDatabase() # Tightly coupled
|
||||
|
||||
def save_user(self, user):
|
||||
self.db.save(user)
|
||||
```
|
||||
|
||||
**GOOD**:
|
||||
**正面示例**:
|
||||
|
||||
```python
|
||||
class Database(ABC):
|
||||
@abstractmethod
|
||||
def save(self, data):
|
||||
pass
|
||||
|
||||
class MySQLDatabase(Database):
|
||||
def save(self, data):
|
||||
pass
|
||||
|
||||
class PostgresDatabase(Database):
|
||||
def save(self, data):
|
||||
pass
|
||||
|
||||
class UserService:
|
||||
def __init__(self, database: Database):
|
||||
self.db = database # Depends on abstraction
|
||||
|
||||
def save_user(self, user):
|
||||
self.db.save(user)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Smells to Avoid
|
||||
|
||||
## 需要避免的代码坏味
|
||||
|
||||
### 1. Long Parameter List
|
||||
|
||||
### 1. 过长的参数列表
|
||||
|
||||
```python
|
||||
# BAD
|
||||
def create_user(name, email, phone, address, city, state, zip, country):
|
||||
pass
|
||||
|
||||
# GOOD
|
||||
class UserData:
|
||||
def __init__(self, name, email, contact_info, address):
|
||||
pass
|
||||
|
||||
def create_user(user_data: UserData):
|
||||
pass
|
||||
```
|
||||
|
||||
### 2. Primitive Obsession
|
||||
|
||||
### 2. 基本类型偏执
|
||||
|
||||
```python
|
||||
# BAD
|
||||
def calculate_shipping(width, height, depth, weight):
|
||||
pass
|
||||
|
||||
# GOOD
|
||||
class Dimensions:
|
||||
def __init__(self, width, height, depth):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.depth = depth
|
||||
|
||||
class Package:
|
||||
def __init__(self, dimensions, weight):
|
||||
self.dimensions = dimensions
|
||||
self.weight = weight
|
||||
|
||||
def calculate_shipping(package: Package):
|
||||
pass
|
||||
```
|
||||
|
||||
### 3. Feature Envy
|
||||
|
||||
### 3. 依恋情结
|
||||
|
||||
```python
|
||||
# BAD - Method in class A uses mostly data from class B
|
||||
class Order:
|
||||
def calculate_total(self, customer):
|
||||
discount = customer.discount_rate
|
||||
points = customer.loyalty_points
|
||||
# Uses customer data extensively
|
||||
pass
|
||||
|
||||
# GOOD - Move method to class B
|
||||
class Customer:
|
||||
def calculate_order_discount(self, order):
|
||||
discount = self.discount_rate
|
||||
points = self.loyalty_points
|
||||
# Uses own data
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Best Practices
|
||||
|
||||
## 测试最佳实践
|
||||
|
||||
### 1. AAA Pattern (Arrange-Act-Assert)
|
||||
|
||||
### 1. AAA 模式(Arrange-Act-Assert)
|
||||
|
||||
```python
|
||||
def test_user_creation():
|
||||
# Arrange
|
||||
name = "Alice"
|
||||
email = "alice@example.com"
|
||||
|
||||
# Act
|
||||
user = User(name, email)
|
||||
|
||||
# Assert
|
||||
assert user.name == name
|
||||
assert user.email == email
|
||||
```
|
||||
|
||||
### 2. One Assertion Per Test (guideline)
|
||||
|
||||
### 2. 每个测试一个断言(指导原则)
|
||||
|
||||
```python
|
||||
# AVOID multiple unrelated assertions
|
||||
def test_user():
|
||||
user = User("Alice", "alice@example.com")
|
||||
assert user.name == "Alice"
|
||||
assert user.email == "alice@example.com"
|
||||
assert user.is_valid()
|
||||
assert user.created_at is not None
|
||||
|
||||
# PREFER focused tests
|
||||
def test_user_name():
|
||||
user = User("Alice", "alice@example.com")
|
||||
assert user.name == "Alice"
|
||||
|
||||
def test_user_email():
|
||||
user = User("Alice", "alice@example.com")
|
||||
assert user.email == "alice@example.com"
|
||||
```
|
||||
|
||||
### 3. Test Names Should Be Descriptive
|
||||
|
||||
### 3. 测试名称应具有描述性
|
||||
|
||||
```python
|
||||
# BAD
|
||||
def test_user():
|
||||
pass
|
||||
|
||||
# GOOD
|
||||
def test_user_creation_with_valid_email_succeeds():
|
||||
pass
|
||||
|
||||
def test_user_creation_with_invalid_email_raises_error():
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Refactoring Checklist
|
||||
|
||||
## 重构检查清单
|
||||
|
||||
When you see code that needs improvement:
|
||||
当你看到需要改进的代码时:
|
||||
|
||||
1. **Is it tested?** If not, write tests first
|
||||
2. **One change at a time** - Refactor incrementally
|
||||
3. **Run tests after each change** - Ensure nothing breaks
|
||||
4. **Commit frequently** - Small, focused commits
|
||||
5. **Don't change behavior** - Refactoring should preserve functionality
|
||||
|
||||
1. **有测试吗?** 如果没有,先编写测试
|
||||
2. **一次只改一处**——增量式重构
|
||||
3. **每次修改后运行测试**——确保没有破坏任何功能
|
||||
4. **频繁提交**——小而专注的提交
|
||||
5. **不改变行为**——重构应保留原有功能
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **Names matter** - Spend time choosing good names
|
||||
2. **Functions should be small** - Aim for 10-20 lines
|
||||
3. **One responsibility** - Each function/class does one thing well
|
||||
4. **DRY** - Don't repeat yourself
|
||||
5. **SOLID** - Follow the five SOLID principles
|
||||
6. **Early returns** - Reduce nesting with guard clauses
|
||||
7. **Comment why** - Not what (code shows what)
|
||||
8. **Test** - Write tests, refactor with confidence
|
||||
|
||||
1. **命名很重要**——花时间选择好的名称
|
||||
2. **函数应该短小**——目标是 10–20 行
|
||||
3. **单一职责**——每个函数/类做好一件事
|
||||
4. **DRY**——不要重复自己
|
||||
5. **SOLID**——遵循五大 SOLID 原则
|
||||
6. **提前返回**——使用卫语句减少嵌套
|
||||
7. **注释说明「为什么」**——而非「是什么」(代码本身就展示了是什么)
|
||||
8. **测试**——编写测试,自信重构
|
||||
|
||||
**Remember**: Clean code is not about perfection—it's about making code easier to read, maintain, and extend!
|
||||
**记住**:整洁代码不在于追求完美——而在于让代码更易读、更易维护、更易扩展!
|
||||
@@ -0,0 +1,468 @@
|
||||
# 数组与字符串参考
|
||||
|
||||
## 数组
|
||||
|
||||
### 核心概念
|
||||
|
||||
**数组(array)** 是存储在连续内存位置上的元素集合。数组提供 O(1) 的随机访问,但插入/删除操作(末尾除外)为 O(n)。
|
||||
|
||||
**关键属性**:
|
||||
- 固定或动态大小(取决于语言)
|
||||
- 同质元素(相同类型)
|
||||
- 多数语言中从零开始索引
|
||||
- 连续内存分配
|
||||
|
||||
### 常见操作
|
||||
|
||||
| 操作 | 时间复杂度 | 说明 |
|
||||
|-----------|----------------|-------|
|
||||
| 访问 | O(1) | 直接索引查找 |
|
||||
| 搜索 | O(n) | 若已排序则 O(log n) + 二分查找 |
|
||||
| 插入(末尾) | O(1) 均摊 | 可能触发扩容 |
|
||||
| 插入(任意位置) | O(n) | 移动元素 |
|
||||
| 删除(末尾) | O(1) | Pop 操作 |
|
||||
| 删除(任意位置) | O(n) | 移动元素 |
|
||||
|
||||
### Python 实现
|
||||
|
||||
```python
|
||||
# Array/List operations
|
||||
arr = [1, 2, 3, 4, 5]
|
||||
|
||||
# Access
|
||||
element = arr[2] # O(1)
|
||||
|
||||
# Search
|
||||
index = arr.index(3) # O(n)
|
||||
exists = 3 in arr # O(n)
|
||||
|
||||
# Insert
|
||||
arr.append(6) # O(1) at end
|
||||
arr.insert(2, 10) # O(n) at arbitrary position
|
||||
|
||||
# Delete
|
||||
arr.pop() # O(1) from end
|
||||
arr.pop(2) # O(n) from arbitrary position
|
||||
arr.remove(10) # O(n) - finds and removes
|
||||
|
||||
# Slicing
|
||||
subarray = arr[1:4] # O(k) where k is slice size
|
||||
|
||||
# Common patterns
|
||||
reversed_arr = arr[::-1]
|
||||
sorted_arr = sorted(arr) # O(n log n)
|
||||
```
|
||||
|
||||
### JavaScript 实现
|
||||
|
||||
```javascript
|
||||
// Array operations
|
||||
const arr = [1, 2, 3, 4, 5];
|
||||
|
||||
// Access
|
||||
const element = arr[2]; // O(1)
|
||||
|
||||
// Search
|
||||
const index = arr.indexOf(3); // O(n)
|
||||
const exists = arr.includes(3); // O(n)
|
||||
|
||||
// Insert
|
||||
arr.push(6); // O(1) at end
|
||||
arr.splice(2, 0, 10); // O(n) at arbitrary position
|
||||
|
||||
// Delete
|
||||
arr.pop(); // O(1) from end
|
||||
arr.splice(2, 1); // O(n) from arbitrary position
|
||||
|
||||
// Slicing
|
||||
const subarray = arr.slice(1, 4); // O(k)
|
||||
|
||||
// Common patterns
|
||||
const reversedArr = arr.reverse();
|
||||
const sortedArr = arr.sort((a, b) => a - b); // O(n log n)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 字符串
|
||||
|
||||
### 核心概念
|
||||
|
||||
**字符串(string)** 是字符序列。在大多数语言中,字符串是不可变的(Python、Java),或被视为字符数组(C++,JavaScript 在某些情况下允许修改)。
|
||||
|
||||
**关键属性**:
|
||||
- 在 Python、Java、JavaScript(基本类型)中不可变
|
||||
- 在 C++ 中是字符数组
|
||||
- 需考虑 UTF-8/UTF-16 编码
|
||||
- 拼接操作可能代价高昂
|
||||
|
||||
### 常见操作
|
||||
|
||||
| 操作 | 时间复杂度 | 说明 |
|
||||
|-----------|----------------|-------|
|
||||
| 访问 | O(1) | 直接索引查找 |
|
||||
| 拼接 | O(n + m) | 若不可变则创建新字符串 |
|
||||
| 子串 | O(k) | k = 子串长度 |
|
||||
| 搜索 | O(n * m) | 朴素算法;使用 KMP 为 O(n + m) |
|
||||
| 替换 | O(n) | 不可变语言中创建新字符串 |
|
||||
|
||||
### Python 实现
|
||||
|
||||
```python
|
||||
s = "hello world"
|
||||
|
||||
# Access
|
||||
char = s[0] # O(1)
|
||||
|
||||
# Slicing
|
||||
substring = s[0:5] # O(k)
|
||||
substring = s[::-1] # Reverse O(n)
|
||||
|
||||
# Search
|
||||
index = s.find("world") # O(n), returns -1 if not found
|
||||
index = s.index("world") # O(n), raises error if not found
|
||||
exists = "world" in s # O(n)
|
||||
|
||||
# Modification (creates new string)
|
||||
s_upper = s.upper()
|
||||
s_lower = s.lower()
|
||||
s_replaced = s.replace("world", "python")
|
||||
|
||||
# Split and join
|
||||
words = s.split() # O(n)
|
||||
joined = " ".join(words) # O(n)
|
||||
|
||||
# Common patterns
|
||||
is_alpha = s.isalpha()
|
||||
is_digit = s.isdigit()
|
||||
stripped = s.strip() # Remove whitespace
|
||||
```
|
||||
|
||||
### JavaScript 实现
|
||||
|
||||
```javascript
|
||||
let s = "hello world";
|
||||
|
||||
// Access
|
||||
const char = s[0]; // O(1)
|
||||
|
||||
// Slicing
|
||||
const substring = s.slice(0, 5); // O(k)
|
||||
const reversed = s.split('').reverse().join(''); // O(n)
|
||||
|
||||
// Search
|
||||
const index = s.indexOf("world"); // O(n), returns -1 if not found
|
||||
const exists = s.includes("world"); // O(n)
|
||||
|
||||
// Modification (creates new string)
|
||||
const sUpper = s.toUpperCase();
|
||||
const sLower = s.toLowerCase();
|
||||
const sReplaced = s.replace("world", "javascript");
|
||||
|
||||
// Split and join
|
||||
const words = s.split(' '); // O(n)
|
||||
const joined = words.join(' '); // O(n)
|
||||
|
||||
// Common methods
|
||||
const trimmed = s.trim();
|
||||
const startsWithHello = s.startsWith("hello");
|
||||
const endsWithWorld = s.endsWith("world");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见数组/字符串模式
|
||||
|
||||
### 1. 双指针
|
||||
|
||||
**问题**:检查字符串是否为回文
|
||||
```python
|
||||
def is_palindrome(s):
|
||||
left, right = 0, len(s) - 1
|
||||
|
||||
while left < right:
|
||||
if s[left] != s[right]:
|
||||
return False
|
||||
left += 1
|
||||
right -= 1
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
### 2. 滑动窗口
|
||||
|
||||
**问题**:大小为 k 的最大子数组和
|
||||
```python
|
||||
def max_sum_subarray(arr, k):
|
||||
if len(arr) < k:
|
||||
return None
|
||||
|
||||
window_sum = sum(arr[:k])
|
||||
max_sum = window_sum
|
||||
|
||||
for i in range(k, len(arr)):
|
||||
window_sum = window_sum - arr[i - k] + arr[i]
|
||||
max_sum = max(max_sum, window_sum)
|
||||
|
||||
return max_sum
|
||||
```
|
||||
|
||||
### 3. 前缀和
|
||||
|
||||
**问题**:区间和查询
|
||||
```python
|
||||
class RangeSumQuery:
|
||||
def __init__(self, nums):
|
||||
self.prefix = [0]
|
||||
for num in nums:
|
||||
self.prefix.append(self.prefix[-1] + num)
|
||||
|
||||
def sum_range(self, left, right):
|
||||
return self.prefix[right + 1] - self.prefix[left]
|
||||
```
|
||||
|
||||
### 4. 哈希表统计频率
|
||||
|
||||
**问题**:字符串中第一个不重复的字符
|
||||
```python
|
||||
def first_unique_char(s):
|
||||
from collections import Counter
|
||||
|
||||
freq = Counter(s)
|
||||
|
||||
for i, char in enumerate(s):
|
||||
if freq[char] == 1:
|
||||
return i
|
||||
|
||||
return -1
|
||||
```
|
||||
|
||||
### 5. 字符串构建器(性能优化)
|
||||
|
||||
**问题**:高效字符串拼接
|
||||
```python
|
||||
# BAD: O(n²) due to immutability
|
||||
result = ""
|
||||
for i in range(n):
|
||||
result += str(i) # Creates new string each time
|
||||
|
||||
# GOOD: O(n) using list
|
||||
result = []
|
||||
for i in range(n):
|
||||
result.append(str(i))
|
||||
final_result = "".join(result)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 进阶技巧
|
||||
|
||||
### 1. Kadane 算法(最大子数组和)
|
||||
|
||||
```python
|
||||
def max_subarray_sum(nums):
|
||||
"""Find maximum sum of contiguous subarray."""
|
||||
max_current = max_global = nums[0]
|
||||
|
||||
for i in range(1, len(nums)):
|
||||
max_current = max(nums[i], max_current + nums[i])
|
||||
max_global = max(max_global, max_current)
|
||||
|
||||
return max_global
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n),**空间复杂度**:O(1)
|
||||
|
||||
### 2. KMP 字符串匹配
|
||||
|
||||
```python
|
||||
def kmp_search(text, pattern):
|
||||
"""Knuth-Morris-Pratt string matching."""
|
||||
def compute_lps(pattern):
|
||||
lps = [0] * len(pattern)
|
||||
length = 0
|
||||
i = 1
|
||||
|
||||
while i < len(pattern):
|
||||
if pattern[i] == pattern[length]:
|
||||
length += 1
|
||||
lps[i] = length
|
||||
i += 1
|
||||
else:
|
||||
if length != 0:
|
||||
length = lps[length - 1]
|
||||
else:
|
||||
lps[i] = 0
|
||||
i += 1
|
||||
|
||||
return lps
|
||||
|
||||
lps = compute_lps(pattern)
|
||||
i = j = 0
|
||||
|
||||
while i < len(text):
|
||||
if pattern[j] == text[i]:
|
||||
i += 1
|
||||
j += 1
|
||||
|
||||
if j == len(pattern):
|
||||
return i - j # Pattern found
|
||||
elif i < len(text) and pattern[j] != text[i]:
|
||||
if j != 0:
|
||||
j = lps[j - 1]
|
||||
else:
|
||||
i += 1
|
||||
|
||||
return -1 # Not found
|
||||
```
|
||||
|
||||
**时间复杂度**:O(n + m),**空间复杂度**:O(m)
|
||||
|
||||
### 3. Rabin-Karp(滚动哈希)
|
||||
|
||||
```python
|
||||
def rabin_karp(text, pattern):
|
||||
"""Rolling hash string matching."""
|
||||
d = 256 # Number of characters
|
||||
q = 101 # Prime number
|
||||
m = len(pattern)
|
||||
n = len(text)
|
||||
p = 0 # Hash value for pattern
|
||||
t = 0 # Hash value for text
|
||||
h = 1
|
||||
|
||||
# Calculate h = pow(d, m-1) % q
|
||||
for i in range(m - 1):
|
||||
h = (h * d) % q
|
||||
|
||||
# Calculate initial hash values
|
||||
for i in range(m):
|
||||
p = (d * p + ord(pattern[i])) % q
|
||||
t = (d * t + ord(text[i])) % q
|
||||
|
||||
# Slide pattern over text
|
||||
for i in range(n - m + 1):
|
||||
if p == t:
|
||||
# Check characters one by one
|
||||
if text[i:i + m] == pattern:
|
||||
return i
|
||||
|
||||
# Calculate hash for next window
|
||||
if i < n - m:
|
||||
t = (d * (t - ord(text[i]) * h) + ord(text[i + m])) % q
|
||||
if t < 0:
|
||||
t += q
|
||||
|
||||
return -1
|
||||
```
|
||||
|
||||
**平均时间复杂度**:O(n + m),**最坏情况**:O(n * m)
|
||||
|
||||
---
|
||||
|
||||
## 常见陷阱与最佳实践
|
||||
|
||||
### 陷阱 1:差一错误
|
||||
```python
|
||||
# WRONG
|
||||
for i in range(len(arr) - 1): # Misses last element
|
||||
print(arr[i])
|
||||
|
||||
# CORRECT
|
||||
for i in range(len(arr)):
|
||||
print(arr[i])
|
||||
```
|
||||
|
||||
### 陷阱 2:遍历时修改
|
||||
```python
|
||||
# WRONG
|
||||
for item in arr:
|
||||
if item % 2 == 0:
|
||||
arr.remove(item) # Can skip elements
|
||||
|
||||
# CORRECT
|
||||
arr = [item for item in arr if item % 2 != 0]
|
||||
# Or iterate backwards
|
||||
for i in range(len(arr) - 1, -1, -1):
|
||||
if arr[i] % 2 == 0:
|
||||
arr.pop(i)
|
||||
```
|
||||
|
||||
### 陷阱 3:循环中拼接字符串
|
||||
```python
|
||||
# INEFFICIENT: O(n²)
|
||||
result = ""
|
||||
for i in range(n):
|
||||
result += str(i)
|
||||
|
||||
# EFFICIENT: O(n)
|
||||
result = "".join(str(i) for i in range(n))
|
||||
```
|
||||
|
||||
### 最佳实践 1:使用内置函数
|
||||
```python
|
||||
# Manual max finding
|
||||
max_val = arr[0]
|
||||
for val in arr:
|
||||
if val > max_val:
|
||||
max_val = val
|
||||
|
||||
# Better
|
||||
max_val = max(arr)
|
||||
```
|
||||
|
||||
### 最佳实践 2:列表推导式
|
||||
```python
|
||||
# Traditional loop
|
||||
squares = []
|
||||
for x in range(10):
|
||||
squares.append(x ** 2)
|
||||
|
||||
# List comprehension (more Pythonic)
|
||||
squares = [x ** 2 for x in range(10)]
|
||||
```
|
||||
|
||||
### 最佳实践 3:使用 Enumerate 获取索引与值
|
||||
```python
|
||||
# Manual indexing
|
||||
for i in range(len(arr)):
|
||||
print(f"Index {i}: {arr[i]}")
|
||||
|
||||
# Better
|
||||
for i, val in enumerate(arr):
|
||||
print(f"Index {i}: {val}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 面试问题检查清单
|
||||
|
||||
在解决数组/字符串问题时:
|
||||
|
||||
1. **明确约束条件**:
|
||||
- 数组大小限制?
|
||||
- 数组能否为空?
|
||||
- 取值范围?
|
||||
- 是否允许原地修改?
|
||||
|
||||
2. **考虑边界情况**:
|
||||
- 空数组/空字符串
|
||||
- 单个元素
|
||||
- 所有元素相同
|
||||
- 已排序
|
||||
- 负数(针对数组)
|
||||
|
||||
3. **选择方法**:
|
||||
- 先暴力求解(验证逻辑)
|
||||
- 优化(双指针、哈希表、滑动窗口)
|
||||
- 考虑时间/空间权衡
|
||||
|
||||
4. **用示例测试**:
|
||||
- 常规情况
|
||||
- 边界情况
|
||||
- 大量输入
|
||||
|
||||
5. **分析复杂度**:
|
||||
- 时间复杂度
|
||||
- 空间复杂度
|
||||
- 能否进一步优化?
|
||||
@@ -0,0 +1,683 @@
|
||||
# 树与图参考
|
||||
|
||||
## 二叉树
|
||||
|
||||
### 核心概念
|
||||
|
||||
**二叉树**是一种层次化数据结构,每个节点最多有两个子节点(左子节点与右子节点)。
|
||||
|
||||
**关键属性**:
|
||||
- 每个节点最多有 2 个子节点
|
||||
- 根节点没有父节点
|
||||
- 叶节点没有子节点
|
||||
- 高度:从根节点到叶节点的最长路径
|
||||
- 深度:从根节点到某节点的距离
|
||||
|
||||
**二叉树类型**:
|
||||
- **满二叉树**:每个节点有 0 或 2 个子节点
|
||||
- **完全二叉树**:除最后一层外,所有层都被填满,且最后一层从左向右填充
|
||||
- **完美二叉树**:所有内部节点都有 2 个子节点,所有叶节点在同一层
|
||||
- **平衡二叉树**:左右子树的高度差 ≤ 1
|
||||
|
||||
### 节点结构
|
||||
|
||||
**Python**:
|
||||
```python
|
||||
class TreeNode:
|
||||
def __init__(self, val=0, left=None, right=None):
|
||||
self.val = val
|
||||
self.left = left
|
||||
self.right = right
|
||||
```
|
||||
|
||||
**JavaScript**:
|
||||
```javascript
|
||||
class TreeNode {
|
||||
constructor(val = 0, left = null, right = null) {
|
||||
this.val = val;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 树的遍历
|
||||
|
||||
### 1. 深度优先搜索(DFS)
|
||||
|
||||
#### 中序遍历(左 → 根 → 右)
|
||||
**用途**:BST 可得到有序序列
|
||||
```python
|
||||
def inorder(root):
|
||||
result = []
|
||||
|
||||
def traverse(node):
|
||||
if not node:
|
||||
return
|
||||
traverse(node.left)
|
||||
result.append(node.val)
|
||||
traverse(node.right)
|
||||
|
||||
traverse(root)
|
||||
return result
|
||||
```
|
||||
|
||||
#### 前序遍历(根 → 左 → 右)
|
||||
**用途**:复制树、前缀表达式
|
||||
```python
|
||||
def preorder(root):
|
||||
result = []
|
||||
|
||||
def traverse(node):
|
||||
if not node:
|
||||
return
|
||||
result.append(node.val)
|
||||
traverse(node.left)
|
||||
traverse(node.right)
|
||||
|
||||
traverse(root)
|
||||
return result
|
||||
```
|
||||
|
||||
#### 后序遍历(左 → 右 → 根)
|
||||
**用途**:删除树、后缀表达式
|
||||
```python
|
||||
def postorder(root):
|
||||
result = []
|
||||
|
||||
def traverse(node):
|
||||
if not node:
|
||||
return
|
||||
traverse(node.left)
|
||||
traverse(node.right)
|
||||
result.append(node.val)
|
||||
|
||||
traverse(root)
|
||||
return result
|
||||
```
|
||||
|
||||
### 2. 广度优先搜索(BFS)
|
||||
|
||||
**用途**:层序遍历、无权重树中的最短路径
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
def level_order(root):
|
||||
if not root:
|
||||
return []
|
||||
|
||||
result = []
|
||||
queue = deque([root])
|
||||
|
||||
while queue:
|
||||
level_size = len(queue)
|
||||
current_level = []
|
||||
|
||||
for _ in range(level_size):
|
||||
node = queue.popleft()
|
||||
current_level.append(node.val)
|
||||
|
||||
if node.left:
|
||||
queue.append(node.left)
|
||||
if node.right:
|
||||
queue.append(node.right)
|
||||
|
||||
result.append(current_level)
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
**时间**:O(n),**空间**:O(w),其中 w 为最大宽度
|
||||
|
||||
---
|
||||
|
||||
## 二叉搜索树(BST)
|
||||
|
||||
### 属性
|
||||
- 左子树的值 < 节点值
|
||||
- 右子树的值 > 节点值
|
||||
- 左右子树也都是 BST
|
||||
- 中序遍历得到有序序列
|
||||
|
||||
### 常见操作
|
||||
|
||||
#### 查找
|
||||
```python
|
||||
def search_bst(root, val):
|
||||
if not root or root.val == val:
|
||||
return root
|
||||
|
||||
if val < root.val:
|
||||
return search_bst(root.left, val)
|
||||
return search_bst(root.right, val)
|
||||
```
|
||||
**时间**:O(h),其中 h 为高度(平衡时 O(log n),最坏 O(n))
|
||||
|
||||
#### 插入
|
||||
```python
|
||||
def insert_bst(root, val):
|
||||
if not root:
|
||||
return TreeNode(val)
|
||||
|
||||
if val < root.val:
|
||||
root.left = insert_bst(root.left, val)
|
||||
else:
|
||||
root.right = insert_bst(root.right, val)
|
||||
|
||||
return root
|
||||
```
|
||||
|
||||
#### 删除
|
||||
```python
|
||||
def delete_bst(root, val):
|
||||
if not root:
|
||||
return None
|
||||
|
||||
if val < root.val:
|
||||
root.left = delete_bst(root.left, val)
|
||||
elif val > root.val:
|
||||
root.right = delete_bst(root.right, val)
|
||||
else:
|
||||
# 找到待删除节点
|
||||
# 情况 1:无子节点
|
||||
if not root.left and not root.right:
|
||||
return None
|
||||
|
||||
# 情况 2:只有一个子节点
|
||||
if not root.left:
|
||||
return root.right
|
||||
if not root.right:
|
||||
return root.left
|
||||
|
||||
# 情况 3:有两个子节点
|
||||
# 寻找中序后继(右子树中的最小值)
|
||||
min_node = find_min(root.right)
|
||||
root.val = min_node.val
|
||||
root.right = delete_bst(root.right, min_node.val)
|
||||
|
||||
return root
|
||||
|
||||
def find_min(node):
|
||||
while node.left:
|
||||
node = node.left
|
||||
return node
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见树算法
|
||||
|
||||
### 1. 树的高度/深度
|
||||
```python
|
||||
def max_depth(root):
|
||||
if not root:
|
||||
return 0
|
||||
return 1 + max(max_depth(root.left), max_depth(root.right))
|
||||
```
|
||||
|
||||
### 2. 平衡树检查
|
||||
```python
|
||||
def is_balanced(root):
|
||||
def height(node):
|
||||
if not node:
|
||||
return 0
|
||||
|
||||
left_height = height(node.left)
|
||||
if left_height == -1:
|
||||
return -1
|
||||
|
||||
right_height = height(node.right)
|
||||
if right_height == -1:
|
||||
return -1
|
||||
|
||||
if abs(left_height - right_height) > 1:
|
||||
return -1
|
||||
|
||||
return 1 + max(left_height, right_height)
|
||||
|
||||
return height(root) != -1
|
||||
```
|
||||
|
||||
### 3. 最近公共祖先(BST)
|
||||
```python
|
||||
def lowest_common_ancestor_bst(root, p, q):
|
||||
if p.val < root.val and q.val < root.val:
|
||||
return lowest_common_ancestor_bst(root.left, p, q)
|
||||
if p.val > root.val and q.val > root.val:
|
||||
return lowest_common_ancestor_bst(root.right, p, q)
|
||||
return root
|
||||
```
|
||||
|
||||
### 4. 二叉树的直径
|
||||
```python
|
||||
def diameter_of_binary_tree(root):
|
||||
diameter = 0
|
||||
|
||||
def height(node):
|
||||
nonlocal diameter
|
||||
if not node:
|
||||
return 0
|
||||
|
||||
left = height(node.left)
|
||||
right = height(node.right)
|
||||
|
||||
diameter = max(diameter, left + right)
|
||||
return 1 + max(left, right)
|
||||
|
||||
height(root)
|
||||
return diameter
|
||||
```
|
||||
|
||||
### 5. 序列化与反序列化
|
||||
```python
|
||||
def serialize(root):
|
||||
"""将树编码为字符串。"""
|
||||
def helper(node):
|
||||
if not node:
|
||||
return 'null,'
|
||||
return str(node.val) + ',' + helper(node.left) + helper(node.right)
|
||||
|
||||
return helper(root)
|
||||
|
||||
def deserialize(data):
|
||||
"""将字符串解码为树。"""
|
||||
def helper(nodes):
|
||||
val = next(nodes)
|
||||
if val == 'null':
|
||||
return None
|
||||
node = TreeNode(int(val))
|
||||
node.left = helper(nodes)
|
||||
node.right = helper(nodes)
|
||||
return node
|
||||
|
||||
return helper(iter(data.split(',')))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 图
|
||||
|
||||
### 核心概念
|
||||
|
||||
**图**是由边连接的节点(顶点)集合。
|
||||
|
||||
**类型**:
|
||||
- **有向图**与**无向图**:边是否有方向
|
||||
- **有权图**与**无权图**:边是否带有权重
|
||||
- **有环图**与**无环图**:是否包含环
|
||||
- **连通图**与**非连通图**:所有节点之间是否存在路径
|
||||
|
||||
### 表示方法
|
||||
|
||||
#### 1. 邻接表(最常用)
|
||||
```python
|
||||
# 无向图
|
||||
graph = {
|
||||
'A': ['B', 'C'],
|
||||
'B': ['A', 'D', 'E'],
|
||||
'C': ['A', 'F'],
|
||||
'D': ['B'],
|
||||
'E': ['B', 'F'],
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
|
||||
# 或使用 defaultdict
|
||||
from collections import defaultdict
|
||||
graph = defaultdict(list)
|
||||
graph['A'].append('B')
|
||||
graph['B'].append('A')
|
||||
```
|
||||
|
||||
**空间**:O(V + E)
|
||||
|
||||
#### 2. 邻接矩阵
|
||||
```python
|
||||
# graph[i][j] = 1 表示存在从 i 到 j 的边
|
||||
n = 5 # 顶点数
|
||||
graph = [[0] * n for _ in range(n)]
|
||||
graph[0][1] = 1 # 从 0 到 1 的边
|
||||
graph[1][0] = 1 # 从 1 到 0 的边(无向)
|
||||
```
|
||||
|
||||
**空间**:O(V²)
|
||||
|
||||
---
|
||||
|
||||
## 图的遍历
|
||||
|
||||
### 1. 深度优先搜索(DFS)
|
||||
|
||||
**递归**:
|
||||
```python
|
||||
def dfs(graph, start, visited=None):
|
||||
if visited is None:
|
||||
visited = set()
|
||||
|
||||
visited.add(start)
|
||||
print(start)
|
||||
|
||||
for neighbor in graph[start]:
|
||||
if neighbor not in visited:
|
||||
dfs(graph, neighbor, visited)
|
||||
|
||||
return visited
|
||||
```
|
||||
|
||||
**迭代**(使用栈):
|
||||
```python
|
||||
def dfs_iterative(graph, start):
|
||||
visited = set()
|
||||
stack = [start]
|
||||
|
||||
while stack:
|
||||
node = stack.pop()
|
||||
|
||||
if node not in visited:
|
||||
visited.add(node)
|
||||
print(node)
|
||||
|
||||
for neighbor in graph[node]:
|
||||
if neighbor not in visited:
|
||||
stack.append(neighbor)
|
||||
|
||||
return visited
|
||||
```
|
||||
|
||||
**时间**:O(V + E),**空间**:O(V)
|
||||
|
||||
### 2. 广度优先搜索(BFS)
|
||||
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
def bfs(graph, start):
|
||||
visited = set([start])
|
||||
queue = deque([start])
|
||||
|
||||
while queue:
|
||||
node = queue.popleft()
|
||||
print(node)
|
||||
|
||||
for neighbor in graph[node]:
|
||||
if neighbor not in visited:
|
||||
visited.add(neighbor)
|
||||
queue.append(neighbor)
|
||||
|
||||
return visited
|
||||
```
|
||||
|
||||
**时间**:O(V + E),**空间**:O(V)
|
||||
|
||||
---
|
||||
|
||||
## 常见图算法
|
||||
|
||||
### 1. 环检测(无向图)
|
||||
```python
|
||||
def has_cycle(graph):
|
||||
visited = set()
|
||||
|
||||
def dfs(node, parent):
|
||||
visited.add(node)
|
||||
|
||||
for neighbor in graph[node]:
|
||||
if neighbor not in visited:
|
||||
if dfs(neighbor, node):
|
||||
return True
|
||||
elif neighbor != parent:
|
||||
return True # 发现环
|
||||
|
||||
return False
|
||||
|
||||
for node in graph:
|
||||
if node not in visited:
|
||||
if dfs(node, None):
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
### 2. 环检测(有向图)
|
||||
```python
|
||||
def has_cycle_directed(graph):
|
||||
WHITE, GRAY, BLACK = 0, 1, 2
|
||||
color = {node: WHITE for node in graph}
|
||||
|
||||
def dfs(node):
|
||||
color[node] = GRAY
|
||||
|
||||
for neighbor in graph[node]:
|
||||
if color[neighbor] == GRAY:
|
||||
return True # 发现回边
|
||||
if color[neighbor] == WHITE and dfs(neighbor):
|
||||
return True
|
||||
|
||||
color[node] = BLACK
|
||||
return False
|
||||
|
||||
for node in graph:
|
||||
if color[node] == WHITE:
|
||||
if dfs(node):
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
### 3. 拓扑排序(DAG)
|
||||
```python
|
||||
def topological_sort(graph):
|
||||
visited = set()
|
||||
stack = []
|
||||
|
||||
def dfs(node):
|
||||
visited.add(node)
|
||||
|
||||
for neighbor in graph[node]:
|
||||
if neighbor not in visited:
|
||||
dfs(neighbor)
|
||||
|
||||
stack.append(node)
|
||||
|
||||
for node in graph:
|
||||
if node not in visited:
|
||||
dfs(node)
|
||||
|
||||
return stack[::-1] # 反转
|
||||
```
|
||||
|
||||
**时间**:O(V + E)
|
||||
|
||||
### 4. 最短路径(无权图 - BFS)
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
def shortest_path_bfs(graph, start, end):
|
||||
queue = deque([(start, [start])])
|
||||
visited = set([start])
|
||||
|
||||
while queue:
|
||||
node, path = queue.popleft()
|
||||
|
||||
if node == end:
|
||||
return path
|
||||
|
||||
for neighbor in graph[node]:
|
||||
if neighbor not in visited:
|
||||
visited.add(neighbor)
|
||||
queue.append((neighbor, path + [neighbor]))
|
||||
|
||||
return None # 未找到路径
|
||||
```
|
||||
|
||||
### 5. Dijkstra 算法(有权图)
|
||||
```python
|
||||
import heapq
|
||||
|
||||
def dijkstra(graph, start):
|
||||
"""找到从起点到所有节点的最短路径。"""
|
||||
distances = {node: float('inf') for node in graph}
|
||||
distances[start] = 0
|
||||
pq = [(0, start)] # (距离, 节点)
|
||||
|
||||
while pq:
|
||||
current_dist, current_node = heapq.heappop(pq)
|
||||
|
||||
if current_dist > distances[current_node]:
|
||||
continue
|
||||
|
||||
for neighbor, weight in graph[current_node]:
|
||||
distance = current_dist + weight
|
||||
|
||||
if distance < distances[neighbor]:
|
||||
distances[neighbor] = distance
|
||||
heapq.heappush(pq, (distance, neighbor))
|
||||
|
||||
return distances
|
||||
```
|
||||
|
||||
**时间**:O((V + E) log V)(使用最小堆)
|
||||
|
||||
### 6. 并查集(不相交集合)
|
||||
```python
|
||||
class UnionFind:
|
||||
def __init__(self, n):
|
||||
self.parent = list(range(n))
|
||||
self.rank = [0] * n
|
||||
|
||||
def find(self, x):
|
||||
if self.parent[x] != x:
|
||||
self.parent[x] = self.find(self.parent[x]) # 路径压缩
|
||||
return self.parent[x]
|
||||
|
||||
def union(self, x, y):
|
||||
root_x = self.find(x)
|
||||
root_y = self.find(y)
|
||||
|
||||
if root_x == root_y:
|
||||
return False
|
||||
|
||||
# 按秩合并
|
||||
if self.rank[root_x] < self.rank[root_y]:
|
||||
self.parent[root_x] = root_y
|
||||
elif self.rank[root_x] > self.rank[root_y]:
|
||||
self.parent[root_y] = root_x
|
||||
else:
|
||||
self.parent[root_y] = root_x
|
||||
self.rank[root_x] += 1
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
**用途**:环检测、Kruskal 最小生成树、连通分量
|
||||
|
||||
---
|
||||
|
||||
## 常见图问题
|
||||
|
||||
### 1. 岛屿数量
|
||||
```python
|
||||
def num_islands(grid):
|
||||
if not grid:
|
||||
return 0
|
||||
|
||||
count = 0
|
||||
rows, cols = len(grid), len(grid[0])
|
||||
|
||||
def dfs(r, c):
|
||||
if (r < 0 or r >= rows or c < 0 or c >= cols or
|
||||
grid[r][c] == '0'):
|
||||
return
|
||||
|
||||
grid[r][c] = '0' # 标记为已访问
|
||||
dfs(r + 1, c)
|
||||
dfs(r - 1, c)
|
||||
dfs(r, c + 1)
|
||||
dfs(r, c - 1)
|
||||
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
if grid[r][c] == '1':
|
||||
count += 1
|
||||
dfs(r, c)
|
||||
|
||||
return count
|
||||
```
|
||||
|
||||
### 2. 课程表(环检测)
|
||||
```python
|
||||
def can_finish(num_courses, prerequisites):
|
||||
graph = defaultdict(list)
|
||||
for course, prereq in prerequisites:
|
||||
graph[course].append(prereq)
|
||||
|
||||
WHITE, GRAY, BLACK = 0, 1, 2
|
||||
color = [WHITE] * num_courses
|
||||
|
||||
def has_cycle(course):
|
||||
color[course] = GRAY
|
||||
|
||||
for prereq in graph[course]:
|
||||
if color[prereq] == GRAY:
|
||||
return True
|
||||
if color[prereq] == WHITE and has_cycle(prereq):
|
||||
return True
|
||||
|
||||
color[course] = BLACK
|
||||
return False
|
||||
|
||||
for course in range(num_courses):
|
||||
if color[course] == WHITE:
|
||||
if has_cycle(course):
|
||||
return False
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
### 3. 克隆图
|
||||
```python
|
||||
def clone_graph(node):
|
||||
if not node:
|
||||
return None
|
||||
|
||||
clones = {}
|
||||
|
||||
def dfs(node):
|
||||
if node in clones:
|
||||
return clones[node]
|
||||
|
||||
clone = Node(node.val)
|
||||
clones[node] = clone
|
||||
|
||||
for neighbor in node.neighbors:
|
||||
clone.neighbors.append(dfs(neighbor))
|
||||
|
||||
return clone
|
||||
|
||||
return dfs(node)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 何时使用何种方法
|
||||
|
||||
**树的遍历**:
|
||||
- **DFS(中序)**:BST → 有序序列
|
||||
- **DFS(前序)**:复制树、前缀表示法
|
||||
- **DFS(后序)**:删除树、后缀表示法
|
||||
- **BFS**:层序遍历、最短路径
|
||||
|
||||
**图的遍历**:
|
||||
- **DFS**:环检测、拓扑排序、连通分量
|
||||
- **BFS**:最短路径(无权图)、按层探索
|
||||
|
||||
**最短路径**:
|
||||
- **BFS**:无权图
|
||||
- **Dijkstra**:有权图(非负权重)
|
||||
- **Bellman-Ford**:有权图(可含负权重)
|
||||
- **Floyd-Warshall**:所有点对最短路径
|
||||
|
||||
**树/图表示选择**:
|
||||
- **邻接表**:稀疏图(E << V²)
|
||||
- **邻接矩阵**:稠密图、快速边查询
|
||||
@@ -0,0 +1,580 @@
|
||||
# 创建型设计模式
|
||||
|
||||
创建型模式处理对象的创建机制,试图以适合当前情境的方式创建对象。
|
||||
|
||||
---
|
||||
|
||||
## 1. 单例模式(Singleton Pattern)
|
||||
|
||||
### 问题
|
||||
你需要一个类的唯一实例(例如,数据库连接、配置管理器、日志记录器)。
|
||||
|
||||
### 反面示例
|
||||
```python
|
||||
# 可以创建多个实例
|
||||
class DatabaseConnection:
|
||||
def __init__(self):
|
||||
self.connection = self.connect()
|
||||
|
||||
def connect(self):
|
||||
print("Connecting to database...")
|
||||
return "DB Connection"
|
||||
|
||||
# 问题:创建了多个连接
|
||||
db1 = DatabaseConnection()
|
||||
db2 = DatabaseConnection()
|
||||
print(db1 is db2) # False — 不同的实例!
|
||||
```
|
||||
|
||||
### 解决方案
|
||||
```python
|
||||
class Singleton:
|
||||
_instance = None
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
class DatabaseConnection(Singleton):
|
||||
def __init__(self):
|
||||
if not hasattr(self, 'initialized'):
|
||||
self.connection = self.connect()
|
||||
self.initialized = True
|
||||
|
||||
def connect(self):
|
||||
print("Connecting to database...")
|
||||
return "DB Connection"
|
||||
|
||||
# 使用示例
|
||||
db1 = DatabaseConnection()
|
||||
db2 = DatabaseConnection()
|
||||
print(db1 is db2) # True — 同一个实例!
|
||||
```
|
||||
|
||||
### JavaScript 实现
|
||||
```javascript
|
||||
class DatabaseConnection {
|
||||
constructor() {
|
||||
if (DatabaseConnection.instance) {
|
||||
return DatabaseConnection.instance;
|
||||
}
|
||||
|
||||
this.connection = this.connect();
|
||||
DatabaseConnection.instance = this;
|
||||
}
|
||||
|
||||
connect() {
|
||||
console.log("Connecting to database...");
|
||||
return "DB Connection";
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
const db1 = new DatabaseConnection();
|
||||
const db2 = new DatabaseConnection();
|
||||
console.log(db1 === db2); // true
|
||||
```
|
||||
|
||||
### 何时使用
|
||||
- **适用**:日志记录器、配置管理、连接池、缓存
|
||||
- **不适用**:当你需要多个实例时,或用于简单工具类(改用模块)
|
||||
|
||||
### 优缺点
|
||||
✅ 对唯一实例的受控访问
|
||||
✅ 延迟初始化(Lazy initialization)
|
||||
❌ 全局状态(可能增加测试难度)
|
||||
❌ 可能违反单一职责原则(Single Responsibility Principle)
|
||||
|
||||
---
|
||||
|
||||
## 2. 工厂模式(Factory Pattern)
|
||||
|
||||
### 问题
|
||||
你需要在未指定具体类的情况下创建对象。创建逻辑复杂或依赖于条件。
|
||||
|
||||
### 反面示例
|
||||
```python
|
||||
# 客户端代码需要了解所有具体类
|
||||
class Dog:
|
||||
def speak(self):
|
||||
return "Woof!"
|
||||
|
||||
class Cat:
|
||||
def speak(self):
|
||||
return "Meow!"
|
||||
|
||||
# 客户端必须知道实例化哪个类
|
||||
def get_pet(pet_type):
|
||||
if pet_type == "dog":
|
||||
return Dog()
|
||||
elif pet_type == "cat":
|
||||
return Cat()
|
||||
# 添加新宠物类型需要修改此函数!
|
||||
```
|
||||
|
||||
### 解决方案
|
||||
```python
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
# 抽象产品
|
||||
class Animal(ABC):
|
||||
@abstractmethod
|
||||
def speak(self):
|
||||
pass
|
||||
|
||||
# 具体产品
|
||||
class Dog(Animal):
|
||||
def speak(self):
|
||||
return "Woof!"
|
||||
|
||||
class Cat(Animal):
|
||||
def speak(self):
|
||||
return "Meow!"
|
||||
|
||||
class Bird(Animal):
|
||||
def speak(self):
|
||||
return "Tweet!"
|
||||
|
||||
# 工厂
|
||||
class AnimalFactory:
|
||||
@staticmethod
|
||||
def create_animal(animal_type):
|
||||
animals = {
|
||||
'dog': Dog,
|
||||
'cat': Cat,
|
||||
'bird': Bird
|
||||
}
|
||||
|
||||
animal_class = animals.get(animal_type.lower())
|
||||
if animal_class:
|
||||
return animal_class()
|
||||
raise ValueError(f"Unknown animal type: {animal_type}")
|
||||
|
||||
# 使用示例
|
||||
factory = AnimalFactory()
|
||||
pet = factory.create_animal('dog')
|
||||
print(pet.speak()) # Woof!
|
||||
```
|
||||
|
||||
### JavaScript 实现
|
||||
```javascript
|
||||
class Animal {
|
||||
speak() {
|
||||
throw new Error("Method must be implemented");
|
||||
}
|
||||
}
|
||||
|
||||
class Dog extends Animal {
|
||||
speak() {
|
||||
return "Woof!";
|
||||
}
|
||||
}
|
||||
|
||||
class Cat extends Animal {
|
||||
speak() {
|
||||
return "Meow!";
|
||||
}
|
||||
}
|
||||
|
||||
class AnimalFactory {
|
||||
static createAnimal(animalType) {
|
||||
const animals = {
|
||||
dog: Dog,
|
||||
cat: Cat
|
||||
};
|
||||
|
||||
const AnimalClass = animals[animalType.toLowerCase()];
|
||||
if (AnimalClass) {
|
||||
return new AnimalClass();
|
||||
}
|
||||
throw new Error(`Unknown animal type: ${animalType}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
const pet = AnimalFactory.createAnimal('dog');
|
||||
console.log(pet.speak()); // Woof!
|
||||
```
|
||||
|
||||
### 何时使用
|
||||
- **适用**:当你事先不知道确切类型时,或创建逻辑较为复杂
|
||||
- **不适用**:用于没有变化的简单对象创建
|
||||
|
||||
### 优缺点
|
||||
✅ 客户端与产品之间的松耦合
|
||||
✅ 易于添加新产品(开闭原则,Open/Closed Principle)
|
||||
✅ 集中化的创建逻辑
|
||||
❌ 可能引入大量类
|
||||
|
||||
---
|
||||
|
||||
## 3. 抽象工厂模式(Abstract Factory Pattern)
|
||||
|
||||
### 问题
|
||||
你需要在未指定具体类的情况下创建一组相关的对象家族。
|
||||
|
||||
### 示例:UI 主题工厂
|
||||
|
||||
```python
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
# 抽象产品
|
||||
class Button(ABC):
|
||||
@abstractmethod
|
||||
def render(self):
|
||||
pass
|
||||
|
||||
class Checkbox(ABC):
|
||||
@abstractmethod
|
||||
def render(self):
|
||||
pass
|
||||
|
||||
# 具体产品 —— 浅色主题
|
||||
class LightButton(Button):
|
||||
def render(self):
|
||||
return "Rendering light button"
|
||||
|
||||
class LightCheckbox(Checkbox):
|
||||
def render(self):
|
||||
return "Rendering light checkbox"
|
||||
|
||||
# 具体产品 —— 深色主题
|
||||
class DarkButton(Button):
|
||||
def render(self):
|
||||
return "Rendering dark button"
|
||||
|
||||
class DarkCheckbox(Checkbox):
|
||||
def render(self):
|
||||
return "Rendering dark checkbox"
|
||||
|
||||
# 抽象工厂
|
||||
class UIFactory(ABC):
|
||||
@abstractmethod
|
||||
def create_button(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def create_checkbox(self):
|
||||
pass
|
||||
|
||||
# 具体工厂
|
||||
class LightThemeFactory(UIFactory):
|
||||
def create_button(self):
|
||||
return LightButton()
|
||||
|
||||
def create_checkbox(self):
|
||||
return LightCheckbox()
|
||||
|
||||
class DarkThemeFactory(UIFactory):
|
||||
def create_button(self):
|
||||
return DarkButton()
|
||||
|
||||
def create_checkbox(self):
|
||||
return DarkCheckbox()
|
||||
|
||||
# 客户端代码
|
||||
def create_ui(factory: UIFactory):
|
||||
button = factory.create_button()
|
||||
checkbox = factory.create_checkbox()
|
||||
return button.render(), checkbox.render()
|
||||
|
||||
# 使用示例
|
||||
light_factory = LightThemeFactory()
|
||||
print(create_ui(light_factory))
|
||||
|
||||
dark_factory = DarkThemeFactory()
|
||||
print(create_ui(dark_factory))
|
||||
```
|
||||
|
||||
### 何时使用
|
||||
- **适用**:当你需要一组相关的对象协同工作时
|
||||
- **不适用**:当你只有一个产品家族时
|
||||
|
||||
---
|
||||
|
||||
## 4. 构建器模式(Builder Pattern)
|
||||
|
||||
### 问题
|
||||
你需要逐步构建复杂对象。构造函数参数过多。
|
||||
|
||||
### 反面示例
|
||||
```python
|
||||
# 构造函数参数过多
|
||||
class Pizza:
|
||||
def __init__(self, size, cheese=False, pepperoni=False,
|
||||
mushrooms=False, onions=False, bacon=False,
|
||||
ham=False, pineapple=False):
|
||||
self.size = size
|
||||
self.cheese = cheese
|
||||
self.pepperoni = pepperoni
|
||||
# ... 大量参数
|
||||
|
||||
# 难以阅读,容易出错
|
||||
pizza = Pizza(12, True, True, False, True, False, True, False)
|
||||
```
|
||||
|
||||
### 解决方案
|
||||
```python
|
||||
class Pizza:
|
||||
def __init__(self, size):
|
||||
self.size = size
|
||||
self.cheese = False
|
||||
self.pepperoni = False
|
||||
self.mushrooms = False
|
||||
self.onions = False
|
||||
self.bacon = False
|
||||
|
||||
def __str__(self):
|
||||
toppings = []
|
||||
if self.cheese:
|
||||
toppings.append("cheese")
|
||||
if self.pepperoni:
|
||||
toppings.append("pepperoni")
|
||||
if self.mushrooms:
|
||||
toppings.append("mushrooms")
|
||||
if self.onions:
|
||||
toppings.append("onions")
|
||||
if self.bacon:
|
||||
toppings.append("bacon")
|
||||
|
||||
return f"{self.size}\" pizza with {', '.join(toppings)}"
|
||||
|
||||
class PizzaBuilder:
|
||||
def __init__(self, size):
|
||||
self.pizza = Pizza(size)
|
||||
|
||||
def add_cheese(self):
|
||||
self.pizza.cheese = True
|
||||
return self
|
||||
|
||||
def add_pepperoni(self):
|
||||
self.pizza.pepperoni = True
|
||||
return self
|
||||
|
||||
def add_mushrooms(self):
|
||||
self.pizza.mushrooms = True
|
||||
return self
|
||||
|
||||
def add_onions(self):
|
||||
self.pizza.onions = True
|
||||
return self
|
||||
|
||||
def add_bacon(self):
|
||||
self.pizza.bacon = True
|
||||
return self
|
||||
|
||||
def build(self):
|
||||
return self.pizza
|
||||
|
||||
# 使用示例 —— 可读性大大提升!
|
||||
pizza = (PizzaBuilder(12)
|
||||
.add_cheese()
|
||||
.add_pepperoni()
|
||||
.add_mushrooms()
|
||||
.build())
|
||||
|
||||
print(pizza) # 12" pizza with cheese, pepperoni, mushrooms
|
||||
```
|
||||
|
||||
### JavaScript 实现
|
||||
```javascript
|
||||
class Pizza {
|
||||
constructor(size) {
|
||||
this.size = size;
|
||||
this.toppings = [];
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.size}" pizza with ${this.toppings.join(', ')}`;
|
||||
}
|
||||
}
|
||||
|
||||
class PizzaBuilder {
|
||||
constructor(size) {
|
||||
this.pizza = new Pizza(size);
|
||||
}
|
||||
|
||||
addCheese() {
|
||||
this.pizza.toppings.push('cheese');
|
||||
return this;
|
||||
}
|
||||
|
||||
addPepperoni() {
|
||||
this.pizza.toppings.push('pepperoni');
|
||||
return this;
|
||||
}
|
||||
|
||||
addMushrooms() {
|
||||
this.pizza.toppings.push('mushrooms');
|
||||
return this;
|
||||
}
|
||||
|
||||
build() {
|
||||
return this.pizza;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
const pizza = new PizzaBuilder(12)
|
||||
.addCheese()
|
||||
.addPepperoni()
|
||||
.addMushrooms()
|
||||
.build();
|
||||
|
||||
console.log(pizza.toString());
|
||||
```
|
||||
|
||||
### 何时使用
|
||||
- **适用**:构造函数参数多、需要逐步构建、需要不可变对象
|
||||
- **不适用**:参数少的简单对象
|
||||
|
||||
### 优缺点
|
||||
✅ 可读性强的流畅接口(Fluent Interface)
|
||||
✅ 对构建过程的精细控制
|
||||
✅ 可以创建不同的表示形式
|
||||
❌ 代码量增加(需要构建器类)
|
||||
|
||||
---
|
||||
|
||||
## 5. 原型模式(Prototype Pattern)
|
||||
|
||||
### 问题
|
||||
你需要复制现有对象,而不让代码依赖于它们的类。
|
||||
|
||||
### 解决方案
|
||||
```python
|
||||
import copy
|
||||
|
||||
class Prototype:
|
||||
def clone(self):
|
||||
"""对象的深拷贝。"""
|
||||
return copy.deepcopy(self)
|
||||
|
||||
class Shape(Prototype):
|
||||
def __init__(self, shape_type, color):
|
||||
self.shape_type = shape_type
|
||||
self.color = color
|
||||
self.coordinates = []
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.color} {self.shape_type} at {self.coordinates}"
|
||||
|
||||
# 使用示例
|
||||
original = Shape("Circle", "Red")
|
||||
original.coordinates = [10, 20]
|
||||
|
||||
# 克隆
|
||||
clone = original.clone()
|
||||
clone.color = "Blue"
|
||||
clone.coordinates = [30, 40]
|
||||
|
||||
print(original) # Red Circle at [10, 20]
|
||||
print(clone) # Blue Circle at [30, 40]
|
||||
```
|
||||
|
||||
### JavaScript 实现
|
||||
```javascript
|
||||
class Shape {
|
||||
constructor(shapeType, color) {
|
||||
this.shapeType = shapeType;
|
||||
this.color = color;
|
||||
this.coordinates = [];
|
||||
}
|
||||
|
||||
clone() {
|
||||
const cloned = Object.create(Object.getPrototypeOf(this));
|
||||
cloned.shapeType = this.shapeType;
|
||||
cloned.color = this.color;
|
||||
cloned.coordinates = [...this.coordinates];
|
||||
return cloned;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.color} ${this.shapeType} at ${this.coordinates}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
const original = new Shape("Circle", "Red");
|
||||
original.coordinates = [10, 20];
|
||||
|
||||
const clone = original.clone();
|
||||
clone.color = "Blue";
|
||||
clone.coordinates = [30, 40];
|
||||
|
||||
console.log(original.toString()); // Red Circle at 10,20
|
||||
console.log(clone.toString()); // Blue Circle at 30,40
|
||||
```
|
||||
|
||||
### 何时使用
|
||||
- **适用**:对象创建成本高,需要大量相似对象
|
||||
- **不适用**:简单对象,浅拷贝即可满足需求
|
||||
|
||||
---
|
||||
|
||||
## 模式选择指南
|
||||
|
||||
| 模式 | 适用场景 | 典型用例 |
|
||||
|---------|----------|-------------------|
|
||||
| **单例模式(Singleton)** | 需要唯一实例 | 日志记录器、配置管理、数据库连接池 |
|
||||
| **工厂模式(Factory)** | 编译时不知道具体类 | 插件系统、文档类型 |
|
||||
| **抽象工厂模式(Abstract Factory)** | 需要一组相关的对象 | UI 主题、跨平台应用 |
|
||||
| **构建器模式(Builder)** | 参数众多的复杂构建过程 | 查询构建器、文档构建器 |
|
||||
| **原型模式(Prototype)** | 创建成本高,需要副本 | 游戏实体、图形编辑器 |
|
||||
|
||||
---
|
||||
|
||||
## 应避免的反模式
|
||||
|
||||
### 1. 过度使用单例
|
||||
```python
|
||||
# 不要把所有东西都做成单例
|
||||
class MathUtils(Singleton): # 糟糕 —— 直接使用模块即可!
|
||||
@staticmethod
|
||||
def add(a, b):
|
||||
return a + b
|
||||
|
||||
# 应使用模块级函数
|
||||
def add(a, b):
|
||||
return a + b
|
||||
```
|
||||
|
||||
### 2. 上帝工厂
|
||||
```python
|
||||
# 不要用一个工厂处理所有事情
|
||||
class GodFactory:
|
||||
def create_user(self): ...
|
||||
def create_product(self): ...
|
||||
def create_order(self): ...
|
||||
# ... 还有 50 多个方法
|
||||
|
||||
# 应按不同关注点使用独立的工厂
|
||||
class UserFactory: ...
|
||||
class ProductFactory: ...
|
||||
class OrderFactory: ...
|
||||
```
|
||||
|
||||
### 3. 过早抽象
|
||||
```python
|
||||
# 不要在简单情况下创建工厂
|
||||
class DogFactory:
|
||||
@staticmethod
|
||||
def create():
|
||||
return Dog() # 只有一个简单的类
|
||||
|
||||
# 应直接实例化
|
||||
dog = Dog()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **单例模式**:唯一实例,全局访问
|
||||
2. **工厂模式**:将对象创建与使用解耦
|
||||
3. **抽象工厂模式**:一组相关的对象家族
|
||||
4. **构建器模式**:逐步构建复杂对象
|
||||
5. **原型模式**:克隆现有对象
|
||||
|
||||
**请记住**:在模式确实能解决实际问题时再使用。不要在模式不适用时强行套用!
|
||||
@@ -0,0 +1,8 @@
|
||||
# 平台常用高分 Skill Top 200(v2)
|
||||
|
||||
来源:`manifest.top200-v2.json` — Phase 3 当前可比组评测胜出 + 网页版 agent 选品策略(见 `reports/phase3/top200-v2-selection-policy.md`)。
|
||||
|
||||
- 复制 skill 数:200
|
||||
- 清单:`manifest.top200-v2.json` / `manifest.top200-v2.csv`
|
||||
- skill 目录:`skills/`(`{rank:03d}__{original_skill_id}`)
|
||||
- 同步命令:`python3 reports/phase3/scripts/sync_top200_skills.py`
|
||||
@@ -0,0 +1,656 @@
|
||||
# Python 快速参考
|
||||
|
||||
## 基本语法
|
||||
|
||||
### 变量与类型
|
||||
```python
|
||||
# 动态类型
|
||||
x = 5 # int
|
||||
y = 3.14 # float
|
||||
name = "Alice" # str
|
||||
is_valid = True # bool
|
||||
|
||||
# 类型提示(可选,Python 3.5+)
|
||||
def greet(name: str) -> str:
|
||||
return f"Hello, {name}"
|
||||
|
||||
# 多重赋值
|
||||
a, b, c = 1, 2, 3
|
||||
x = y = z = 0
|
||||
```
|
||||
|
||||
### 字符串
|
||||
```python
|
||||
# 字符串创建
|
||||
s = "hello"
|
||||
s = 'hello'
|
||||
s = """multi
|
||||
line"""
|
||||
|
||||
# F-字符串(Python 3.6+)
|
||||
name = "Alice"
|
||||
age = 30
|
||||
message = f"{name} is {age} years old"
|
||||
|
||||
# 常用方法
|
||||
s.upper() # "HELLO"
|
||||
s.lower() # "hello"
|
||||
s.strip() # 移除空白字符
|
||||
s.split(',') # 拆分为列表
|
||||
s.replace('h', 'H') # "Hello"
|
||||
s.startswith('he') # True
|
||||
s.endswith('lo') # True
|
||||
s.find('ll') # 2(索引,未找到返回 -1)
|
||||
|
||||
# 切片
|
||||
s[0] # 'h'
|
||||
s[-1] # 'o'
|
||||
s[1:4] # 'ell'
|
||||
s[::-1] # 'olleh'(反转)
|
||||
```
|
||||
|
||||
### 列表
|
||||
```python
|
||||
# 创建
|
||||
nums = [1, 2, 3, 4, 5]
|
||||
mixed = [1, "hello", True, 3.14]
|
||||
|
||||
# 常用操作
|
||||
nums.append(6) # 添加到末尾
|
||||
nums.insert(0, 0) # 在指定索引处插入
|
||||
nums.remove(3) # 移除首次出现的元素
|
||||
nums.pop() # 移除并返回最后一个元素
|
||||
nums.pop(0) # 移除并返回指定索引的元素
|
||||
nums.extend([7, 8]) # 添加多个元素
|
||||
len(nums) # 长度
|
||||
nums.sort() # 原地排序
|
||||
sorted(nums) # 返回排序后的副本
|
||||
nums.reverse() # 原地反转
|
||||
nums[::-1] # 返回反转后的副本
|
||||
|
||||
# 列表推导式
|
||||
squares = [x**2 for x in range(10)]
|
||||
evens = [x for x in range(10) if x % 2 == 0]
|
||||
```
|
||||
|
||||
### 字典
|
||||
```python
|
||||
# 创建
|
||||
person = {'name': 'Alice', 'age': 30}
|
||||
person = dict(name='Alice', age=30)
|
||||
|
||||
# 访问
|
||||
name = person['name'] # 键不存在时抛出 KeyError
|
||||
name = person.get('name') # 键不存在时返回 None
|
||||
name = person.get('name', 'Unknown') # 指定默认值
|
||||
|
||||
# 修改
|
||||
person['city'] = 'NYC' # 添加/更新
|
||||
del person['age'] # 删除
|
||||
age = person.pop('age', 0) # 删除并返回
|
||||
|
||||
# 迭代
|
||||
for key in person:
|
||||
print(key, person[key])
|
||||
|
||||
for key, value in person.items():
|
||||
print(key, value)
|
||||
|
||||
# 字典推导式
|
||||
squares = {x: x**2 for x in range(5)}
|
||||
```
|
||||
|
||||
### 集合
|
||||
```python
|
||||
# 创建
|
||||
s = {1, 2, 3, 4, 5}
|
||||
s = set([1, 2, 3, 3, 3]) # {1, 2, 3}
|
||||
|
||||
# 操作
|
||||
s.add(6) # 添加元素
|
||||
s.remove(3) # 移除(元素不存在时抛出 KeyError)
|
||||
s.discard(3) # 移除(元素不存在时不报错)
|
||||
s.union({4, 5, 6}) # {1, 2, 3, 4, 5, 6}
|
||||
s.intersection({3, 4}) # {3, 4}
|
||||
s.difference({3, 4}) # {1, 2, 5}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 控制流
|
||||
|
||||
### If-Elif-Else
|
||||
```python
|
||||
x = 10
|
||||
|
||||
if x > 0:
|
||||
print("Positive")
|
||||
elif x < 0:
|
||||
print("Negative")
|
||||
else:
|
||||
print("Zero")
|
||||
|
||||
# 三元表达式
|
||||
result = "Positive" if x > 0 else "Non-positive"
|
||||
```
|
||||
|
||||
### 循环
|
||||
```python
|
||||
# For 循环
|
||||
for i in range(5): # 0, 1, 2, 3, 4
|
||||
print(i)
|
||||
|
||||
for i in range(2, 10, 2): # 2, 4, 6, 8
|
||||
print(i)
|
||||
|
||||
for item in [1, 2, 3]:
|
||||
print(item)
|
||||
|
||||
# Enumerate(索引 + 值)
|
||||
for i, val in enumerate(['a', 'b', 'c']):
|
||||
print(f"{i}: {val}")
|
||||
|
||||
# While 循环
|
||||
i = 0
|
||||
while i < 5:
|
||||
print(i)
|
||||
i += 1
|
||||
|
||||
# Break 和 continue
|
||||
for i in range(10):
|
||||
if i == 3:
|
||||
continue # 跳过 3
|
||||
if i == 8:
|
||||
break # 在 8 处停止
|
||||
print(i)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 函数
|
||||
|
||||
### 基本函数
|
||||
```python
|
||||
def greet(name):
|
||||
return f"Hello, {name}"
|
||||
|
||||
# 默认参数
|
||||
def greet(name="World"):
|
||||
return f"Hello, {name}"
|
||||
|
||||
# 多个返回值
|
||||
def divide(a, b):
|
||||
return a // b, a % b # 返回元组
|
||||
|
||||
quotient, remainder = divide(10, 3)
|
||||
|
||||
# *args 和 **kwargs
|
||||
def print_all(*args):
|
||||
for arg in args:
|
||||
print(arg)
|
||||
|
||||
def print_info(**kwargs):
|
||||
for key, value in kwargs.items():
|
||||
print(f"{key}: {value}")
|
||||
|
||||
print_all(1, 2, 3)
|
||||
print_info(name="Alice", age=30)
|
||||
```
|
||||
|
||||
### Lambda 函数
|
||||
```python
|
||||
# 匿名函数
|
||||
square = lambda x: x ** 2
|
||||
add = lambda x, y: x + y
|
||||
|
||||
# 常用于 map、filter、sorted
|
||||
nums = [1, 2, 3, 4, 5]
|
||||
squares = list(map(lambda x: x**2, nums))
|
||||
evens = list(filter(lambda x: x % 2 == 0, nums))
|
||||
sorted_tuples = sorted([(1, 'c'), (2, 'a')], key=lambda x: x[1])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 面向对象编程
|
||||
|
||||
### 类
|
||||
```python
|
||||
class Person:
|
||||
# 类变量
|
||||
species = "Homo sapiens"
|
||||
|
||||
def __init__(self, name, age):
|
||||
# 实例变量
|
||||
self.name = name
|
||||
self.age = age
|
||||
|
||||
def greet(self):
|
||||
return f"Hello, I'm {self.name}"
|
||||
|
||||
def __str__(self):
|
||||
return f"Person(name={self.name}, age={self.age})"
|
||||
|
||||
def __repr__(self):
|
||||
return f"Person('{self.name}', {self.age})"
|
||||
|
||||
# 使用
|
||||
p = Person("Alice", 30)
|
||||
print(p.greet())
|
||||
print(p) # 使用 __str__
|
||||
```
|
||||
|
||||
### 继承
|
||||
```python
|
||||
class Animal:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def speak(self):
|
||||
pass
|
||||
|
||||
class Dog(Animal):
|
||||
def speak(self):
|
||||
return f"{self.name} says Woof!"
|
||||
|
||||
class Cat(Animal):
|
||||
def speak(self):
|
||||
return f"{self.name} says Meow!"
|
||||
|
||||
dog = Dog("Buddy")
|
||||
print(dog.speak()) # Buddy says Woof!
|
||||
```
|
||||
|
||||
### 属性
|
||||
```python
|
||||
class Circle:
|
||||
def __init__(self, radius):
|
||||
self._radius = radius
|
||||
|
||||
@property
|
||||
def radius(self):
|
||||
return self._radius
|
||||
|
||||
@radius.setter
|
||||
def radius(self, value):
|
||||
if value < 0:
|
||||
raise ValueError("Radius cannot be negative")
|
||||
self._radius = value
|
||||
|
||||
@property
|
||||
def area(self):
|
||||
return 3.14159 * self._radius ** 2
|
||||
|
||||
# 使用
|
||||
c = Circle(5)
|
||||
print(c.area) # 78.53975
|
||||
c.radius = 10 # 使用 setter
|
||||
```
|
||||
|
||||
### 特殊方法(魔术方法)
|
||||
```python
|
||||
class Vector:
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __add__(self, other):
|
||||
return Vector(self.x + other.x, self.y + other.y)
|
||||
|
||||
def __str__(self):
|
||||
return f"Vector({self.x}, {self.y})"
|
||||
|
||||
def __len__(self):
|
||||
return 2
|
||||
|
||||
def __getitem__(self, index):
|
||||
return [self.x, self.y][index]
|
||||
|
||||
v1 = Vector(1, 2)
|
||||
v2 = Vector(3, 4)
|
||||
v3 = v1 + v2 # 使用 __add__
|
||||
print(v3) # 使用 __str__
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文件 I/O
|
||||
|
||||
```python
|
||||
# 读取
|
||||
with open('file.txt', 'r') as f:
|
||||
content = f.read() # 读取整个文件
|
||||
# 或
|
||||
lines = f.readlines() # 读取为行列表
|
||||
# 或
|
||||
for line in f: # 逐行迭代
|
||||
print(line.strip())
|
||||
|
||||
# 写入
|
||||
with open('file.txt', 'w') as f:
|
||||
f.write("Hello\n")
|
||||
f.writelines(["Line 1\n", "Line 2\n"])
|
||||
|
||||
# 追加
|
||||
with open('file.txt', 'a') as f:
|
||||
f.write("New line\n")
|
||||
|
||||
# JSON
|
||||
import json
|
||||
|
||||
# 写入 JSON
|
||||
data = {'name': 'Alice', 'age': 30}
|
||||
with open('data.json', 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
# 读取 JSON
|
||||
with open('data.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 错误处理
|
||||
|
||||
```python
|
||||
# Try-except
|
||||
try:
|
||||
result = 10 / 0
|
||||
except ZeroDivisionError:
|
||||
print("Cannot divide by zero")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
else:
|
||||
print("No errors") # 未发生异常时执行
|
||||
finally:
|
||||
print("Always runs") # 始终执行
|
||||
|
||||
# 抛出异常
|
||||
def divide(a, b):
|
||||
if b == 0:
|
||||
raise ValueError("Divisor cannot be zero")
|
||||
return a / b
|
||||
|
||||
# 自定义异常
|
||||
class InvalidAgeError(Exception):
|
||||
pass
|
||||
|
||||
def set_age(age):
|
||||
if age < 0:
|
||||
raise InvalidAgeError("Age cannot be negative")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常用库
|
||||
|
||||
### Collections
|
||||
```python
|
||||
from collections import Counter, defaultdict, deque
|
||||
|
||||
# Counter
|
||||
words = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
|
||||
count = Counter(words)
|
||||
print(count['apple']) # 3
|
||||
print(count.most_common(2)) # [('apple', 3), ('banana', 2)]
|
||||
|
||||
# defaultdict
|
||||
d = defaultdict(list)
|
||||
d['key'].append(1) # 不会抛出 KeyError
|
||||
|
||||
# deque(双端队列)
|
||||
q = deque([1, 2, 3])
|
||||
q.append(4) # 从右侧添加
|
||||
q.appendleft(0) # 从左侧添加
|
||||
q.pop() # 从右侧移除
|
||||
q.popleft() # 从左侧移除
|
||||
```
|
||||
|
||||
### Itertools
|
||||
```python
|
||||
from itertools import combinations, permutations, product
|
||||
|
||||
# 组合
|
||||
list(combinations([1, 2, 3], 2)) # [(1, 2), (1, 3), (2, 3)]
|
||||
|
||||
# 排列
|
||||
list(permutations([1, 2, 3], 2)) # [(1, 2), (1, 3), (2, 1), ...]
|
||||
|
||||
# 笛卡尔积
|
||||
list(product([1, 2], ['a', 'b'])) # [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]
|
||||
```
|
||||
|
||||
### Functools
|
||||
```python
|
||||
from functools import lru_cache, reduce
|
||||
|
||||
# 记忆化
|
||||
@lru_cache(maxsize=None)
|
||||
def fibonacci(n):
|
||||
if n < 2:
|
||||
return n
|
||||
return fibonacci(n-1) + fibonacci(n-2)
|
||||
|
||||
# Reduce
|
||||
from functools import reduce
|
||||
product = reduce(lambda x, y: x * y, [1, 2, 3, 4]) # 24
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 列表/字典/集合推导式
|
||||
|
||||
```python
|
||||
# 列表推导式
|
||||
squares = [x**2 for x in range(10)]
|
||||
evens = [x for x in range(10) if x % 2 == 0]
|
||||
nested = [[i for i in range(3)] for j in range(3)]
|
||||
|
||||
# 字典推导式
|
||||
squares_dict = {x: x**2 for x in range(5)}
|
||||
filtered = {k: v for k, v in squares_dict.items() if v > 5}
|
||||
|
||||
# 集合推导式
|
||||
unique_lengths = {len(word) for word in ['apple', 'banana', 'kiwi']}
|
||||
|
||||
# 生成器表达式(内存高效)
|
||||
sum_of_squares = sum(x**2 for x in range(1000000))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 有用的内置函数
|
||||
|
||||
```python
|
||||
# any, all
|
||||
any([False, True, False]) # True(至少一个为 True)
|
||||
all([True, True, True]) # True(全部为 True)
|
||||
|
||||
# zip
|
||||
names = ['Alice', 'Bob']
|
||||
ages = [30, 25]
|
||||
for name, age in zip(names, ages):
|
||||
print(f"{name}: {age}")
|
||||
|
||||
# enumerate
|
||||
for i, val in enumerate(['a', 'b', 'c']):
|
||||
print(f"{i}: {val}")
|
||||
|
||||
# map, filter
|
||||
nums = [1, 2, 3, 4, 5]
|
||||
squared = list(map(lambda x: x**2, nums))
|
||||
evens = list(filter(lambda x: x % 2 == 0, nums))
|
||||
|
||||
# sorted, reversed
|
||||
sorted([3, 1, 2]) # [1, 2, 3]
|
||||
sorted([3, 1, 2], reverse=True) # [3, 2, 1]
|
||||
list(reversed([1, 2, 3])) # [3, 2, 1]
|
||||
|
||||
# max, min, sum
|
||||
max([1, 5, 3]) # 5
|
||||
min([1, 5, 3]) # 1
|
||||
sum([1, 2, 3]) # 6
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常用惯用法
|
||||
|
||||
### 变量交换
|
||||
```python
|
||||
a, b = b, a
|
||||
```
|
||||
|
||||
### 三元运算符
|
||||
```python
|
||||
result = "Even" if x % 2 == 0 else "Odd"
|
||||
```
|
||||
|
||||
### 字典默认值
|
||||
```python
|
||||
value = my_dict.get('key', default_value)
|
||||
```
|
||||
|
||||
### 带起始值的 Enumerate
|
||||
```python
|
||||
for i, val in enumerate(items, start=1):
|
||||
print(f"{i}. {val}")
|
||||
```
|
||||
|
||||
### 解包
|
||||
```python
|
||||
first, *middle, last = [1, 2, 3, 4, 5]
|
||||
# first=1, middle=[2,3,4], last=5
|
||||
```
|
||||
|
||||
### 上下文管理器
|
||||
```python
|
||||
with open('file.txt') as f:
|
||||
data = f.read()
|
||||
# 文件自动关闭
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. PEP 8 风格指南
|
||||
```python
|
||||
# 使用 4 个空格缩进
|
||||
# 变量和函数使用 snake_case
|
||||
# 类使用 PascalCase
|
||||
# 常量使用大写
|
||||
|
||||
def calculate_total(items):
|
||||
DISCOUNT_RATE = 0.1
|
||||
total = sum(items)
|
||||
return total * (1 - DISCOUNT_RATE)
|
||||
```
|
||||
|
||||
### 2. 列表推导式 vs 循环
|
||||
```python
|
||||
# 简单转换优先使用推导式
|
||||
squares = [x**2 for x in range(10)]
|
||||
|
||||
# 复杂逻辑使用循环
|
||||
results = []
|
||||
for x in range(10):
|
||||
if x % 2 == 0:
|
||||
result = process_even(x)
|
||||
else:
|
||||
result = process_odd(x)
|
||||
results.append(result)
|
||||
```
|
||||
|
||||
### 3. None 用 `is`,值比较用 `==`
|
||||
```python
|
||||
if value is None: # 正确
|
||||
if value == None: # 也能工作但不推荐
|
||||
```
|
||||
|
||||
### 4. EAFP 与 LBYL
|
||||
```python
|
||||
# 请求原谅比获得许可更容易(Pythonic 风格)
|
||||
try:
|
||||
value = my_dict['key']
|
||||
except KeyError:
|
||||
value = default
|
||||
|
||||
# 三思而后行(不够 Pythonic)
|
||||
if 'key' in my_dict:
|
||||
value = my_dict['key']
|
||||
else:
|
||||
value = default
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见陷阱
|
||||
|
||||
### 1. 可变默认参数
|
||||
```python
|
||||
# 错误
|
||||
def append_to(element, lst=[]):
|
||||
lst.append(element)
|
||||
return lst
|
||||
|
||||
# 所有调用共享同一个列表!
|
||||
print(append_to(1)) # [1]
|
||||
print(append_to(2)) # [1, 2] — 不符合预期!
|
||||
|
||||
# 正确
|
||||
def append_to(element, lst=None):
|
||||
if lst is None:
|
||||
lst = []
|
||||
lst.append(element)
|
||||
return lst
|
||||
```
|
||||
|
||||
### 2. 闭包延迟绑定
|
||||
```python
|
||||
# 错误
|
||||
funcs = [lambda: i for i in range(5)]
|
||||
print([f() for f in funcs]) # [4, 4, 4, 4, 4]
|
||||
|
||||
# 正确
|
||||
funcs = [lambda i=i: i for i in range(5)]
|
||||
print([f() for f in funcs]) # [0, 1, 2, 3, 4]
|
||||
```
|
||||
|
||||
### 3. 遍历列表时修改
|
||||
```python
|
||||
# 错误
|
||||
lst = [1, 2, 3, 4, 5]
|
||||
for item in lst:
|
||||
if item % 2 == 0:
|
||||
lst.remove(item) # 可能跳过元素
|
||||
|
||||
# 正确
|
||||
lst = [item for item in lst if item % 2 != 0]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Python 3.10+ 特性
|
||||
|
||||
### 结构化模式匹配
|
||||
```python
|
||||
def process_command(command):
|
||||
match command.split():
|
||||
case ["quit"]:
|
||||
return "Quitting"
|
||||
case ["load", filename]:
|
||||
return f"Loading {filename}"
|
||||
case ["save", filename]:
|
||||
return f"Saving {filename}"
|
||||
case _:
|
||||
return "Unknown command"
|
||||
```
|
||||
|
||||
### 联合类型
|
||||
```python
|
||||
def greet(name: str | None = None) -> str:
|
||||
if name is None:
|
||||
return "Hello, stranger"
|
||||
return f"Hello, {name}"
|
||||
```
|
||||
@@ -0,0 +1,26 @@
|
||||
# 学习日志
|
||||
|
||||
本文档用于记录你在 Code Mentor 中的学习进度与成长历程。每次学习结束后,你的进度会自动保存。
|
||||
|
||||
## 学习历史
|
||||
|
||||
*随着你的学习,以下将记录每次的学习记录……*
|
||||
|
||||
---
|
||||
|
||||
## 已掌握知识点
|
||||
|
||||
*你已熟练掌握的主题将显示在这里……*
|
||||
|
||||
## 待复习内容
|
||||
|
||||
*需要进一步练习的主题将在此处追踪……*
|
||||
|
||||
## 学习目标
|
||||
|
||||
*你的学习目标将在此处追踪……*
|
||||
|
||||
---
|
||||
|
||||
**最近更新**:初始设置
|
||||
**总学习次数**:0
|
||||
@@ -0,0 +1,15 @@
|
||||
# Code Mentor - Python 依赖
|
||||
# 以下为脚本功能的可选增强
|
||||
# 技能本身无需这些依赖即可完美运行!
|
||||
|
||||
# 用于代码分析(analyze_code.py)
|
||||
pylint>=2.15.0
|
||||
|
||||
# 用于测试(run_tests.py)
|
||||
pytest>=7.2.0
|
||||
|
||||
# 用于更好的输出格式化
|
||||
colorama>=0.4.6
|
||||
|
||||
# 注意:JavaScript 测试需要 Jest(通过 npm 安装)
|
||||
# npm install --save-dev jest
|
||||
@@ -0,0 +1,379 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Code Analyzer - Static analysis tool for code review
|
||||
|
||||
Analyzes code for:
|
||||
- Bugs and potential errors
|
||||
- Style violations
|
||||
- Complexity metrics
|
||||
- Security issues
|
||||
- Best practice violations
|
||||
|
||||
Supports: Python, JavaScript, Java, C++
|
||||
|
||||
Usage:
|
||||
python analyze_code.py <file_path>
|
||||
python analyze_code.py <file_path> --format json
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import ast
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any
|
||||
|
||||
|
||||
class CodeIssue:
|
||||
"""Represents a code issue found during analysis."""
|
||||
|
||||
def __init__(self, category, severity, line, message, suggestion=None):
|
||||
self.category = category # bug, style, performance, security
|
||||
self.severity = severity # critical, warning, info
|
||||
self.line = line
|
||||
self.message = message
|
||||
self.suggestion = suggestion
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'category': self.category,
|
||||
'severity': self.severity,
|
||||
'line': self.line,
|
||||
'message': self.message,
|
||||
'suggestion': self.suggestion
|
||||
}
|
||||
|
||||
|
||||
class PythonAnalyzer:
|
||||
"""Analyzer for Python code."""
|
||||
|
||||
def __init__(self, code, filename):
|
||||
self.code = code
|
||||
self.filename = filename
|
||||
self.lines = code.split('\n')
|
||||
self.issues = []
|
||||
|
||||
def analyze(self) -> List[CodeIssue]:
|
||||
"""Run all analysis checks."""
|
||||
try:
|
||||
tree = ast.parse(self.code)
|
||||
self._check_syntax(tree)
|
||||
except SyntaxError as e:
|
||||
self.issues.append(CodeIssue(
|
||||
'bug', 'critical', e.lineno,
|
||||
f"Syntax error: {e.msg}"
|
||||
))
|
||||
return self.issues
|
||||
|
||||
self._check_style()
|
||||
self._check_complexity()
|
||||
self._check_best_practices()
|
||||
self._check_security()
|
||||
|
||||
return self.issues
|
||||
|
||||
def _check_syntax(self, tree):
|
||||
"""Check for common syntax and logic issues."""
|
||||
for node in ast.walk(tree):
|
||||
# Check for bare except
|
||||
if isinstance(node, ast.ExceptHandler):
|
||||
if node.type is None:
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'warning', node.lineno,
|
||||
"Bare except: clause catches all exceptions",
|
||||
"Use specific exception types (e.g., except ValueError:)"
|
||||
))
|
||||
|
||||
# Check for mutable default arguments
|
||||
if isinstance(node, ast.FunctionDef):
|
||||
for default in node.args.defaults:
|
||||
if isinstance(default, (ast.List, ast.Dict, ast.Set)):
|
||||
self.issues.append(CodeIssue(
|
||||
'bug', 'warning', node.lineno,
|
||||
f"Mutable default argument in function '{node.name}'",
|
||||
"Use None as default and create mutable object inside function"
|
||||
))
|
||||
|
||||
def _check_style(self):
|
||||
"""Check PEP 8 style guidelines."""
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
# Line too long
|
||||
if len(line) > 100:
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'info', i,
|
||||
f"Line too long ({len(line)} > 100 characters)"
|
||||
))
|
||||
|
||||
# Multiple statements on one line
|
||||
if ';' in line and not line.strip().startswith('#'):
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'info', i,
|
||||
"Multiple statements on one line (use semicolon)",
|
||||
"Place each statement on its own line"
|
||||
))
|
||||
|
||||
# Trailing whitespace
|
||||
if line.endswith(' ') or line.endswith('\t'):
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'info', i,
|
||||
"Trailing whitespace"
|
||||
))
|
||||
|
||||
def _check_complexity(self):
|
||||
"""Check for complexity issues."""
|
||||
try:
|
||||
tree = ast.parse(self.code)
|
||||
except:
|
||||
return
|
||||
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.FunctionDef):
|
||||
# Count nested depth
|
||||
max_depth = self._calculate_nesting_depth(node)
|
||||
if max_depth > 4:
|
||||
self.issues.append(CodeIssue(
|
||||
'performance', 'warning', node.lineno,
|
||||
f"Function '{node.name}' has deep nesting (depth {max_depth})",
|
||||
"Consider extracting nested logic into separate functions"
|
||||
))
|
||||
|
||||
# Count number of statements
|
||||
statements = sum(1 for _ in ast.walk(node))
|
||||
if statements > 50:
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'warning', node.lineno,
|
||||
f"Function '{node.name}' is too long ({statements} statements)",
|
||||
"Consider breaking into smaller functions"
|
||||
))
|
||||
|
||||
def _calculate_nesting_depth(self, node, depth=0):
|
||||
"""Calculate maximum nesting depth in a function."""
|
||||
max_depth = depth
|
||||
for child in ast.iter_child_nodes(node):
|
||||
if isinstance(child, (ast.If, ast.For, ast.While, ast.With)):
|
||||
child_depth = self._calculate_nesting_depth(child, depth + 1)
|
||||
max_depth = max(max_depth, child_depth)
|
||||
return max_depth
|
||||
|
||||
def _check_best_practices(self):
|
||||
"""Check for violations of best practices."""
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
# Check for print statements in production code
|
||||
if re.search(r'\bprint\s*\(', line) and 'debug' not in line.lower():
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'info', i,
|
||||
"Print statement found - consider using logging",
|
||||
"Use logging module instead of print for production code"
|
||||
))
|
||||
|
||||
# Check for == None instead of is None
|
||||
if re.search(r'==\s*None|None\s*==', line):
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'info', i,
|
||||
"Use 'is None' instead of '== None'"
|
||||
))
|
||||
|
||||
# Check for != None instead of is not None
|
||||
if re.search(r'!=\s*None|None\s*!=', line):
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'info', i,
|
||||
"Use 'is not None' instead of '!= None'"
|
||||
))
|
||||
|
||||
def _check_security(self):
|
||||
"""Check for common security issues."""
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
# SQL injection vulnerability
|
||||
if 'execute' in line and ('+' in line or '%' in line or 'format' in line):
|
||||
if 'SELECT' in line.upper() or 'INSERT' in line.upper():
|
||||
self.issues.append(CodeIssue(
|
||||
'security', 'critical', i,
|
||||
"Potential SQL injection vulnerability",
|
||||
"Use parameterized queries with placeholders"
|
||||
))
|
||||
|
||||
# eval() usage
|
||||
if re.search(r'\beval\s*\(', line):
|
||||
self.issues.append(CodeIssue(
|
||||
'security', 'critical', i,
|
||||
"Use of eval() is dangerous",
|
||||
"Avoid eval() - use ast.literal_eval() for safe evaluation"
|
||||
))
|
||||
|
||||
# Hard-coded passwords/secrets
|
||||
if re.search(r'password\s*=\s*["\']', line, re.IGNORECASE):
|
||||
self.issues.append(CodeIssue(
|
||||
'security', 'critical', i,
|
||||
"Potential hard-coded password",
|
||||
"Use environment variables or secure configuration"
|
||||
))
|
||||
|
||||
|
||||
class JavaScriptAnalyzer:
|
||||
"""Basic analyzer for JavaScript code."""
|
||||
|
||||
def __init__(self, code, filename):
|
||||
self.code = code
|
||||
self.filename = filename
|
||||
self.lines = code.split('\n')
|
||||
self.issues = []
|
||||
|
||||
def analyze(self) -> List[CodeIssue]:
|
||||
"""Run all analysis checks."""
|
||||
self._check_style()
|
||||
self._check_best_practices()
|
||||
return self.issues
|
||||
|
||||
def _check_style(self):
|
||||
"""Check style guidelines."""
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
# var instead of let/const
|
||||
if re.search(r'\bvar\s+', line):
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'warning', i,
|
||||
"Use 'let' or 'const' instead of 'var'",
|
||||
"ES6+ recommends let/const for better scoping"
|
||||
))
|
||||
|
||||
# == instead of ===
|
||||
if '==' in line and '===' not in line and '!==' not in line:
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'info', i,
|
||||
"Use '===' instead of '==' for strict equality"
|
||||
))
|
||||
|
||||
def _check_best_practices(self):
|
||||
"""Check JavaScript best practices."""
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
# console.log in production
|
||||
if 'console.log' in line:
|
||||
self.issues.append(CodeIssue(
|
||||
'style', 'info', i,
|
||||
"console.log found - remove before production"
|
||||
))
|
||||
|
||||
|
||||
class CodeMetrics:
|
||||
"""Calculate code metrics."""
|
||||
|
||||
def __init__(self, code):
|
||||
self.code = code
|
||||
self.lines = code.split('\n')
|
||||
|
||||
def calculate(self) -> Dict[str, Any]:
|
||||
"""Calculate various metrics."""
|
||||
total_lines = len(self.lines)
|
||||
code_lines = sum(1 for line in self.lines if line.strip() and not line.strip().startswith('#'))
|
||||
comment_lines = sum(1 for line in self.lines if line.strip().startswith('#'))
|
||||
blank_lines = total_lines - code_lines - comment_lines
|
||||
|
||||
return {
|
||||
'total_lines': total_lines,
|
||||
'code_lines': code_lines,
|
||||
'comment_lines': comment_lines,
|
||||
'blank_lines': blank_lines,
|
||||
'comment_ratio': round(comment_lines / max(code_lines, 1), 2)
|
||||
}
|
||||
|
||||
|
||||
def detect_language(filename):
|
||||
"""Detect programming language from file extension."""
|
||||
ext = Path(filename).suffix.lower()
|
||||
language_map = {
|
||||
'.py': 'python',
|
||||
'.js': 'javascript',
|
||||
'.jsx': 'javascript',
|
||||
'.ts': 'javascript',
|
||||
'.tsx': 'javascript',
|
||||
'.java': 'java',
|
||||
'.cpp': 'cpp',
|
||||
'.cc': 'cpp',
|
||||
'.cxx': 'cpp',
|
||||
'.c': 'c'
|
||||
}
|
||||
return language_map.get(ext, 'unknown')
|
||||
|
||||
|
||||
def analyze_file(filepath, output_format='text'):
|
||||
"""Analyze a code file."""
|
||||
if not os.path.exists(filepath):
|
||||
print(f"Error: File '{filepath}' not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
code = f.read()
|
||||
|
||||
language = detect_language(filepath)
|
||||
|
||||
# Choose analyzer based on language
|
||||
if language == 'python':
|
||||
analyzer = PythonAnalyzer(code, filepath)
|
||||
elif language == 'javascript':
|
||||
analyzer = JavaScriptAnalyzer(code, filepath)
|
||||
else:
|
||||
print(f"Error: Unsupported language '{language}'", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Run analysis
|
||||
issues = analyzer.analyze()
|
||||
|
||||
# Calculate metrics
|
||||
metrics = CodeMetrics(code).calculate()
|
||||
|
||||
# Output results
|
||||
if output_format == 'json':
|
||||
result = {
|
||||
'file': filepath,
|
||||
'language': language,
|
||||
'metrics': metrics,
|
||||
'issues': [issue.to_dict() for issue in issues]
|
||||
}
|
||||
print(json.dumps(result, indent=2))
|
||||
else:
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f"Code Analysis: {filepath}")
|
||||
print(f"Language: {language}")
|
||||
print(f"{'=' * 60}\n")
|
||||
|
||||
print("METRICS:")
|
||||
print(f" Total lines: {metrics['total_lines']}")
|
||||
print(f" Code lines: {metrics['code_lines']}")
|
||||
print(f" Comment lines: {metrics['comment_lines']}")
|
||||
print(f" Blank lines: {metrics['blank_lines']}")
|
||||
print(f" Comment ratio: {metrics['comment_ratio']:.2%}\n")
|
||||
|
||||
if issues:
|
||||
print(f"ISSUES FOUND: {len(issues)}\n")
|
||||
|
||||
# Group by severity
|
||||
critical = [i for i in issues if i.severity == 'critical']
|
||||
warnings = [i for i in issues if i.severity == 'warning']
|
||||
info = [i for i in issues if i.severity == 'info']
|
||||
|
||||
for severity, items in [('CRITICAL', critical), ('WARNING', warnings), ('INFO', info)]:
|
||||
if items:
|
||||
print(f"{severity}:")
|
||||
for issue in items:
|
||||
print(f" Line {issue.line}: [{issue.category}] {issue.message}")
|
||||
if issue.suggestion:
|
||||
print(f" → {issue.suggestion}")
|
||||
print()
|
||||
else:
|
||||
print("✓ No issues found!\n")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Analyze code for issues and metrics')
|
||||
parser.add_argument('file', help='Path to code file to analyze')
|
||||
parser.add_argument('--format', choices=['text', 'json'], default='text',
|
||||
help='Output format (default: text)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
analyze_file(args.file, args.format)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,291 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Complexity Analyzer - Analyze time and space complexity of algorithms
|
||||
|
||||
Features:
|
||||
- Parse code using AST
|
||||
- Detect loops (nested, sequential)
|
||||
- Identify recursion
|
||||
- Analyze data structure operations
|
||||
- Estimate Big-O complexity
|
||||
- Suggest optimizations
|
||||
|
||||
Usage:
|
||||
python complexity_analyzer.py <file_path> [--function <function_name>]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import ast
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
|
||||
class ComplexityAnalyzer(ast.NodeVisitor):
|
||||
"""Analyze time and space complexity of Python code."""
|
||||
|
||||
def __init__(self, function_name=None):
|
||||
self.function_name = function_name
|
||||
self.results = {}
|
||||
self.current_function = None
|
||||
|
||||
def visit_FunctionDef(self, node):
|
||||
"""Analyze a function definition."""
|
||||
# Only analyze specific function if requested
|
||||
if self.function_name and node.name != self.function_name:
|
||||
return
|
||||
|
||||
self.current_function = node.name
|
||||
|
||||
analysis = {
|
||||
'name': node.name,
|
||||
'line': node.lineno,
|
||||
'time_complexity': 'O(1)',
|
||||
'space_complexity': 'O(1)',
|
||||
'loops': [],
|
||||
'recursion': False,
|
||||
'operations': [],
|
||||
'suggestions': []
|
||||
}
|
||||
|
||||
# Analyze the function body
|
||||
loop_depth = self._analyze_loops(node)
|
||||
has_recursion = self._check_recursion(node)
|
||||
data_structure_ops = self._analyze_data_structures(node)
|
||||
|
||||
# Determine time complexity
|
||||
if has_recursion:
|
||||
analysis['recursion'] = True
|
||||
recursion_type = self._classify_recursion(node)
|
||||
analysis['time_complexity'] = recursion_type
|
||||
analysis['suggestions'].append(
|
||||
"Recursive function - consider memoization or iterative approach"
|
||||
)
|
||||
elif loop_depth >= 3:
|
||||
analysis['time_complexity'] = f'O(n^{loop_depth})'
|
||||
analysis['suggestions'].append(
|
||||
f"Deep nesting ({loop_depth} levels) - consider optimization"
|
||||
)
|
||||
elif loop_depth == 2:
|
||||
analysis['time_complexity'] = 'O(n²)'
|
||||
analysis['suggestions'].append(
|
||||
"Nested loop detected - can this be optimized with hash map?"
|
||||
)
|
||||
elif loop_depth == 1:
|
||||
analysis['time_complexity'] = 'O(n)'
|
||||
|
||||
# Adjust for data structure operations
|
||||
for op in data_structure_ops:
|
||||
if op['type'] == 'sort':
|
||||
if 'n²' not in analysis['time_complexity']:
|
||||
analysis['time_complexity'] = 'O(n log n)'
|
||||
elif op['type'] == 'dict_lookup':
|
||||
analysis['operations'].append(op)
|
||||
elif op['type'] == 'list_search':
|
||||
if loop_depth == 0:
|
||||
analysis['time_complexity'] = 'O(n)'
|
||||
|
||||
# Analyze space complexity
|
||||
space = self._analyze_space_complexity(node)
|
||||
analysis['space_complexity'] = space
|
||||
|
||||
self.results[node.name] = analysis
|
||||
self.generic_visit(node)
|
||||
|
||||
def _analyze_loops(self, node, depth=0) -> int:
|
||||
"""Calculate maximum loop nesting depth."""
|
||||
max_depth = depth
|
||||
|
||||
for child in ast.walk(node):
|
||||
if isinstance(child, (ast.For, ast.While)):
|
||||
# Check if this is a direct child, not in a nested function
|
||||
if self._is_direct_child(node, child):
|
||||
child_depth = self._analyze_loops(child, depth + 1)
|
||||
max_depth = max(max_depth, child_depth)
|
||||
|
||||
return max_depth
|
||||
|
||||
def _is_direct_child(self, parent, child):
|
||||
"""Check if child is a direct descendant (not in nested function)."""
|
||||
for node in ast.walk(parent):
|
||||
if node == child:
|
||||
return True
|
||||
if isinstance(node, ast.FunctionDef) and node != parent:
|
||||
# Stop if we hit another function definition
|
||||
return False
|
||||
return False
|
||||
|
||||
def _check_recursion(self, node) -> bool:
|
||||
"""Check if function is recursive."""
|
||||
function_name = node.name
|
||||
|
||||
for child in ast.walk(node):
|
||||
if isinstance(child, ast.Call):
|
||||
if isinstance(child.func, ast.Name) and child.func.id == function_name:
|
||||
return True
|
||||
# Check for indirect recursion via attribute
|
||||
if isinstance(child.func, ast.Attribute):
|
||||
if child.func.attr == function_name:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _classify_recursion(self, node) -> str:
|
||||
"""Classify type of recursion for complexity estimation."""
|
||||
# Count recursive calls
|
||||
recursive_calls = 0
|
||||
function_name = node.name
|
||||
|
||||
for child in ast.walk(node):
|
||||
if isinstance(child, ast.Call):
|
||||
if isinstance(child.func, ast.Name) and child.func.id == function_name:
|
||||
recursive_calls += 1
|
||||
|
||||
if recursive_calls == 1:
|
||||
# Linear recursion (e.g., factorial)
|
||||
return 'O(n)'
|
||||
elif recursive_calls == 2:
|
||||
# Binary recursion (e.g., fibonacci)
|
||||
return 'O(2^n)'
|
||||
else:
|
||||
return 'O(recursive)'
|
||||
|
||||
def _analyze_data_structures(self, node) -> List[Dict]:
|
||||
"""Analyze data structure operations."""
|
||||
operations = []
|
||||
|
||||
for child in ast.walk(node):
|
||||
# Sorting
|
||||
if isinstance(child, ast.Call):
|
||||
if isinstance(child.func, ast.Attribute):
|
||||
if child.func.attr == 'sort':
|
||||
operations.append({'type': 'sort', 'line': child.lineno})
|
||||
elif isinstance(child.func, ast.Name):
|
||||
if child.func.id == 'sorted':
|
||||
operations.append({'type': 'sort', 'line': child.lineno})
|
||||
|
||||
# Dictionary/set operations (O(1) average)
|
||||
if isinstance(child, ast.Subscript):
|
||||
if isinstance(child.value, (ast.Dict, ast.Set)):
|
||||
operations.append({'type': 'dict_lookup', 'line': child.lineno})
|
||||
|
||||
# List search operations (O(n))
|
||||
if isinstance(child, ast.Compare):
|
||||
if any(isinstance(op, ast.In) for op in child.ops):
|
||||
operations.append({'type': 'list_search', 'line': child.lineno})
|
||||
|
||||
return operations
|
||||
|
||||
def _analyze_space_complexity(self, node) -> str:
|
||||
"""Estimate space complexity."""
|
||||
# Check for list comprehensions, array creation
|
||||
has_array_creation = False
|
||||
has_recursion = self._check_recursion(node)
|
||||
|
||||
for child in ast.walk(node):
|
||||
# List comprehension or list creation
|
||||
if isinstance(child, (ast.ListComp, ast.List)):
|
||||
has_array_creation = True
|
||||
|
||||
# Dictionary comprehension
|
||||
if isinstance(child, (ast.DictComp, ast.Dict)):
|
||||
has_array_creation = True
|
||||
|
||||
if has_recursion:
|
||||
# Recursion uses call stack
|
||||
return 'O(n) - call stack'
|
||||
elif has_array_creation:
|
||||
return 'O(n) - auxiliary space'
|
||||
else:
|
||||
return 'O(1)'
|
||||
|
||||
|
||||
def format_output(results, output_format='text'):
|
||||
"""Format analysis results."""
|
||||
if output_format == 'json':
|
||||
print(json.dumps(results, indent=2))
|
||||
else:
|
||||
print("\n" + "=" * 60)
|
||||
print("COMPLEXITY ANALYSIS")
|
||||
print("=" * 60 + "\n")
|
||||
|
||||
for func_name, analysis in results.items():
|
||||
print(f"Function: {func_name} (line {analysis['line']})")
|
||||
print(f" Time Complexity: {analysis['time_complexity']}")
|
||||
print(f" Space Complexity: {analysis['space_complexity']}")
|
||||
|
||||
if analysis['recursion']:
|
||||
print(f" Recursion: Yes")
|
||||
|
||||
if analysis['operations']:
|
||||
print(f" Operations:")
|
||||
for op in analysis['operations']:
|
||||
print(f" - {op['type']} at line {op['line']}")
|
||||
|
||||
if analysis['suggestions']:
|
||||
print(f" Suggestions:")
|
||||
for suggestion in analysis['suggestions']:
|
||||
print(f" → {suggestion}")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
def analyze_file(filepath, function_name=None, output_format='text'):
|
||||
"""Analyze a Python file."""
|
||||
if not os.path.exists(filepath):
|
||||
print(f"Error: File '{filepath}' not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
code = f.read()
|
||||
|
||||
try:
|
||||
tree = ast.parse(code)
|
||||
except SyntaxError as e:
|
||||
print(f"Syntax error in file: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
analyzer = ComplexityAnalyzer(function_name)
|
||||
analyzer.visit(tree)
|
||||
|
||||
if not analyzer.results:
|
||||
if function_name:
|
||||
print(f"Error: Function '{function_name}' not found", file=sys.stderr)
|
||||
else:
|
||||
print("No functions found in file", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
format_output(analyzer.results, output_format)
|
||||
|
||||
|
||||
def analyze_code_snippet(code, output_format='text'):
|
||||
"""Analyze a code snippet."""
|
||||
try:
|
||||
tree = ast.parse(code)
|
||||
except SyntaxError as e:
|
||||
print(f"Syntax error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
analyzer = ComplexityAnalyzer()
|
||||
analyzer.visit(tree)
|
||||
|
||||
format_output(analyzer.results, output_format)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Analyze time and space complexity of code'
|
||||
)
|
||||
parser.add_argument('file', help='Python file to analyze')
|
||||
parser.add_argument('--function', help='Specific function to analyze')
|
||||
parser.add_argument('--format', choices=['text', 'json'], default='text',
|
||||
help='Output format (default: text)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
analyze_file(args.file, args.function, args.format)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,334 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test Runner - Execute and format test results
|
||||
|
||||
Supports:
|
||||
- pytest (Python)
|
||||
- unittest (Python)
|
||||
- jest (JavaScript)
|
||||
- JUnit (Java)
|
||||
|
||||
Usage:
|
||||
python run_tests.py <test_file>
|
||||
python run_tests.py <test_directory>
|
||||
python run_tests.py --framework pytest
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class TestResult:
|
||||
"""Represents test execution results."""
|
||||
|
||||
def __init__(self):
|
||||
self.passed = 0
|
||||
self.failed = 0
|
||||
self.errors = 0
|
||||
self.skipped = 0
|
||||
self.total = 0
|
||||
self.duration = 0.0
|
||||
self.failures = []
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'passed': self.passed,
|
||||
'failed': self.failed,
|
||||
'errors': self.errors,
|
||||
'skipped': self.skipped,
|
||||
'total': self.total,
|
||||
'duration': self.duration,
|
||||
'failures': self.failures
|
||||
}
|
||||
|
||||
|
||||
class TestRunner:
|
||||
"""Base class for test runners."""
|
||||
|
||||
def __init__(self, target):
|
||||
self.target = target
|
||||
|
||||
def run(self) -> TestResult:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class PytestRunner(TestRunner):
|
||||
"""Run pytest tests."""
|
||||
|
||||
def run(self) -> TestResult:
|
||||
result = TestResult()
|
||||
|
||||
try:
|
||||
# Run pytest with verbose output and JSON report
|
||||
cmd = [
|
||||
'python', '-m', 'pytest',
|
||||
self.target,
|
||||
'-v',
|
||||
'--tb=short'
|
||||
]
|
||||
|
||||
process = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
# Parse output
|
||||
output = process.stdout + process.stderr
|
||||
lines = output.split('\n')
|
||||
|
||||
for line in lines:
|
||||
if ' PASSED' in line:
|
||||
result.passed += 1
|
||||
elif ' FAILED' in line:
|
||||
result.failed += 1
|
||||
# Extract test name and failure info
|
||||
test_name = line.split('::')[1].split(' ')[0] if '::' in line else 'unknown'
|
||||
result.failures.append({
|
||||
'test': test_name,
|
||||
'message': 'See output for details'
|
||||
})
|
||||
elif ' ERROR' in line:
|
||||
result.errors += 1
|
||||
elif ' SKIPPED' in line:
|
||||
result.skipped += 1
|
||||
|
||||
# Extract duration
|
||||
if 'passed in' in line or 'failed in' in line:
|
||||
try:
|
||||
duration_str = line.split(' in ')[1].split('s')[0]
|
||||
result.duration = float(duration_str)
|
||||
except:
|
||||
pass
|
||||
|
||||
result.total = result.passed + result.failed + result.errors + result.skipped
|
||||
|
||||
return result
|
||||
|
||||
except FileNotFoundError:
|
||||
print("Error: pytest not found. Install with: pip install pytest", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except subprocess.TimeoutExpired:
|
||||
print("Error: Tests timed out after 60 seconds", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error running tests: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class UnittestRunner(TestRunner):
|
||||
"""Run unittest tests."""
|
||||
|
||||
def run(self) -> TestResult:
|
||||
result = TestResult()
|
||||
|
||||
try:
|
||||
cmd = [
|
||||
'python', '-m', 'unittest',
|
||||
'discover',
|
||||
'-s', self.target,
|
||||
'-v'
|
||||
]
|
||||
|
||||
process = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
output = process.stdout + process.stderr
|
||||
lines = output.split('\n')
|
||||
|
||||
for line in lines:
|
||||
if ' ... ok' in line:
|
||||
result.passed += 1
|
||||
elif 'FAIL:' in line:
|
||||
result.failed += 1
|
||||
test_name = line.replace('FAIL:', '').strip()
|
||||
result.failures.append({
|
||||
'test': test_name,
|
||||
'message': 'See output for details'
|
||||
})
|
||||
elif 'ERROR:' in line:
|
||||
result.errors += 1
|
||||
|
||||
# Parse summary line
|
||||
for line in reversed(lines):
|
||||
if 'Ran ' in line and ' test' in line:
|
||||
try:
|
||||
result.total = int(line.split('Ran ')[1].split(' test')[0])
|
||||
except:
|
||||
pass
|
||||
break
|
||||
|
||||
return result
|
||||
|
||||
except FileNotFoundError:
|
||||
print("Error: unittest module not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error running tests: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class JestRunner(TestRunner):
|
||||
"""Run Jest tests."""
|
||||
|
||||
def run(self) -> TestResult:
|
||||
result = TestResult()
|
||||
|
||||
try:
|
||||
cmd = ['npx', 'jest', self.target, '--verbose']
|
||||
|
||||
process = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
output = process.stdout + process.stderr
|
||||
lines = output.split('\n')
|
||||
|
||||
for line in lines:
|
||||
if '✓' in line or 'PASS' in line:
|
||||
result.passed += 1
|
||||
elif '✕' in line or 'FAIL' in line:
|
||||
result.failed += 1
|
||||
|
||||
# Parse summary
|
||||
for line in lines:
|
||||
if 'Tests:' in line:
|
||||
parts = line.split(',')
|
||||
for part in parts:
|
||||
if 'passed' in part:
|
||||
try:
|
||||
result.passed = int(part.split()[0])
|
||||
except:
|
||||
pass
|
||||
elif 'failed' in part:
|
||||
try:
|
||||
result.failed = int(part.split()[0])
|
||||
except:
|
||||
pass
|
||||
|
||||
result.total = result.passed + result.failed
|
||||
|
||||
return result
|
||||
|
||||
except FileNotFoundError:
|
||||
print("Error: Jest not found. Install with: npm install --save-dev jest", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error running tests: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def detect_framework(target):
|
||||
"""Detect testing framework to use."""
|
||||
# Check if it's a Python file
|
||||
if target.endswith('.py') or os.path.isdir(target):
|
||||
# Check for pytest markers
|
||||
if os.path.isfile(target):
|
||||
with open(target, 'r') as f:
|
||||
content = f.read()
|
||||
if 'import pytest' in content or '@pytest' in content:
|
||||
return 'pytest'
|
||||
elif 'import unittest' in content or 'class Test' in content:
|
||||
return 'unittest'
|
||||
else:
|
||||
# Check for pytest.ini or setup.cfg
|
||||
if os.path.exists('pytest.ini') or os.path.exists('setup.cfg'):
|
||||
return 'pytest'
|
||||
return 'unittest'
|
||||
|
||||
# Check if it's JavaScript
|
||||
elif target.endswith('.js') or target.endswith('.test.js'):
|
||||
return 'jest'
|
||||
|
||||
return 'pytest' # Default
|
||||
|
||||
|
||||
def run_tests(target, framework=None, output_format='text'):
|
||||
"""Run tests and format output."""
|
||||
if not os.path.exists(target):
|
||||
print(f"Error: Target '{target}' not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Detect framework if not specified
|
||||
if framework is None:
|
||||
framework = detect_framework(target)
|
||||
|
||||
# Create appropriate runner
|
||||
if framework == 'pytest':
|
||||
runner = PytestRunner(target)
|
||||
elif framework == 'unittest':
|
||||
runner = UnittestRunner(target)
|
||||
elif framework == 'jest':
|
||||
runner = JestRunner(target)
|
||||
else:
|
||||
print(f"Error: Unsupported framework '{framework}'", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\nRunning tests with {framework}...")
|
||||
print(f"Target: {target}\n")
|
||||
|
||||
# Run tests
|
||||
result = runner.run()
|
||||
|
||||
# Output results
|
||||
if output_format == 'json':
|
||||
print(json.dumps(result.to_dict(), indent=2))
|
||||
else:
|
||||
print("=" * 60)
|
||||
print("TEST RESULTS")
|
||||
print("=" * 60)
|
||||
print(f"Total: {result.total}")
|
||||
print(f"Passed: {result.passed} ✓")
|
||||
print(f"Failed: {result.failed} ✗")
|
||||
if result.errors > 0:
|
||||
print(f"Errors: {result.errors}")
|
||||
if result.skipped > 0:
|
||||
print(f"Skipped: {result.skipped}")
|
||||
if result.duration > 0:
|
||||
print(f"Duration: {result.duration:.2f}s")
|
||||
print()
|
||||
|
||||
if result.failures:
|
||||
print("FAILURES:")
|
||||
for failure in result.failures:
|
||||
print(f" - {failure['test']}")
|
||||
if failure.get('message'):
|
||||
print(f" {failure['message']}")
|
||||
print()
|
||||
|
||||
# Summary
|
||||
if result.failed == 0 and result.errors == 0:
|
||||
print("✓ All tests passed!")
|
||||
else:
|
||||
print(f"✗ {result.failed + result.errors} test(s) failed")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Run and format test results')
|
||||
parser.add_argument('target', help='Test file or directory to run')
|
||||
parser.add_argument('--framework', choices=['pytest', 'unittest', 'jest'],
|
||||
help='Testing framework to use (auto-detected if not specified)')
|
||||
parser.add_argument('--format', choices=['text', 'json'], default='text',
|
||||
help='Output format (default: text)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
run_tests(args.target, args.framework, args.format)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user