算法题学习链路简要分析与面向 ChatGPT 编程

科技资讯 投稿 6300 0 评论

算法题学习链路简要分析与面向 ChatGPT 编程

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。

未经训练,不属于任何真实人物

2023 开年以来,全球媒体最火爆的热点莫过于一个生成式 AI 聊天机器人 —— ChatGPT,我们都被大量的信息刷屏了。在这些信息中,你或许看过这样一则新闻 《ChatGPT Passes Google Coding Interview for Level 3 Engineer With $183K Salary》,它说 ChatGPT 通过了谷歌工程师面试,则这个职位的年薪有 18.3 万美元。

谷歌面试是会考算法的,ChatGPT 已经具备这么强的算法能力了吗?如果答案是肯定的,那么我们借助 ChatGPT 的力量帮助提高算法能力,是不是可行的想法。

未来,固然需要想象。

现实,ChatGPT 能做到吗?

如果你对 ChatGPT 还不够熟悉,希望我能够为你提供一些指引。


今天文章比较长,写个简单的大纲:

2、ChatGPT 助手从入门到放弃

2.2 ChatGPT 的使用原则

4、总结


1. LeetCode 算法题学习链路简要分析

    步骤一:复制代码 🌚
  • 步骤二:粘贴运行 🌚
  • 步骤三:自我满足 🌚

说笑了,这么有任何价值(求饶),应该是:

    阶段 1 - 白板编码
  • 阶段 2 - 阅读优质题解
  • 阶段 3 - 抽象问题模型

1.1 阶段 1 - 白板编码

    1.1 阅读: 快速阅读题目信息,提取出题目的关键信息,包括题目目标、关键约束、输入输出数据类型、数据量大小等;
  • 1.2 抽象: 结合已掌握的算法知识抽象出题目的问题模型,并思考解决问题的算法,需注意算法复杂度能否满足问题的数据量上界;
  • 1.3 编码: 题目一般有多种算法实现,优先写出复杂度最优的版本。如果做不到,则先写出最熟悉的算法,再优化为复杂度更优的算法(在面试和竞赛中策略类似);
  • 1.4 检查: 检查题目条件并完善代码,包括问题约束、数组越界、大数越界、小数精度、初始状态值、目标状态值等;
  • 1.5 调试: 重复第 1 - 4 个动作直到题目通过所有测试用例。

至此,你已经 “通过” 这道题(或许没有),然而你只是对已经学过的知识复习了一遍,对这部分算法更加熟悉了,但是并没有知识增量,所以你需要进入阶段 2:

1.2 阶段 2 - 阅读优质题解

推荐一些优质算法题解作者:

    Krahets 上海交通大学,著有 《Hello 算法》
  • 小羊肖恩 北京大学,Rank 全球 Top 20,全国 Top 10
  • 灵茶山艾府 浙江大学,Rank 全球 Top 20,全国 Top 10
  • liweiwei1419 四川师范大学,参与录制 LC 官方视频题解
  • 负雪明烛,美团,毕业时收获 BAT、亚马逊、微软等 Offer
  • 宫水三叶的刷题日记,微软

因此,阅读题解阶段主要障碍就是看不懂,哪里看不懂呢?

    难点 1 - 算法: 理解算法本身,文字、注释、代码、图表这些都是算法的表现形式;
  • 难点 2 - 算法推导: 理解从题目一步步到算法的推导过程(有些题解会省略推导过程);
  • 难点 3 - 算法证明: 理解算法的严格证明过程,特别是贪心算法(有些题解会省略证明过程)。
    算法:理解 “每轮迭代从小顶堆中获取候选集里距离起点最短路长度最小的节点,并使用该点松弛相邻边” 就是理解算法本身;
  • 算法推导:理解 “暴力 BFS/DFS → Floyd → 朴素 Dijkstra → Dijkstra + 最小堆” 就是理解算法推导过程;
  • 算法证明:理解 “选择候选集中距离起点最短路长度最小的节点的方案不存在更优解” 就是理解算法证明过程。

