亲身经历讲述做题的意义及训练方法- 完整版

欢迎关注更多精彩

简介

本人是国内互联网的一位普通工程师。我没有参加过学校的集训,没参加过什么大学生acm比赛,也没有报过班,之前在leetcode上周赛最好成绩是53名,hihocoder上也有比较不错的成绩,如下图所示。



我写这文章的目是想告诉大家算法没有想象中的那么难,方法得当学起来挺有趣,对自己能力提升有帮助,对以后的工作也有非常大的帮助。
在我看来,我们做题的目无非是2种,一种是要去打比赛的,一种是希望找工作,或者学习一些算法知识以便后续辅助对计算机知识的深入学习。对于前者本来自认为才疏学浅,不足以论述。今天我就以一个码农的身份来谈谈后者。下面我就以四个方面来讲述。

  1. 面试官角度下做题的意义及作用(意义篇)。
  2. 在这些意义的大方向,我们在刷题中要如何做,及以注意的问题(方法篇)。
  3. 学习路径及资源(资源篇)。
  4. 学习中的一些心态问题(心态篇)。

意义篇

本部分主要介绍面试时做题的意义

我理解的一道题是什么

先给出我的观点一道题是一个缩小版的项目。

公司招人是干嘛的,当然是进来做项目的。

那么一个项目从产品到最后产出的过程有哪些(以下是简略版本,实际还要复杂一些)。

  1. 产品经理出产品方案。
  2. 产品经理与技术人员进行产品评审。
  3. 技术人员进行技术方案设计。
  4. 技术评审。
  5. 编写代码(方案落地)。
  6. 产品验收及上线。

看上面的6步跟我们面试算法题过程是一一对应的:

  1. 产品经理出产品方案 – 面试官描述问题
  2. 产品评审 – 求职者会提出一些疑问和意见
  3. 方案设计 – 求职者思考ing
  4. 技术评审 – 求职者与面试官交流自己的思路
  5. 方案落地 – 编写代码
  6. 验收 – 面试官看代码并提问

从上面的类比看出,一个做题的过程与做项目的过程高度相似,所以做题可以比较全面的考查求职者的职业素养。那么面试官到底在考查什么呢。

面试官考查的点有哪些

还是从上面6步来分析

  1. 产品经理出产品方案 – 面试官描述问题。
  2. 产品评审 – 求职者会提出一些疑问和意见。以上2步查考的是我们对业务的理解能力,能否对业务中不明确或者不合理的地方提出质疑。
  3. 方案设计 – 求职者思考ing。考查我们对于解决问题的方式方法,对各种算法或工具(对应到项目中可能是中间件,和工具)运用能力,创新能力,项目中的取舍。
  4. 技术评审 – 求职者与面试官交流自己的思路。考查我们的表达能力,考虑问题是否周全,对未知问题或风险的驾驭能力。
  5. 方案落地 – 编写代码。这也是考查的重点,进来首要事是写代码,考查我们的代码实现能力,代码抽象能力和意识,看我们对细节的把控。
  6. 验收 – 面试官看代码并提问。考查临场应变能力,对算法的创新性和掌握程序。

总结一下,要考查的方面有:

  1. 对业务的理解与思考,甚至能提出业务改进方案。
  2. 解决问题的方式方法,对算法的运用能力,创新能力,项目中的取舍。
  3. 代码实现能力,抽象能力,对细节的把控。

亲身经历

下面是我模拟一下算法面试经过,来感受一下上面一些能力及考查点在过程中的体现。

以leetcode [0047] 全排列 II 这题为例

面试官:我们先来做个题吧。

我:好的。

面试官:我们先来做个题吧。

我:好的。

面试官:给你一个数组,打印出所有的全排列。

此时,面试官已给出题目(需求),然后你拿到需求,不是马上开始做,而是应该是进入到需求评审(题目中有不清楚的,不合理的都要提出来),这一步就是考查你的业务理解,需求洞察,发现问题的能力。那么我发现了几个问题,1 数组的长度是多少呢,很长的话计算机(单机)也不能做啊,可能要选择多机的方案。数组里数字的大小范围啊,确定了才知道是用什么类型存呢。数组里有没有重复的数字,如果有的话,结果重复的要不要呢。结果要不要以某种顺序排序啊。当然还有其他问题,都要问出来。面试中说话才体现出你的想法。这些问题搞清楚了,算法出来的结果才是面试官想要的。

面试官:数组的话就是长度为1到10吧,然后数字都32位正整数,数字有重复,重复的结果都要出来,不要求排序。

好了下面开始设计(方案设计),

我开始思考(内心独白):这个题之前遇到过,用深搜逐位确定就可以,现在的话用原来的可以搞出来。

我:我有思路了。

面试官:那你讲一下吧。

我:巴拉巴拉…

面试官:这个思路可以,那能把代码写一下么。

我:可以。

写代码ing。。。(代码实现)

我:写好了。

面试官:嗯,我看看。

。。。

面试官:嗯,这个代码没有问题,现在希望结果不重复,你有什么好方法么。(验收提问,考查应变创新能力)

