结合cursor的AI能力刷leetcode

0 阅读13分钟

近期开始刷leetcode,我发现不可能自己在leetcode上去硬解题效率太低,还有就是上来直接做题不知道一些原理性的东西也没什么意义。特别是在一些复杂的逻辑里面似懂非懂,这个时候就需要做几个事情来快速提升我们的解题的效率和对题目原理的理解,这是我在刷题过程中基于cursor的AI能力做的几个事情,希望对你们有一些启发:

  1. 让curosr帮我生成刷题的项目工程
  2. 基于cursor的rule快速生成刷题测试demo
  3. 解题过程中让curosr生成解题思路和代码的运行逻辑的详解
  4. 解题完成基于cursor的rule快速生成解题思路和解题原理和代码运行逻辑

接下来看我怎么一步一步刷题的。

一、让curosr帮我快速生成刷题的项目工程

第一步:创建一个目录leetcode

mkdir leetcode 
cd leetcode

第二步:用cursor打开项目,此时是一个空项目,cmd+L 选择Agent和你能用的模型(解释下为什么选agent:agent能主动采取行动,如搜索代码库、读取文件、执行命令,可以使用多种工具完成复杂任务,解决问题时有更强的自主性和连贯性,可以根据上下文进行多步骤的操作,ask主要就是你问他答,通常是不主动操作文件的)

cmd+L 打开对话框

第三步:输入提示词内容,他就会运行一系列的创建文件和文件夹的逻辑

我需要刷leetcode的题目,帮我生成一个刷题项目,要求pnpm和typescript来做开发,jest作为单元测试,每个题目单独一个文件

具体输出内容如下图,创建一个开发项目,这个生成目录主要是一个题目一个文件夹,只用jest作为测试,他把题目搞成一个md文件,测试用例一个文件,解题一个文件,这个还不是我最满意的状态,继续优化工程项目。

第四步:继续优化项目:输入提示词

需要优化下项目,第一个我需要我有一个pnpm命令能够快速的创建一个题目,第二个就是把单元测试全部移动一个一个单独的文件夹,第三个就是题目都是一个文件并且这个文件能够单独的跑服务, 第四个我需要一个index文件能够快速的去切换题号做本地测试

具体内容如下:新增了三个命令,create用来创建题目,start用来跑单个题目,problem用来看现在的题目列表,但是目前还有几个问题,start跑的题目是单次的不是监听和实时刷新形式的这样不利于我们解题中间的调试,创建的文件需要我们输出题号什么的其实没有那么复杂只需要创建一个简单的模板就行,后面有别的方法在文件里面创建题目内容,还有就是md文件名没什么用直接放到ts文件注释里面就行,我继续优化

第五步:继续优化项目:输入提示词,经过几次小的提示词优化工程基本上就搞定了额,你也可以根据自己的习惯创建

第一:不需要创建md题目内容文件。第二:创建的题目内容只需要一个通用的模板就行。第三点就是启动题目的时候不是一次性的需要有监听持续输出结果,启动题目的时候不用专门写题号可以在index文件内部手动切换就行
上面优化后还有点小问题:输入提示词-》在重名的时候需要优化下是否覆盖的问题

具体内容如下图:pnpm new <文件名> 题目的时候只输出简单的模板,不用输入一堆东西,pnpm run star 的时候加入文件名称就可以启动服务并且能够持续监听,这样我们就可以快乐刷题了

第六步:我们演示下几个功能:

1、创建题目模板:

pnpm new 1 //创建题目为2的刷题模板


2、启动服务刷题开始:

pnpm start 1 //启动文件名1的服务监听


3、运行测试用例:

pnpm jest  //跑所有的测试用例

多次优化后的 package.json文件

{
  "name": "leetcode-solutions",
  "version": "1.0.0",
  "description": "LeetCode题目解答 - TypeScript实现",
  "main": "index.js",
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "new": "node scripts/create-problem.js",
    "start": "nodemon --watch src --ext ts --exec "ts-node" src/index.ts"
  },
  "keywords": [
    "leetcode",
    "algorithms",
    "typescript",
    "jest"
  ],
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "@types/jest": "^29.5.12",
    "@types/node": "^20.11.24",
    "jest": "^29.7.0",
    "nodemon": "^3.0.1",
    "ts-jest": "^29.1.2",
    "ts-node": "^10.9.2",
    "typescript": "^5.3.3"
  },
  "dependencies": {
    "chalk": "^4.1.2"
  }
} 

项目的readme.md

# LeetCode 解题项目

使用 TypeScript 实现的 LeetCode 题目解答,使用 Jest 进行单元测试。