理解了阅读题解阶段的主要障碍,那么这些障碍是由哪些原因导致的呢?

    原因 1:题解结构缺失: 有的题解只提供了可运行的代码,但是省略了推导过程和证明过程,甚至没有复杂度分析(题解:没有复杂度分析我不完整了);
  • 原因 2 - 思维复杂度过高: 有些题解结果完整,讲解也很详细,但是其中某些难点或某几行代码思维复杂度很高(大脑复杂度 $O(n^n$);
  • 原因 3 - 前置知识缺失: 有些算法需要一些前置知识基础,例如 Dijkstra 算法就需要有图论基础(基础不牢地动山摇);
  • 原因 4 - 代码语言缺失: 有些题解只会提供一种语言的代码(说的就是我);

因为此时编码不是目的,是通过编码的方式加深对算法的理解。

1.3 阶段 3 - 抽象问题模型

抽象问题模型就是你在阶段 1-2 抽象步骤中做的事情。

所谓抽象,就是总结出题目的模型 / 套路,怎么做呢?

    3.1 题目类型: 例如数学、双指针、回溯、动态规划、贪心、数据结构就是一级题目类型。继续细分下去,双指针又分为二分查找、滑动窗口、同向 / 相向双指针,动态规划又分为线性 DP、树形 DP、转压 DP、数位 DP 等,回溯又分为排列、组合、子集等等;
  • 3.2 算法模型: 模型就是我们说的解题模板 / 板子。例如二分查找有排除严格不成立方向的模型,背包问题有 01 背包和完全背包和滚动数组的模型,线段树有朴素线段树 +Lazy 的模型,质数有暴力和筛法的模板等等;
  • 3.3 编码技巧: 例如负数取模技巧、数组补 0 位技巧、链表 Dummy 节点技巧、除法转乘法技巧等等;

最后,你还需要将整个思考过程按照题目编号记录下来,方便未来的你查阅,小彭就是简单记录在 Github 上。有时候我重新做一道题后,会发现今天写的代码质量比几个月前写的的代码质量高出很多,也在见证自己的成长。

1.4 LeetCode 算法题学习链路小结

完成 LeetCode 算法题学习链路的简要分析后,用一个表格总结:

阶段 动作 描述
1、白板编码 1.1 阅读 快速阅读题目信息,提取出题目的关键信息
1.2 抽象 结合已掌握的算法知识抽象出题目的问题模型
1.3 编码 撸代码
1.4 检查 检查题目条件并完善代码
1.5 调试(for Loop) 重复第 1 - 4 个动作直到题目通过所有测试用例
2、阅读优质题解 2.1 理解算法 理解算法本身,文字、注释、代码、图表这些都是算法的表现形式
2.2 理解算法推导过程 理解从题目一步步到算法的推导过程
2.3 理解算法证明过程 理解算法的严格证明过程,特别是贪心算法
2.4 辅助编码(Async) 撸代码
3、抽象问题模型 3.1 抽象题目类型 例如数学、双指针、回溯、动态规划、贪心、数据结构
3.2 抽象算法模型 例如二分查找、背包问题、线段树 + Lazy、质数
3.3 抽象编码技巧 例如负数取模技巧、数组补 0 位技巧、链表 Dummy 节点技巧、除法转乘法

2. ChatGPT 助手从入门到放弃

ChatGPT 在对自然语言理解方面的进步是令人惊叹的,很多情况下只需要输入一个模糊的指令,ChatGPT 就能直接生成比较完整的答案。

2.1 向 ChatGPT 提问的一个误区

如果我们直接把问题交给 ChatGPT,试图让它直接输出详细的题解,会发生什么?

不是把 ChatGPT 吹到天上去了吗,问题出在哪里呢?

因为我们提出的一个开放(open-ended)问题,而这种提问方式对 ChatGPT 是低效的:

    详细:怎么定义详细?100 个字还是 1000 个字叫详细?
  • 优质:怎么定义优质?需要多少种算法,需要举一反三吗?
  • 题解:怎么定义题解?需要包含哪些信息?

2.2 一个万能的 ChatGPT prompt 模板

在经过一整天被人工智障折磨,以及阅读 《The Art of ChatGPT Prompting》后,我总结出一个提问模板:

    1、角色:限定知识领域(注意:New Bing 玩角色扮演出错概率偏高);
  • 2、目标:一句话概括需要的帮助;
  • 3、要求:对目标补充的具体清晰的要求,尽量表达清晰,避免模糊,一般采用 Do 和 Do not 格式;
  • 4、举例(可选):输入输出样例。

2.3 一个被逼疯的 prompt

经过和 ChatGPT 的来回拉扯后,我终于写出一版相对满意的 prompt。我试图让 ChatGPT 写出优质的题解,类似于要求 ChatGPT 写一篇文章。

我需要你担任算法教师和指导者,你需要给出一道 LeetCode 问题的代码和解题思路。
要求:
1、使用中文回答,使用 Kotlin 语言
2、代码必须带有注释
3、确保每个解法是严格不同的算法,并且每个解法包含算法名称、算法概括,算法详细描述、算法推导过程、代码实现、复杂度分析
4、先总结题目的解法个数,以及每个算法的算法名称
5、先输出复杂度最差的暴力解法,再依次输出复杂度更优的解法
6、不要输出题目描述和测试用例
题目:
718. 最长重复子数组

这道题有 4 种解法:

    1、使用暴力解法,枚举所有子数组,判断是否为重复子数组。
  • 2、使用动态规划解法,以二维数组 dp[i][j] 记录以A[i] 和 B[j] 为结尾的最长重复子数组长度。
  • 3、使用滑动窗口解法,枚举 A 和 B 所有的对齐方式,计算每种对齐方式的最长重复子数组长度。
  • 4、使用二分查找解法,最长重复子数组长度存在单调性,使用二分查找检查是否存在长度为 len 的重复子数组。

何苦看 ChatGPT❓

2.4 降低要求

在文章 《The Art of ChatGPT Prompting》中,提到:“It's important to provide the ChatGPT with enough information to understand the context and purpose of the conversation, but too much information can be overwhelming and confusing.”

那么,有没有可能是因为我们提出的信息量太大,导致 ChatGPT 无法聚焦呢?

我需要你担任算法教师和指导者,你需要给出一道 LeetCode 问题的代码和解题思路。
要求:
1、使用中文回答,使用 Kotlin 语言;
2、使用二分查找+哈希表的解法
3、包含算法、算法概括,算法详细描述、算法推导过程、代码实现、复杂度分析
4、不要输出题目描述和测试用例
题目:
718. 最长重复子数组

2.5 重新认识 ChatGPT 的能力和限制

在经历过反复被折磨后,我决定放弃让 ChatGPT 写题解的想法,原因是:

    1、ChatGPT 确实有总结提炼的能力,但要 ChatGPT 给出准确、全面、深度的答案,目前 ChatGPT 做不到;
  • 2、相比于总结,人类更看重的是对问题的深度拆解和建构能力,目前 ChatGPT 做不到。

AI 这个词,被泛化了。

    概率: ChatGPT 语言模型的数学基础是概率论,通过预测词的概率来输出答案,它绝对无法给出 100% 准确的回答,更不用说自主创作,甚至经常一本正经地给出自相矛盾的回答(GPT-4 也一样)。“原创想法的拙劣表达” 比 “清晰表达的非原创想法” 更有价值,此观点我们在《什么是原创?独立完成就是原创吗?》这篇文章里讨论过。
  • 语料库: ChatGPT 是基于互联网上的公共数据库(截止至 2021 年),不包含互联网上的私有数据库,企业和个人的私有数据库,超出语料库范围的内容它无法给出答案的。

回到文章开头的那个想象,ChatGPT 能做到吗?—— ChatGPT 不仅做不到,还远远做不到,在可见的未来,也不太可能做到。

2.6 在学习过程中使用 ChatGPT 的指导原则

刚开始使用 ChatGPT 的时候,它所表现的能力的确让我们很多人感觉非常惊叹。只是随着实践使用次数增多,随着提问问题的深入和复杂化,ChatGPT 的错误才开始逐渐显现出来,直到最后令人失望而已,是我们把它捧得太高了!

    原则 1 - 主动降低预期:

不要神化 ChatGPT,也不要否定 ChatGPT,而是降低对 AI 的预期,主动掌握使用和控制 AI。

在搜索引擎时代,信息以数据的形式存储在全世界的数据库中,我们要从这些信息中获得解决方案,就需要花费大量的时间去触达、筛选、阅读和加工。而在使用 ChatGPT 后,ChatGPT 能够帮我们搜索和整理信息,并直接呈现出整理后的信息,即使我们对这个领域一无所知。

因此,虽然目前 AI 无法有效解决综合性的复杂问题,但对于比较基本的模式化的问题,ChatGPT 能在短时间生成完整的方案,也是相当厉害的。把对 ChatGPT 的预期降低,理解它的能力和限制,才能更好的控制它。

    原则 2 - 监督和指导:

ChatGPT 的确可以协助我们完成某些特定任务 / 特定动作,但它更需要在人类的监督和指导下才能有效产出,更无法代替人类的创造力和解决问题的思考力。

    原则 3 - 思考的权利:

将思考的权利让渡给 AI,是危险的。

很多时候,我们追求的不仅仅是最终的答案,还包括寻求答案的过程,是一种所谓的 “心流” 状态。因此,越是折磨大脑皮层的动作,我们越不能让渡给 AI,而那些需要花费大量时间的重复的搜索整理动作,不交给 AI 还交给谁呢?

阶段 结论
1、白板编码 100% 不暴露给 AI
2、阅读优质题解 理解过程尽量不暴露给 AI,使用 AI 作为 Checker
3、抽象问题模型 使用 AI 查找和整理信息

接下来基于此结论开始使用 ChatGPT 辅助学习过程中的单个动作:


3. 面向 ChatGPT 编程的正确打开方式

3.1 使用 ChatGPT 输出提示

我需要您担任算法教师和指导者,给出一道 LeetCode 问题的 5 条提示。
要求:
1、用中文回答,回答精简,限制在 15 字内
2、如果存在多种解法,优先提示复杂度最差的暴力解法,再依次提示复杂度更优的解法
问题:718. 最长重复子数组

3.2 使用 ChatGPT 补齐题解结构

有的题解只提供了可运行的代码,但是省略了推导过程或证明过程,甚至没有复杂度分析,我们可以题解交给 ChatGPT 补齐,以 newhar 的这篇题解为例:

我需要你担任算法教师和指导者,你需要补齐一道 LeetCode 题的题解。
要求:
1、使用中文回答;
2、为代码增加注释
3、分析时间和空间复杂度
4、解释这个算法
代码:
class Solution {
public:
    int collectTheCoins(vector<int>& coins, vector<vector<int>>& edges {
        int n = coins.size(;
        unordered_set<int> nes[n];
        for(const auto& e : edges {
            nes[e[0]].insert(e[1];
            nes[e[1]].insert(e[0];
        }
        // 1. 删除所有的无金币的叶子节点,直到树中所有的叶子节点都是有金币的(类似拓扑排序)
        vector<int> deleted(n, 0;
        queue<int> q;
        for(int i = 0; i < n; ++i 
            if(nes[i].size( == 1 && coins[i] == 0 
                q.push(i;
        
        while(q.size( {
            int cur = q.front(; q.pop(;
            deleted[cur] = 1;
            for(int ne : nes[cur] {
                nes[ne].erase(cur;
                if(coins[ne] == 0 && nes[ne].size( == 1 {
                    q.push(ne;
                }
            }
        }
        
        // 2. 删除树中所有叶子节点,及其相邻边(删两次)
        for(int iter = 0; iter < 2; ++iter {
            for(int i = 0; i < n; ++i {
                if(!deleted[i] && nes[i].size( == 1 {
                    deleted[i] = 1;
                }
            }
            for(int i = 0; i < n; ++i {
                if(deleted[i] {
                    for(int ne : nes[i] {
                        nes[ne].erase(i;
                    }
                }
            }
        }
        
        // 3. 答案就是剩下的树中的边数
        int res = 0;
        for(const auto& e : edges
            if(!deleted[e[0]] && !deleted[e[1]] 
                res += 2;
        
        return res;
    }
};

3.3 使用 ChatGPT 辅助阅读

有些题解结果完整,讲解也很详细,但是其中某些难点或某几行代码过于复杂,可以针对性提出问题,ChatGPT 也有能力结合上下文回答。

3.3 使用 ChatGPT 翻译代码

我需要你担任算法教师和指导者,你需要将代码翻译为 Python:
要求:
1、包含代码注释
代码:
class Solution {
    fun collectTheCoins(coins: IntArray, edges: Array<IntArray>: Int {
        val n = coins.size
        // 入度表
        val inDegrees = IntArray(n
        // 领接表
        val graph = HashMap<Int, MutableList<Int>>(
        for (edge in edges {
            graph.getOrPut(edge[0] { LinkedList<Int>( }.add(edge[1]
            graph.getOrPut(edge[1] { LinkedList<Int>( }.add(edge[0]
            inDegrees[edge[0]]++
            inDegrees[edge[1]]++
        }
        // 剩余的边
        var left_edge = edges.size // n - 1
        // 1、拓扑排序剪枝无金币子树
        val queue = LinkedList<Int>(
        for (node in 0 until n {
            // 题目是无向图,所以叶子结点的入度也是 1
            if (inDegrees[node] == 1 && coins[node] == 0 {
                queue.offer(node
            }
        }
        while (!queue.isEmpty( {
            // 删除叶子结点
            val node = queue.poll(
            left_edge -= 1
            // 修改相邻节点
            for (edge in graph[node]!! {
                if (--inDegrees[edge] == 1 && coins[edge] == 0 queue.offer(edge
            }
        }
        // 2、拓扑排序剪枝与叶子结点距离不大于 2 的节点(裁剪 2 层)
        // 叶子节点
        for (node in 0 until n {
            if (inDegrees[node] == 1 && coins[node] == 1 {
                queue.offer(node
            }
        }
        for (node in queue {
            // 2.1 删除叶子结点
            left_edge -= 1
            // 2.2 删除到叶子结点距离为 1 的节点
            for (edge in graph[node]!! {
                if (--inDegrees[edge] == 1 left_edge -= 1
            }
        }
        // println(inDegrees.joinToString(
        // coins=[0,0],edges=[[0,1]] 会减去所有节点导致出现负数
        return Math.max(left_edge * 2, 0
    }
}

3.4 使用 ChatGPT 规范代码

我们可以将自己写的代码交给 ChatGPT 做 CodeReview:

我需要你担任算法教师和指导者,你需要对代码做 CodeReview:
要求:
1、评价代码规范性
2、指出不足指出
3、给出改进后的版本
代码:略

图片过大,只截取部分信息。

GPT-4 实验结果:https://poe.com/s/XelhIjmHxWFtbnZpLmEd

3.5 使用 ChatGPT 推荐相似题目

我需要你担任算法教师和指导者,你需要给出 10 道同类型题目和链接:
题目:
718. 最长重复子数组

“动态规划” 这一层,推荐的题目实际关联度不高。

我需要你担任算法教师和指导者,你需要给出 10 道同类型题目和链接:
要求:
1、都包含动态规划、滑动窗口和二分查找解法
题目:
718. 最长重复子数组

是不是逐渐掌握调教 ChatGPT 的正确方式?更多 case 就不再展示了,希望这篇文章能够给你带来一些灵感或者思路。


4. 总结

让我意外的是,在 OpenAI 的 GPT-4 技术报告中,GPT-4 在 LeetCode 算法上的测试数据表现非常糟糕。如果以 GPT-4 的水平是不可能通过 Google 的算法面试的,更不用说该新闻发表日期时的 ChatGPT 应该还在用 GPT-3.5 模型。

总结一下:

    1、ChatGPT 能够解决 “信息量太大 ”而 “注意力太少” 的矛盾,每个人的延展性将被极大扩展;
  • 2、ChatGPT 确实有总结提炼的能力,但对问题的深度拆解和建构能力,ChatGPT 无法做倒;
  • 3、将思考的权利让渡给 AI 是危险的,越是折磨大脑皮层的过程越不能让渡给 AI;
  • 4、我们的对手不是 AI,而是比你更懂控制 AI 的人。

你认为 ChatGPT 技术是否被过度炒作?你对这个问题有什么见解?欢迎聊聊你的看,也欢迎你转发、留言、在看,给我一个反馈喔。


ChatGPT 实验资料

    交流|面向 ChatGPT 学习算法 —— Krahets 著
  • 如何与ChatGPT4结对编程提升研发效率 —— cheney(腾讯)著
  • 我和 chatGPT 对线操作系统! —— cxuan 著

参考资料

    The Art of ChatGPT Prompting: A Guide to Crafting Clear and Effective Prompts —— fatih kadir akin 著
  • ChatGPT Is a Blurry JPEG of the Web —— Ted Chiang(《降临》作者)著
  • 通过谷歌面试的 ChatGPT 要取代码农了?硅谷工程师:先别急 —— 硅星人 著
  • 最近很火的 ChatGPT 究竟是什么?会给我们的生活带来什么改变? —— 李睿秋 Lachel 著

编程笔记 » 算法题学习链路简要分析与面向 ChatGPT 编程

赞同 (28) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