专栏名称: 吴师兄学算法
和程序员小吴一起从初学者的角度学习算法,以动画的形式呈现解题的思路。每周四篇原创文章,期待你的鉴赏!
目录
相关文章推荐
国家外汇管理局  ·  中国人民银行、国家外汇局召开2025年全面从 ... ·  昨天  
安徽司法  ·  以“新”为帆,奋力开拓外贸新空间 ·  昨天  
国家外汇管理局  ·  李强主持国务院第十二次专题学习 ·  2 天前  
北京药监  ·  以“新”为帆,奋力开拓外贸新空间 ·  2 天前  
北京药监  ·  以“新”为帆,奋力开拓外贸新空间 ·  2 天前  
51好读  ›  专栏  ›  吴师兄学算法

大家刷题都是自己写出来的吗?

吴师兄学算法  · 公众号  ·  · 2024-10-03 10:55

正文

大家好,我是吴师兄。

在算法学习的道路上,刷题是一个不可或缺的过程。作为程序员,无论是准备面试还是提升自己的编程能力,LeetCode 等平台上的算法题都成为了必修课。然而,很多人在刷题的过程中会感到迷茫,不知道该从何入手,甚至会陷入刷题无效的困境。

今天,我想分享一些个人的刷题经验,帮助大家更高效地掌握算法题目的解题技巧和方法。

一、合理的刷题顺序

刷题的核心之一在于建立一个合理的刷题顺序,而不是简单地按照 LeetCode 上的题号顺序来进行题目解答。

LeetCode 题目的编号虽然看似有序,但并没有按照学习难度或知识点进行合理的编排。很多初学者容易犯的一个错误就是从编号1开始刷,但实际上,编号1的“ 两数之和 ”这道题看似简单,却涉及了 哈希表 这一数据结构。如果没有对哈希表的了解和掌握,这题可能会卡住很多刚刚接触算法的同学。

再比如编号4的“ 寻找两个正序数组的中位数 ”,这道题目涉及复杂的二分查找和归并的思想,大多数人如果没有做过至少100道算法题,这道题几乎是不可能在合理时间内解出来的。

如何制定合理的刷题顺序?

  1. 从简单到复杂,按知识点递进刷题 :建议先从数据结构的基础知识开始,循序渐进地学习和刷题。比如从数组、链表、栈、队列等数据结构入手,逐渐过渡到树、图等高级数据结构。这样做的好处是可以系统地掌握基础数据结构,并且随着学习的深入,对这些知识的应用会更加熟练。

  2. 划分题目类型,集中解决一类问题 :刷题的过程中,我们可以将题目按照类型进行划分,比如动态规划、回溯、贪心算法等。针对每一种类型题目,可以先学习相关的理论知识,然后集中攻克一类题目。这样的刷题方式可以帮助你在短时间内掌握一类算法的精髓,避免知识点混杂在一起,难以巩固。

  3. 利用经典题目作为突破口 :LeetCode 上有一些题目被认为是“经典题”,因为它们能够很好地概括某种算法或数据结构的核心思想。这些题目往往会出现在面试中,也是学习某种算法的绝佳入门题。比如对于 动态规划 ,经典题目如 LeetCode 70“ 爬楼梯 ”、LeetCode 322“ 零钱兑换 ”等是非常好的入门题目。通过攻克这些题目,你会对动态规划有更深刻的理解。

刷题顺序推荐:

  1. 数组与链表 :这是最基础的部分,掌握这些结构的操作对于接下来的学习至关重要。建议从 LeetCode 1“ 两数之和 ”、LeetCode 206“ 反转链表 ”、LeetCode 283“ 移动零 ”等题目入手。

  2. 栈与队列 :在熟悉了线性数据结构后,开始深入学习栈与队列。这类结构在解决括号匹配、递归等问题时非常重要。经典题目包括 LeetCode 20“ 有效的括号 ”、LeetCode 155“ 最小栈 ”。

  3. 树与图 :树结构是许多复杂算法的基础,二叉树、二叉搜索树、图等是高级数据结构的核心内容,建议从 LeetCode 94“ 二叉树的中序遍历 ”、LeetCode 226“ 翻转二叉树 ”等开始。

  4. 动态规划 :这是算法中的难点,也是最容易卡住的部分。经典的动态规划题目如 LeetCode 70“ 爬楼梯 ”、LeetCode 53“ 最大子序和 ”等都值得反复练习。

  5. 回溯与贪心 :这些策略在解决组合问题时非常有效,回溯算法可以帮助解决排列组合问题,如 LeetCode 46“ 全排列 ”。贪心算法适合解决局部最优问题,如 LeetCode 55“ 跳跃游戏 ”。