## 项目结构

- `src/`:存放题目解答
  - 每个题目一个单独的文件,例如 `two-sum.ts`
- `tests/`:存放测试文件
  - 每个题目对应一个测试文件,例如 `two-sum.test.ts`
- `scripts/`:工具脚本
  - `create-problem.js`:创建新题目

## 使用方法

### 安装依赖

```bash
pnpm install
```

### 创建新题目

```bash
pnpm new <题目名称>
```

例如:
```bash
pnpm new 1
```

如果题目文件已存在,会询问是否覆盖。可以使用 `-f``--force` 参数强制覆盖:

```bash
pnpm new 1 -f
```

### 运行题目

```bash
# 运行默认题目
pnpm start

# 指定题目运行
pnpm start 1
```

程序启动后自动运行指定题目,并提供交互式界面进行自定义测试。
每次创建新题目时,新题目会自动被设置为默认题目。

#### 交互式命令

在运行模式下,可以使用以下命令:
- 输入 JSON 数据:执行自定义测试
- `exit`:退出程序
- `clear`:清屏
- `reload`:重新加载当前题目并运行测试

### 运行测试

```bash
# 运行所有测试
pnpm test

# 运行单个题目的测试
pnpm test tests/1.test.ts

# 监视模式运行测试
pnpm test:watch
```

## 题目列表
- [1](./src/1.ts)

- [two-sum](./src/two-sum.ts)
- [add-two-numbers](./src/add-two-numbers.ts) 

总结:目前整个项目是可以自由的创建文件和启动服务跑demo了,下面我就开始演示刷题了。

二、基于cursor的rule快速生成刷题测试demo

前面我们把项目跑起来了,有几个问题没解决,创建的每个题目都是死模板,需要手动去写入题目内容和写测试代码,然后再去解题。 有没有更加简单的指令告诉ai给我快速生成刷题代码了。这个时候我们就要借助cursor的rule功能了,能够通过简单的一句话让他快速生成刷题模板,我们看看怎么做。

第一步:我们创建一个cursor rule

打开cusror的设置->然后点击rules->点击add new rule,具体操作如下图;

这样我就在根目录下创建了一个.cursor/rules/generate-template.mdc 这个文件主要帮我们写一些模板生成规则了,接下来我们写模板代码生成规则

第二步:模板生成规则编写,我就不太讲为什么要这么写了,你们可以查相关的资料,其实也可以直接问gpt,具体内容如下:

其实就是一个md文件,可以按照层级去写你要生成代码的规则,也可以给出一些模板去限定生成的规则,这个规则里面会给出一个leetcode的题目的链接,然后按照大模型更具链接去生成这个文件需要的代码,里面要求了按照提供url生成注释,并且给出测试代码,这样你就能专心刷题了


# LeetCode网址解析规则

这个规则用于从LeetCode网址提取题目内容并生成文件头部注释。

## 规则内容

当用户输入LeetCode题目URL时,执行以下操作:
1. 从URL中提取题目编号和标题
2. 注释顶部给出原题的链接
3. 访问LeetCode网站获取题目详情
4. 提取以下内容:
   - 题目标题和编号
   - 题目描述
   - 示例输入/输出
   - 约束条件
5. 将内容格式化为文件顶部注释格式
6. 生成对应的函数签名都叫solution
7. 要求不要解题,只需要输出跑用例的代码就行,需要输出的用例得告诉我是否是正确的
8. 再次强调不要解题

## 输出格式和示例

```typescript
/**
 * [题号]. [题目标题]
 * 题目链接 https://aa.xx.com
 * [题目描述]
 * 
 * 示例:
 * 输入:[示例输入]
 * 输出:[示例输出]
 * 解释:[解释说明]
 *
 * 提示:
 * - [约束条件1]
 * - [约束条件2]
 */

// 导出函数 示例
export function solution(params: any): any {
  // 实现算法
  return null;
}

// 导出测试用例供index.ts使用
export const testCases = [
  {
    input: null,
    expected: null
  }
];
/**
 * 本地测试
 */
if (require.main === module) {
  // 这里编写本地测试用例
  testCases.forEach((testCase, index) => {
    console.log(`测试用例 ${index + 1}:`);
    console.log(`输入: ${JSON.stringify(testCase.input)}`);
    const result = solution(testCase.input);
    console.log(`输出: ${JSON.stringify(result)}`);
    console.log(`预期: ${JSON.stringify(testCase.expected)}`);
    console.log(`结果: ${JSON.stringify(result) === JSON.stringify(testCase.expected) ? '通过 ✅' : '失败 ❌'}`);
    console.log('-------------------');
  });
}
```