想一会儿。

我:我想到2种方法,一种是把所有的求出来后,再去重,另一种是在搜索中就把重复的去掉了,由于后一种效率更高,我使用后者(比较取舍)。前一种也是有应用场景的。巴拉巴拉。。。

面试官:好的,那你写一下代码。

我:好的。

。。。。

面试官:好的,那我们下一题吧。

以上是一个面试题的过程,基本上是这样。

从上面的过程中可以看考查得非常仔细,从需求评审到方案设计,再到方案取舍,提出问题和挑战。全面的考查了求职者的主观能动性,思考能力,创新能力,代码能力。

好了,讲了这么多,主要是让大家明白,面试官为什么要让我们做题,以及做题中要考查的方面。

那么我们已知道要考查的方面了,怎么样去通过学习提高呢。请看方法篇。

方法篇

本篇主要讲如何针对上面要考查的方面进行提高。

考查面之间的关系

通过上面的分析,我们知道我们要学习掌握的能力或知识有:

  1. 代码实现能力,直白点说就是告诉你怎么做了,你用代码来实现一下。
  2. 掌握足够的算法与数据结构知识,对一个题目知道用什么方法,对于用到的数据结构熟悉,才能写代码,是写代码的基础。
  3. 对于知识工具的应用,对题目分析得到的数学模型或思路要能够对应到自己所学的算法中。
  4. 对题目的分析抽象能力,对题目进行全面的分析,挖掘题目的信息,抽象出自己比较熟悉的模型。
  5. 主观能动性,思考能力等等,这是贯穿全局的能力,一定要经常训练这方面的意识,你的提问,你的回答,测试用例的设计等等都体现这些方面。

以上5点从1到4是逐级提高的,上下之是相互服务的,缺一不可,第五点是贯穿全局。

对题目的思考过程可以参考一下这一篇文章,先感受一下大致的流程。

leetcode-1674-使数组互补的最少操作次数-线段树
leetcode - 1681 - 最小不兼容性 - bitset -搜索 - 剪枝 - 数字集合
这2题是我在遇到自己不会或者一下子想不出来时所经历的过程,面试时有些时候一下子想不出来也是差不多这么个过程。你思考的都要说出来,让面试官知道,可以相互讨论的。

集中训练,专项突破

我一开始也和很多人一样,来一题做一题。做一题,下一题又不会了。感觉进度很慢,而且感觉没有什么进步和积累。本质上就是上面5个能力一个也不强,每一步都要卡一下。根据刻意练习理论,一项技能要掌握,就是不停的用,中间的间隔不能太久。就像背书一样,要经常读,要不然就会忘记。

根据这个理论,我们也对上面5项能力进行拆分,然后练习。但不是绝对的拆开,毕竟每做一题都要经历这些过程,只是刻意的去侧重一个方面。

练习方法和步骤:

  1. 对于代码能力,我们可以选择一些简单的题目或者是我们做过的题目,稍微整理一下思路(不会的先看别人的题解,理解思路消化一下),然后开始写代码。我这边选择了200道题目大家可以根据自己需要做其中的4,5十道重复刷,达到打代码行云流水(手放键盘上就不用停下来思考,看着之前做好的思考稿子就是打,直到代码写完)。
  2. 如何掌握比较多的算法下数据结构。首先把严老师的《数据结构与算法》里面所有的算法(书上有代码的)都要理解自己写一遍,因为这些太常用了(保守估计leetcode上70%以上的题目都有用)。对于其他高级的数据结构的理解也非常有帮助。然后,是要学些更高级的。因为leetcode上题目难度比较中等,很难遇到用新算法的时候,要自己主动去扩充,我这边也整理了一些有用的算法,大家有空学习,大家一定要认识到,做十道简单题不如做一道难题,这样才提高快。
  3. 对于知识工具的应用,前2步都输入性的学习,这一步主要是训练对掌握算法的应用。主要的训练方法就是学会一个方法后,去找一些题目集合来做。网络上有很多。这种情况下是我们已知用什么数据结构了,但用法不可能完全一样,需要自己思考并改造一下用。
  4. 对题目的分析抽象能力,这步开始要自己主动思考并输出了。基本思路是拿到一个题目后,自己分析分析,感觉可能哪几个方向解法。记录一下,针对每个方向都思考一下,往自己学习过的算法上靠,可能一开始还是很难,实在思考不出来就看答案。我的经历是,如果我想了好久想不出来,可能这个算法我根本没有学过。这种情况下,再去思考是没有意义了,我不是天才,还不到自己创造算法的地步。这个时候就是学习新算法的好时机。
  5. 主观能动性,思考能力等等,这是贯穿全局的能力。以上4步认真做了,能力自然提高了。还有一点是测试用例,尽量考虑全面,争取一次过,对于犯的错,没有考虑到的情况,自己深刻反思一下,下次注意。

上面的1,2是偏执行的,自己的思考其实比较少,第三步开始就要慢慢自己思考增多了。