二、刷题的方法

仅仅有一个合理的刷题顺序还不够,刷题的方法同样重要。

刷题的过程类似于我们学习数学的过程,都需要经过“ 概念学习 例题理解 实际练习 ”这三个步骤。

很多人喜欢直接跳到第三步,也就是拿到题目就直接开始解题,然而这种方式往往效率低下,甚至会导致刷题的质量很差。

学习概念是基础

不论是哪种算法或数据结构,它们都有一定的理论基础。例如, 哈希表 的原理是通过哈希函数将数据映射到一个位置上,这样查找效率会非常高。

而类似的还有 二叉树 二分查找 双指针 等重要概念。

在刷题之前,先花时间学习这些基础概念,可以让你在遇到相关题目时有更好的思路。

建议你通过书籍、课程或者文档去系统地学习这些概念。比如经典的《算法导论》、以及互联网平台上提供的免费教程都是不错的资源。打好基础,后续的题目就会变得相对容易理解。

看例题是提升理解的关键

在学习完理论知识后,接下来的步骤是通过一些例题来加深对概念的理解。

这一步不需要立刻开始自己写代码,而是先去分析和理解别人提供的解题思路。为什么要这样做呢?因为很多题目背后其实有非常固定的解法模式,而这些模式需要通过例题进行理解和巩固。

例如,我们学习了 双指针 这一技巧后,可以先通过阅读经典题目的解答,去理解双指针是如何在数组中被应用的。LeetCode 283“ 移动零 ”和 LeetCode 26“ 删除有序数组中的重复项 ”就是非常典型的双指针题目。

在你掌握了这些题目的解法后,再去尝试类似的题目,如 LeetCode 80“ 删除有序数组中的重复项II ”,这样就可以巩固你的知识。

真正的练习才能扎实掌握

当你通过理论和例题建立了初步的理解后,最后的步骤才是自己动手去写代码进行练习。在这一阶段,最重要的是多写、多思考。不要只是简单地抄答案,而是每次在遇到问题时,先自己分析思路,然后再去比对解法。

练习的关键在于反复琢磨那些经典的题目和解法,因为这些题目背后的思路往往可以举一反三。

同时,建议你针对每一道题目都尽可能尝试多种解法,比如暴力解法、优化解法等。这样不仅能够加深对题目的理解,还能提升你在面试中的应对能力。

三、以经典题目为例的刷题实战

为了让刷题过程更具实践性,我们可以以具体的经典题目为例,进行详细分析。

LeetCode 283“移动零”

这是一道典型的双指针问题。题目要求我们将数组中的所有0移动到数组末尾,并且保持非零元素的相对顺序。使用双指针法可以高效地解决这道题目,一个指针用于遍历数组,另一个指针用于记录非零元素的位置。

def moveZeroes(nums):
    j = 0  # j用于记录非零元素的位置
    for i in range(len(nums)):
        if nums[i] != 0:
            nums[i], nums[j] = nums[j], nums[i]
            j += 1

通过这道题目,可以理解双指针的核心思想,即通过两个指针来减少无用的遍历和交换操作。在理解了这道题的解法之后,我们可以进一步挑战类似的题目,如 LeetCode 485“ 最大连续 1 的个数 ”、LeetCode 26“ 删除有序数组中的重复项 ”,这些题目都可以通过双指针技巧来解决。







请到「今天看啥」查看全文