## 温度配置

- 温度值: 0.7
  - 较低温度(0.2-0.5):生成更确定性、更保守的解题思路
  - 中等温度(0.6-0.8):平衡创新性和准确性
  - 较高温度(0.9-1.0):提供更多样化、创新的解题思路

## 使用说明

在聊天窗口中使用 `@cursor rules generate-template` 调用此规则。
使用 `@cursor rules generate-template temp=0.3` 调用低温度版本(更准确)。
使用 `@cursor rules generate-template temp=0.9` 调用高温度版本(更创新)。

第三部:我们试下生成效果

打开对话框,输入@就会出现一个悬浮框,选中cursor rules,里面选中刚才我们写的提示词规则文件,然后贴上leetcode地址就行,具体操作看下图:

看我们按照地址生成刷题内容:他分为顶部注释内容是题目内容,中间部分是我们要解题的函数,下面是测试用例内容:


这样我们pnpm start 1就可以快乐的刷题了。但是刷题有个问题,题目完全不会,或者说完全没思路怎么办?这就是下面我们做的让ai帮我解题。

三、解题过程中让curosr生成解题思路和代码的运行逻辑的详解

还是按照上面的第一题来做,

第一步:直接对话,通过cursor的对话功能帮忙解题

请帮我输出下解题思路,不要直接解题

从下图可以看到:大模型会根据我的要求去帮我生成解题思路,让我用双指针解题,

第二步:逐渐加码,可以通过cursor对话功能去逐渐帮我们解题或者纠错,这个我就不详细演示了

四、解题完成基于cursor的rule快速生成解题思路和解题原理和代码运行逻辑

当我们把题目做完了,需要有一些笔记给我们后续复习工作,这个时候我们也可以借助rule的能帮我们去生成笔记,下面我们看看怎么操作

第一步:还是老样子写一个生成笔记的rule,后面直接通过调用rule来快速生成,并且我们能够有一个标准的笔记模板给大模型,打开cusror的设置->然后点击rules->点击add new rule,具体操作如下图;

第二步:写提示词,约束生成规则,具体内容如下,也给出示例

# LeetCode解题思路注释生成

这个规则用于分析算法解答。

## 规则内容

当分析LeetCode题目时,请提供以下内容:

1. 问题理解:简述题目的关键点和要求
   
2. 解题思路:主要参考我的解题方案
   - 问题本质
   - 解决方案(可多种)
   
3. 具体执行流程(以${xx}为例)

4. 代码的详细执行的过程(需要把遍历工程全部讲一遍)
   -  特别是详细的复杂和递归需要特别详细
   
5. 关键点
   - 数据结构选择原因
   - 算法思路步骤
   - 时间复杂度分析
   - 空间复杂度分析

6. 复杂度分析

7. 方法选择

8. 将内容格式化为注释格式,添加成文件底部
   
9.  生成对应的TypeScript函数签名

## 示例

```typescript
/**
 * 问题:两数之和
 * 解题思路:
 * 1. 问题本质
 * - 在n×n的矩阵中找出行和列完全相同的配对数量
 * - 行和列相等意味着它们包含的元素完全相同且顺序一致
 * - 需要考虑重复情况:同一行可能与多个列相等
 *
 * 2. 解决方案(三种主要方法)
 *
 * A. 暴力法(三重循环)
 * - 遍历每一行
 * - 对每一行,遍历每一列
 * - 比较行和列的每个元素是否相等
 *
 * B. 哈希表法(优化方案)
 * - 将每一行转换为字符串作为特征值
 * - 使用Map存储每种行的出现次数
 * - 遍历列并检查是否存在匹配的行
 *
 * C. 矩阵转置法
 * - 将矩阵转置(行列互换)
 * - 比较原矩阵的行与转置矩阵的行
 * - 统计匹配的数量
 *
 * 3. 具体执行流程(以哈希表法为例):
 * 以 grid = [[3,2,1],[1,7,6],[2,7,7]] 为例:
 * - 第一步:处理行
 *   - "3,2,1" -> count: 1
 *   - "1,7,6" -> count: 1
 *   - "2,7,7" -> count: 1
 * - 第二步:检查列
 *   - 第0列 "3,1,2" -> 不匹配
 *   - 第1列 "2,7,7" -> 匹配一次
 *   - 第2列 "1,6,7" -> 不匹配
 * - 返回匹配总数:1
 *
 * 4. 关键点
 * - 使用字符串表示可以简化数组比较
 * - Map的查找效率为O(1)
 * - 需要正确处理重复匹配的情况
 * - 矩阵一定是方阵(n×n)
 *
 * 5. 复杂度分析
 * - 暴力法:
 *   - 时间:O(n³),三重循环
 *   - 空间:O(1),只需要常数空间
 *
 * - 哈希表法:
 *   - 时间:O(n² * k),k为转字符串的开销
 *   - 空间:O(n²),存储行的字符串表示
 *
 * - 矩阵转置法:
 *   - 时间:O(n²),需要遍历矩阵两次
 *   - 空间:O(n²),存储转置矩阵
 *
 * 6. 方法选择
 * - 对于小规模数据,暴力法简单直接
 * - 哈希表法在大规模数据时更优
 * - 转置法思路清晰但空间消耗较大
 */
```
## 温度配置