1,2做好了后,基本上leetcode70%的题目都可以解掉。后面3个阶段其实是后期持续要做的。所以1,2阶段的目的是打好基础掌握工具,只要觉得1,2不是自己的瓶颈了,就可以减少练习量,注重后面3步的练习。

资源篇

下面主要讲练习的材料及服用方法

代码能力练习:

http://acm.hdu.edu.cn/listproblem.php?vol=11这里面都是一些裸题意思都很明白了,直接从第3步能力开始,自己先思考一下,不会就看题解,然后自己理解,再写代码。可以选择4,5十题集中练习,其他的也可以当作练习题做。

数据结构与算法学习:

  1. 《数据结构与算法》大家之前应该都学过,只是没有深刻理解,现在好好认真练习一下。关注公众号回复「数据结构资料」下载。
  2. 其他常用数据结构 常用数据结构 (还在完善中)
  3. 常用网站leetcode, hihocoder 可以学到一些高级算法,https://vjudge.net/ 刷题网站大集合(有时候不好登录)

数据结构与算法运用,对题目的分析抽象能力:

以线段树应用为例
我们可以去搜索大神们总结的题目
ACM大牛总结的线段树专辑
然后,就是按照线段树的思路对题目进行分析。一定要自己先思考,可以规定一个时间,比如2天想不出来,就看看提示或答案,然后把后续的实现做完。

对题目的分析抽象能力,主观能动性

参加比赛:
有了前4步的基础,偶尔也要来一些模拟真实面试训练,比赛就比较真实,题目都是没有见过的,随机的,以赛代练。
看水平而定,水平不高做不出来会打击积极性,但一定要有参加,可能是一个月一次,要有在紧张中思考的经历。赛后做不出来的题,就自己思考,锻炼自己的对于知识工具的应用,对题目的分析抽象能力,主观能动性,主动思考和解决问题。实在想不出来就看看别人的思路,然后自己实现一下。然后把不会的算法找些题再巩固一下。

总结一下,就是

  1. 重视基础,把前2步做好。
  2. 强化训练,巩固新算法。
  3. 注重思考,做题不只是做题,培养自己的意识。
  4. 以赛代练,模拟真实场景,提升应对生题的能力。

心态与心得篇

学习过程中的心态也很重要,下面讲讲我的心得。

正视自己,努力提高

题目是有难易之分的,有些难题确实很难想到,没有必要去死磕,毕竟我们还有其他的东西要学习。 此时,要看别人的题解,然后努力消化成自己的,至少要把新算法学一学(如果有出现的话)。

注重基础,注重沟通(修炼内功)

面试中,并不是没有思路就挂,有些难题想不出来正常,可以跟面试官说自己的想法。面试官有时候会给一些思路和指导,或者跟你讲一下思路让你实现。此时,如果你的代码能力和数据结构知识有一定积累的话,基本上都可以实现出来的。这也是满足面试要求的。至少不会因为算法题直接挂,还有后续与同等级别的求职者pk环节。

注重总结,形成自己的解题体系(修炼外功)

在做了一些题后,总会遇到类似的题,可者写类似的代码,比如说DFS算法,在搜索, dp 等实现的时候都有用到,可以总结出自己的一些模板,然后烂熟于心,一到用时不用思考就可以写出来。还有一些是算法比较的,比如说排序来说有好多种,可能都用过了,也都了解了,但是真正问起来区别一下子答不出来。这些平时要总结一下,想想。用起来的时候就会很清晰,用哪个时可以很快的分析出区别。

遇到不会的题怎么办

  1. 不要想着马上就可以思考出来,要准备花一段时间。
  2. 可以分段进行,比如专门抽个半个小时思考一下。或者走路时。
  3. 先确定一下方向,有可能用什么方法解。想想以前是不是有人说过这种题一般怎么怎么样。
  4. 自己思考不出来就去讨论区里看看别人的思考,顺着别人的思路想想。
  5. 实在想不出来(3天),就去看题解,学习新算法,然后巩固新算法。
    总结一下,就是持久战,定方向,努力思考,学习新算法。

模拟线下测试

面试时一般都是纸上思考和写代码,我们平时线下也要找几题自己模拟一下思考,然后讲述思路和写代码。一般一星期弄一次,要从平时积累,不能临时报佛脚。

总结

面试的目不是为了考倒求职者,是为了考查能力。我们可以针对这些能力针对性的训练并拿到合格的分数,不要因为算法而被挂。
基础特别重要,一定要重点关照一下。
做十道水题不如做一道难题,可以学习到很多新思路和方法。
对于难题不要怕,要以学一个赚一个的心态去想。
要经常总结,形成自己的套路。
要模拟线下笔试,熟悉线下环境。
以上都是一些方法,不花时间再好的方法也没用,一定要抽一些时间出来。最差的坚持也好过放弃,坚持住一定可以的。

最后,水平有限,有误之处还请大家指正。一篇文章不可能讲得很细。大家如果有遇到困惑或难题,可以留言一起讨论。

祝大家多多AC


本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。

在这里插入图片描述