likes
comments
collection
share

刷题不停,忘记不止

作者站长头像
站长
· 阅读数 7

我在“第四份工作,刷题”中整理过自己的刷题经历:我曾经多次尝试过刷题,每次刷题都因为“题目太难我太懒”停下来。

大概是前年,一面字节成都,算法题目为“二叉树的右视角”,当时表现是窘迫的,我对这题目(二叉树,一直是我技能点的生疏处)毫无思路,结果当然是没结果。

所以,要找一份自己满意工作,要进大厂,又似乎不得不刷题。刷题需要从每天的业余时间中抽出一部分来思考来行动,需要克服自己的懒惰与疲惫,这是一件很难的事……

后来养成阅读习惯,我尝试一种新的折中的“刷题方式”:从每天的阅读时间中抽出精力较好部分用来看一本专门讲算法题目的书。

选书,是简单的,有好几位大佬整理出好几本专为刷题的书。我选择的是何海涛老师的《剑指Offer(专项突破版):数据结构与算法名企面试题精讲》。

这本书一共21万字,我花15小时过完一遍。

这本书分作15个章节,前面10个章节和最末章节分别介绍一种数据结构,并选出许多与该数据结构相关联的算法题目进行讲解;第11到14章则为几种算法的详解。这些章节分别是:

  • 整数,主要知识点是整数的内存占用长度和整数的二进制运算;
  • 数组,解决数组题目的一种常用思路是双指针,从两头往中间靠或是一快一慢;数组中元素求和,是常见的题目;二维数组甚至多维数组,也是可能出现的;
  • 字符串,本质上也是一种数组,不过变化更多,变位词或是回文常出现;固定大小(26个字符)的哈希表和双指针,是常用解法的小提示;
  • 链表的节点“手牵手”,链表在空间上比数组灵活;哨兵节点可以简化插入与删除代码的逻辑;到此章节,题目花样开始多起来,反转链表、重排链表、双向链表、循环链表;双指针依然很有用;
  • 哈希表,插入、查找和删除一个元素都只需要O(1)的数据结构;哈希函数的选择,数据碰撞的处理以及哈希表的使用,是常有题目;
  • 栈,“后入先出”,许多算法依赖栈的使用;
  • 队列,“先入先出”,即日常生活中的排队,与栈一样,许多算法都使用队列作为辅助数据结构;二叉树的广度优先搜索便需要队列的帮助;
  • 树,一种分层的数据结构,二叉树是最常见的树;二叉树的深度优先搜索,使用递归实现会很简单;二叉树的深度优先搜索有三种方式,中序遍历、前序遍历和后序遍历;二叉搜索树的左子节点、根节点和右子节点,是有序的;
  • 堆,是一种特殊的树,分为最大堆和最小堆,在最大堆中,每个节点的值总是大于或等于其任意子节点的值;在某个数据集合中找出k个最大值或最小值,常常使用堆;
  • 前缀树,英文单词的存储可以借用前缀树实现,它主要用来解决字符串查找相关问题;
  • 二分查找,对于在排序数组中找答案,二分查找总是值得尝试的;
  • 排序,是非常基础、重要的算法;
  • 回溯法,是蛮力法的升级版,集合的组合、排列计算需要用到回溯法,那种需要若干步骤、每个步骤面临若干选项的问题都可以用回溯法;
  • 动态规划,与回溯法很像,回溯法是列出所有可能结果,而动态规划是从这许多结果中找出最优解;动态规划,总是将大问题拆分为小问题来解决,找出大问题的解和小问题的解之间递归关系的状态转移方程是解题关键;动态规划的题目有许多;
  • 图,有节点有边,图的搜索算法也分为广度优先搜索或深度优先搜索;导航地图中的路径选择算法,就该是与图有关的;

我的阅读习惯基于碎片时间,每次看这本书,都只会持续十几二十分钟。一道题目,二十分钟内理解不到位,便放到明天再来,明天不行,又推到第三天。就这样地持续阅读,终于花半年读完本书。

整理本篇读书笔记前,我理过一个小小大纲:开篇指出自己曾经没做出来“二叉树的右视角”,中间是全书大概内容以及阅读体验,最末将“二叉树的右视角”默写出来。

默写前一周,我先复习一遍队列章节内容。昨天做题时,总不敢相信自己的代码是正确的,总感觉它有些过于简单,待与书中答案对比,才确认这代码并不算错。

def rightView(tree):
    result = []
    if(tree.head is None):
        return result

    queue1 = [tree.head]
    queue2 = []

    while(len(queue1) != 0):
        root = queue1[0]
        queue1 = queue1[1:]

        if(root.left is not None):
            queue2.append(root.left)
        if(root.right is not None):
            queue2.append(root.right)

        if(len(queue1) == 0):
            result.append(root.val)
            queue1 = queue2
            queue2 = []

    return result

刷题,可真是一件烦恼事。

我的这种折中刷题方式,并不太靠谱,到整理本篇笔记时,书中许多题目都需要很花心思才能跟着作者思路再走上一遍;甚至很有一些,即便很花心思也走不了一遍。

到底怎样能够将这些题目真的记住呢?怎样能够不忘记呢?我知道的一个答案是将这些题目运用到具体业务场景中去,熟能生巧永远是最好的学习方式。但工作中,真的需要持续思考相关问题么?

刷题,可真是一件烦恼事。写这样的读书笔记,也是一件烦恼事,读完一本书,我仿佛什么都没学到,又仿佛知道了许多。

怎样能够将使用数据结构与算法变得跟骑自行车一样——不用想便能生出自然反应并做出正确选择——呢?

且待我再找几本书来看。只看书?或许并不太够。