- 温度值: 0.7
  - 较低温度(0.2-0.5):生成更确定性、更保守的解题思路
  - 中等温度(0.6-0.8):平衡创新性和准确性
  - 较高温度(0.9-1.0):提供更多样化、创新的解题思路

## 使用说明

在聊天窗口中使用 `@cursor rules generate-notes` 调用此规则。
使用 `@cursor rules generate-notes temp=0.3` 调用低温度版本(更准确)。
使用 `@cursor rules generate-notes temp=0.9` 调用高温度版本(更创新)。

第三步:我来试下生成笔记的能力,打开对话框,输入@就会出现一个悬浮框,选中cursor rules,里面选中刚才我们写的提示词规则文件,输出生成注释就行,具体操作看下图:

这是生成解题笔记

/**
 * 问题: 合并交替字符串
 * 解题思路:
 * 1. 问题本质
 * - 需要交替合并两个字符串,从word1开始
 * - 如果一个字符串比另一个长,多出的部分需要添加到结果末尾
 * - 返回最终合并后的字符串
 *
 * 2. 解决方案
 *
 * A. 迭代法
 * - 找出两个字符串的最大长度
 * - 遍历到最大长度,交替添加两个字符串的字符
 * - 对于已经遍历完的较短字符串,跳过其添加步骤
 *
 * 3. 具体执行流程:
 * 以 word1 = "abc", word2 = "pqr" 为例:
 * - 初始化 result = ""
 * - 最大长度 maxLength = 3
 * - 遍历 i = 0 到 2:
 *   - i = 0: result += "a"; result += "p"; result = "ap"
 *   - i = 1: result += "b"; result += "q"; result = "apbq"
 *   - i = 2: result += "c"; result += "r"; result = "apbqcr"
 * - 返回结果 "apbqcr"
 *
 * 以 word1 = "ab", word2 = "pqrs" 为例:
 * - 初始化 result = ""
 * - 最大长度 maxLength = 4
 * - 遍历 i = 0 到 3:
 *   - i = 0: result += "a"; result += "p"; result = "ap"
 *   - i = 1: result += "b"; result += "q"; result = "apbq"
 *   - i = 2: word1已遍历完,跳过; result += "r"; result = "apbqr"
 *   - i = 3: word1已遍历完,跳过; result += "s"; result = "apbqrs"
 * - 返回结果 "apbqrs"
 *
 * 4. 关键点
 * - 使用Math.max获取两个字符串的最大长度
 * - 遍历时需要检查当前索引是否超出各字符串长度
 * - 交替添加字符的顺序始终是word1先,word2后
 *
 * 5. 复杂度分析
 * - 时间复杂度:O(n),其中n是两个字符串的最大长度
 *   需要遍历一次最大长度
 * - 空间复杂度:O(n),存储结果字符串
 *
 * 6. 方法选择
 * - 这个问题相对简单,迭代法直观且高效
 * - 也可以考虑使用双指针方法,但对本题而言没有明显优势
 */

现在看从刷题项目到笔记生成都已经完成,接下来我们只需要重复的去创建题目刷题就好

五、总结

  1. 我们已经完成了基于AI agent对刷题项目的创建,如果是我创建这个项目工程估计得个小半天,不一定有AI的代码写的好,其实多看看ai写的代码也能发现自己写代码的问题。
  2. 我们完成了对题目自动创建模板的功能也完成了,只需要通rules功能就能快速的完成对刷题模板的快速创建,并且也限定了模板的生成结构
  3. 我们在刷题期间可以借助于ai对话的能力,去解答自己刷题过程中的一些疑惑或者说对原理的理解
  4. 我们能够在刷完题后对这题进行笔记总结,也是通过rules功能输出统一化的解题笔记

最后:这只是我在借助ai帮我辅助刷题的小尝试,欢迎大家多交流