上一文,我们从思想方面聊了算法,但是我们没有说算法到底要刷什么?怎么才能刷清楚,本文继续谈我的观点。

1.算法的三种境界

在《神雕侠侣》中,杨过断臂坠谷,与雕兄为伴,雕兄带之剑冢,此地有三冢。剑冢中,埋的是独孤求败一生几个阶段中用过的几柄剑。
第一柄是一柄青光闪闪的无名利剑。凌厉刚猛,无坚不摧,弱冠前以之与河朔群雄争锋。
第二柄是「玄铁重剑」,重剑无锋,大巧不工,四十岁之前恃之横行天下。
第三柄是:柄已腐朽的木剑,原因是独孤求败「四十岁后,不滞于物,草木竹石均可为剑」

这三把剑也代表了技术的三层境界。第一层是凌厉刚毅,也就是我们会找各个各样的开包,工具包,看谁更强大,更好用,就用谁,而不关心内部实现的差异。

第二层是大巧不工,我们开始重视内在逻辑,开始分析问题的本质,开始研究如何自己实现。这才是真正锻炼能力的境界。

第三层,不滞于物,在我们眼里,一个牛逼的包可能只有一个框架是其设计的亮点,可能只有一个核心算法是其精华,我们将这些吸收之后,就不会人人忽悠,也不会依赖外部工具,能从最本质的角度解决问题。

其实不仅仅算法,技术学习也是一样,这是我非常欣赏的学习方式,也一直在试图这么做。

对于算法,我们可能会讨论是看书,还是买课,还是直接干LeetCode,这都是形式,也就是上面的第一层,这个无所谓,怎么都行。我们整个连载更希望在第二层有所突破。

我们的武功心法是什么呢?我总结了这么几句:

一招多题,看透本质。

一题多解,融会贯通。

循序渐进,画图拆解。

持之以恒,终会成功。

上面的好像没啥特别的是吗?我们一个个来介绍,相信看完后你会明白。

2.一招多题 看透本质

首先我们看一个面试题:

LeetCode 107:给定一个二叉树,返回其节点值自底向上的层序遍历。(即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历),例如下图:

输出结果为:

[[15,7],[9,20],[3]
]

看到这个题你是否有思路呢?如果研究二叉树比较少,可能半天也想不到该怎么做。我用这个题目测试了一些小伙伴,大部分人都没啥思路,说明如果面试直接出这个题,很多人是搞不定的。如果再给你一些时间,可能想到深度优先,但是顺序好像和预期的不一样。可能过了大半天想到可能用广度优先更好一些,那该怎么层次遍历呢,怎么才能倒着来呢?一堆的疑惑,貌似挺难的,对不。

如果学过数据结构,一定记得树有个层次遍历的方式,就是先将根节点的所有子节点都先访问了,然后再依次访问下一层。每一层的节点先用一个队列保存,某个元素出队的时候随便将子节点都入队,这样一层访问完的时候下一层的节点也恰好都入队了。这就是层次遍历的基本过程。

上面这么做,虽然能够按照层次访问所有的元素,但是在很多场景下需要将每层的元素区分开来。这里可以通过一个标记位等方式来实现。拿到一层层的元素之后可以做什么呢?我们可以做很多事情:

1.求每一层的最大值

2.求每一层的平均值

3.将奇数层显示逻辑不变,偶数层的元素反转,也就是之字型访问

4.只打印每层最右侧的元素(右视图)

5.按照从最底层到根节点,倒序打印

6.将二叉树改成N叉树,也是层次输出

7.只打印每层最左侧的元素

8.找每层最小的元素

上面这些操作 搞来搞去, 有啥意思呢?其实没啥意思,但是我告诉你上面前6个题分别是LeetCode的515题、637题、103题、199题、107题、429题。你还觉得没意思吗?

如果将层次的问题解决了,对于每层的处理,上面就是改了改要求就是一道新的题目了。所以面试的算法就是在基本算法的基础上不断修改条件,让你实现对应的功能。假如面试的时候让你做的是第7和8两个题,你还觉得难吗?一点都不难了对不?

上面的7 和8是我自己造出来的题,面试官有时候为了识别出哪些人是专门刷题刷进来的,也会将一些题目的条件改一改,让你现场解决。这就是算法。

一个层次遍历就可以解决6道LeetCode题,还能自己造两个题,这就是我们说的,一招多提,看透本质。

你会觉得,这应该是个例吧,你怎么知道其他题目也是这样的。好!我们再看个例子:

给你一个链表,每 3 个节点一组进行翻转,请你返回翻转后的链表,不足一组的不做处理。例如开始的链表为

1->2->3->4->5->6->7

三个一组,则结果为:

3->2->1->6->5->4->7

这个题目会怎么做?你可能想到先遍历 ,然后将找到的组分别反转。是的,就是这么个思路,但是当你开始写的时候发现贼难处理,如果反转?首结点怎么处理?中间怎么交换?组和组之间怎么处理?一堆的问题,结果写着写着就发现写不下去了。

事实上,在链表的练习中我们会练习如何在不申请额外空间的前提下实现链表反转,之后我们还可以继续训练如何在链表中将指定的区间进行反转, 还会训练如何实现两两反转,最后我们还会训练如何将k个一组进行反转。如果经历过这样一个过程,我们就会发现此时再让我们做三个一组反转的是不是就很容易了?

你可能会问,我怎么知道要训练上面几种方式呢?上面对应的就是LeetCode25、Leetcode24等题目,特别是LeetCode25,就是k个一组反转,如果这个练习好了,直接将k换成3不就行了吗?

这种例子特别特别多,至少有2/3的常考题都属于这种情况。

我们再看一下上面两个题的关系:

层次遍历的:

链表反转的:

观察上面两个图,最左侧是教材以及大部分教程里花大量篇幅介绍的内容,而中间位置的题目在我看到的几乎所有教程中都没有完整的讲述,而面试时经常遇到的可能是最右侧从来没见过的,或者中间位置的题目。

这就导致了教材和面试题是脱节的。我们一方面总感觉算法题毫无章法,全凭运气,一方面又总感觉所谓的算法课学了也没啥用。

原因就在这里!我认为好的教程应该把基本内容快速过完之后,将重点放在上面中间位置题目的训练上,只有这些中间位置的内容进行充分锻炼,我们才可能轻松应对最右侧的面试题。

这就是算法命题的内在逻辑,只有了解了,我们才能看透算法的本质,才知道怎么刷题。可惜我见到的市面所有的教材、教程等都没有这么做。

而且这么做的好处是,当你做了一定量的题目之后,很多新题都不用刷了。比如上面的层次遍历,当你刷了其中三道,剩下的看一下就行,面试的时候现场也能写出来。

3.一题多解 融会贯通

这句话是什么意思呢?我们先来看一个题:LeetCode234题,给你一个单链表,判断这个链表是否为回文链表,例如如果一个链表是 1->2->2->1,就是回文链表。如果是1->2->3->1,就不是回文链表。

这个题你看到之后能想到几种方式来处理?我能想到7种方法。不信来看:

(1)将链表元素赋值到数组,然后用右标从两端到中间来判断。

(2)将元素全部压栈,然后一边出栈,一边与原始链表比较,如果都一致,就是回文链表。

(3)改造上面的方法,先遍历一遍获得长度,然后只将一半的元素压栈。之后的一半元素一边遍历一边与出栈的元素比较。如果都相等,就是回文链表。

(4)采用反转链表的方式,先创建一个原始链表的反转链表,之后再分别遍历两个链表来对比,都一样,则为回文链表。

(5)对(4)进行优化,先遍历一遍,找到中间元素。只为一半的元素创建反转链表,之后两个链表一边遍历,一边比较,都一样则为回文链表。

(6)还是对(4)找中间位置的过程进行优化,使用快慢指针,fast一次走两步,slow一次走一步,当fast到达表尾的时候,show正好在链表的中间,接下来就可以逆序前一半或者后一半。

(7)递归法,这个不好一句话说清楚,这里先不说了。

看到了吗。一个题我们能想到很多种方法处理。那这个是不是个例呢?我们再看一个题:输入两个链表,判断他们是否有公共结点,有则找出第一个公共节点。例如下面这样子:

这个题该如何入手呢?好像一时想不到是吗?我告诉你这个题至少有5种可行的方法。
首先是蛮力法,类似于冒泡排序的方式,将第一个链表中的每一个结点依次与第二个链表的进行比较,当出现相等的结点指针时,即为相交结点,但是这种方法时间复杂度高,而且有可能只是部分匹配上,所以还有要处理复杂的情况。排除!

第一种是Hash法,将第一个链表全部保存到Hash中,然后遍历第二个并检查是否在Hash中存在,有的话一定能找到,OK,第一种方法。

第二种是集合呢?集合的底层实现就是Hash,可以和Hash一样用,OK,第二种方法。

第三种:栈能解决问题,首先创建两个栈,将两个链表分别入栈,然后再一边出栈,一边比较,如果存在公共结点 ,自然就找到了。于是就有了第三种方法。

如果能回到到这一步,其实算法面试就算过关了,下面两种方法比较难想到。

第四种:双指针,这个方式只是稍微麻烦一些,我们这里先不说了,OK,第四种方法。

第五种,如果我们将两个链表分别拼接成AB和BA,就会发现:

AB:0-1-2-3-4-5-a-b-4-5BA:a-b-4-5-0-1-2-3-4-5

此时分别遍历两个合并后的链表,走到第二个4的位置之后,就是 4 和5,正好就是重合的位置。

看到了吗?一个题目我们可以有很多种方式解决。

你可能会问了,有一种方法不就行了,为啥要搞这么多方法?

注意上面两个题,你会发现我们都从链表、栈、双指针等不同的角度来思考,都能解决问题,只是解决问题的难易程度和需要的空间不一样。这就意味着,我们 每做一道题,就将基本功练习了好几遍。这有什么好处呢?是为了融会贯通!

面试官给了你一个算法,如果一时想不到该怎么办呢?连解决问题的思路都没有,这是很多人倒下的第一步。

这时候我们可以将常用数据结构和常用算法都想一遍,看看哪些能解决问题。

我们先在脑子里快速过一下谁有可能解决问题。比如上面的题,我们快速想队列行不行,栈行不行,双指针行不行,等等。如果没想清楚,你也可以和面试官,可能用某某方法可以。接着他会问你怎么做,你可以继续思考,面试官也会给你几分钟让你思考,如果你最后发现不行, 则可以直接说这种方式不行,该用什么什么方法。直到最后找到最合适的方式。

上面这个过程,我们一般不会注意到,但是这就是人的思维方式。常用的数据结构也就数组、链表、队、栈、Hash、集合、树、位图、堆等。常用的算法思想也就查找、排序、双指针、递归、迭代、分治、贪心、回溯和动态规划等等。

虽然LeetCode已经有接近2000题了,但是大家常接触的也不过几百道,很多题目其实还是垃圾题,没必要看。而这些高频题使用的具体方法也不过上面这个范围的。我们虽然说一题多解,但是就是在不断练习这些基本数据结构和算法的,根据要求进行组合与调整,这才是刷算法真正该训练的地方。毫无目的的乱刷,只会越刷越迷茫?如果我们平时刷算法将这些内容刷的滚瓜烂熟 ,遇到各种基本操作信手拈来,面试怎么会过不了?????

4.循序渐进 画图拆解

算法是什么?就是一张图,可能是结构图,也可能是执行的流程图,我们只有清晰得明白每个题的逻辑过程是什么,才能真正理解一个算法。我见过一本书,它是这么解释算法过程的。我看了之后很快就将这本书扔掉了,因为我宁可自己想也不愿意看这么没脑子的解释。其实教别人看懂算法,只要给出一个完整的执行动画就全明白了,不需要太多的废话。

可惜的是,我们当前不会在这方面花太多时间,图示可能也不多,主要是我们现在想将整个算法的体系梳理出来,后面我们再逐渐补充和完善。

5.持之以恒 终会成功

其实上面的道理,大部分都是懂的,也知道该怎么做,但是问题是执行起来实在困难。

在参加咕泡的训练营之后,我养成了每天“早晚+周末”学习的习惯 。如果有事情就做,没有事情就继续学习。结课之后,我决定将这个习惯继续保持下去。技术方面还需要持续学习,就目前而言,感觉技术暂时够工作用,遇到新的也可以在可控的时间内学掉。所以我打算将做了十年的大梦完成——刷清楚LeetCode,基本解决算法问题。

这时候有几个问题需要解决:如何保持工作生活与刷算法之间的平衡?如何能一直坚持?好在现在都找到了相对靠谱的方法。

如何保持算法和工作的平衡

练算法本身就要花费大量的时间和精力,如果一门心思刷,必然会影响到其他方面,该如何平衡呢?

首先,我之前换工作的过程中也练习过算法,还算有点基础吧。更重要的是在训练营的新一期开营之前,我就曾给新学员整理过一套算法笔记,基本算法、常考算法等也算过了一遍。现在在这些工作的基础上进一步拓展和完善也更加容易,花费的时间也相对小一些,至少现在是这样的。

其次,就是公众号令人恶心的问题中最大的好处了。个人公众号一天只能推送一篇,编辑器也不是很好用,而且个人公众号还不能接受评论。但是好处是因为每天都只能推一次,瞎推送的话要撤回,不推也不会将机会累加到下一次,这样都会损失一次机会。为了保证质量,每天都要多多少少看一点,推之前也要用心检查一遍,这会让自己一直保持算法的状态。

更重要的一点就是利用异步缓存的思想,我会一次集中精力准备一批文章,平时只要检查一下,没有问题就一天一篇的发了,花费的时间就更少。已经准备的文章推完之后,我会再集中精力准备一波,这就实现了算法和工作生活的动态平衡。

(3)如何能一直坚持

其实整个事情最难的还是在坚持。我上学的时候曾经参加过几次万米长跑,也参加过几次越野比赛。我的感触是学习更像长跑,而不是百米冲刺。长跑有个要领就是不能快,也不能慢,更不能停下。如果太快,很快就体力不支了,如果太慢或者停下了就再难跑起来。比较好的方式找到一个适合自己的速度一直跑,坚持跑,即使到后面自己没意识了不能改变速度,这样坚持到最后成绩一定不会太差。学习也一样,如果醉心学习,必然影响工作、影响生活。如果一直不刷,临时抱佛脚基本没用,贵在坚持,也跪在坚持。

目标拆解也是个不错的方法,公众号发文章,每次准备一批,每天发一篇的节奏,可以将一个大目标分成了很多小目标,压力就不会那么大了。比如接下来我要准备链表算法的文章,大约15篇,这比上来就要准备100篇就容易很多。半个月后,我要准备10篇左右栈的文章,之后再准备一波树的,这样压力就分散开了。

有个自己的社区也很重要,你的文章被人看,还能得到及时的反馈,这个过程是充满乐趣的。所以每天向微信群转发新文章是最有成就感的事,也促使我能持续不断的输出。

不过呢,公众号的问题就是一旦发了就不能修改了,还不能发评论,无法忍受,现在决定还是回到csdn,以后公众号只简单推一下摘要和csdn地址,整体节奏还是保持一天一篇。

更新内容请关注我的公众号:

征服面试算法-2:算法应该怎么刷相关推荐

  1. 程序员如何快速准备面试中的算法 - 结构之法

    准备面试.学习算法,特别推荐最新出版的我的新书<编程之法:面试和算法心得>,已经上架京东等各大网店 前言 我决定写篇短文,即为此文.之所以要写这篇文章,缘于微博上常有朋友询问,要毕业找工作 ...

  2. 程序员如何快速准备面试中的算法

    程序员如何快速准备面试中的算法 准备面试.学习算法,特别推荐最新出版的 新书<编程之法:面试和算法心得>,已经上架 京东等各大网店 前言 我决定写篇短文,即为此文.之所以要写这篇文章,缘于 ...

  3. 赠书|大厂面试喜欢考算法,该怎么破?

    这两年的软件工程师面试可谓神仙打架! 有些 985.211 院校毕业的高材生都没有拿到满意的 Offer.国内一些大公司的门槛也越来越高,这里的门槛很大程度上体现为对算法能力的要求. 很多人因为算法能 ...

  4. 大厂面试喜欢考算法,该怎么破?

    这两年的软件工程师面试可谓神仙打架! 有些 985.211 院校毕业的高材生都没有拿到满意的 Offer.国内一些大公司的门槛也越来越高,这里的门槛很大程度上体现为对算法能力的要求. 很多人因为算法能 ...

  5. .net 遍历数组找重复值写入一个新数组_面试 | 数组类算法精析

    点击上方蓝字设为星标 每周一.三.五上午 8:30 准时推送 下面开始今天的学习- 面试中的算法问题,有很多并不需要复杂的数据结构支撑.就是用数组,就能考察出很多东西了.其实,经典的排序问题,二分搜索 ...

  6. 分享干货:靠刷算法题,真的可以刷进大厂吗?

    在国外 Facebook,Google 等互联网巨头中,算法无疑是面试中的重头戏,不过,在最近几年国内互联网大厂面试中,算法的比重也越来越高,算法不扎实,笔试可能就直接被刷了. 那你知道大厂的技术面为 ...

  7. 靠刷算法题,真的可以刷进大厂吗?

    我一直不知道我在大家心目中的定位是什么,但我内心其实是把自己定义为一个『工具人』的. 可能是因为我自己本身就是程序员,所以更能理解程序员的不易吧. 所以,我尽量不写水文,只分享干货. 就是希望大家看了 ...

  8. 不用找了,这300家公司面试不考算法

    关于程序员面试要不要考算法的讨论,几乎已经是各大求职论坛的月经帖.而苦于刷题量越来越多的同学不禁要问:有没有不面算法的公司? 答案当然是有的,Github上就有一个star 15k的项目,名叫hiri ...

  9. 数据结构与算法太重要了,刷了两月题,终于进入了梦寐以求的大厂,

    前言 最近一个读者和我反馈,他坚持刷题2个月,终于去了他梦寐以求的大厂,薪资涨幅非常可观,期间面字节跳动还遇到了原题... 因为据我所知很多大厂技术面试的要求是:技术要好,计算机基础扎实,熟练掌握算法 ...

  10. 如何快速准备面试中的算法,获得 Offer?

    如何快速准备面试中的算法,获得 Offer? 现如今越来越多的公司在面试过程中会考察数据结构和算法.在最近几年,难度颇有上升趋势.因此作为求职者,在面试前刷刷题似乎已经成为准备过程中必不可少的环节了. ...

最新文章

  1. tf.truncated_normal和tf.random_normal使用方法的区别
  2. 在线抠图工具:亲测有效
  3. 第三天 css核心属性
  4. 母版页调用内容页的方法的简单实现
  5. 计算机系统组装 维护常用工具及其作用,《计算机系统组装维护》课程实用标准.doc...
  6. idea中@Data标签getset不起作用
  7. 用深度强化学习玩atari游戏_(一)深度强化学习·入门从游戏开始
  8. java第六次作业 计科1501班 张鹏
  9. centos7上的图形化界面svn客户端_基于windows平台的SVN教程。
  10. Flask 应用上下文
  11. AcWing 91. 最短Hamilton路径(状态压缩DP+哈密顿回路)
  12. scala Basic 第三课
  13. vs2012安装教程图文版
  14. ExtremeComponents源码解析(一)
  15. 1998-2018 TOM邮箱20年发展
  16. TabLayout+ViewPager实现tab切换
  17. python 打开excel并在屏幕上呈现_python读取excel数据,并可视化展现
  18. Docker容器运行GUI程序的方法(直接进入Docker容器运行或通过SSH连接Docker容器运行)
  19. 制作一套适用于Oracle数据库的县及县以上行政区划数据
  20. php7的新特性有哪些,php7新特性有哪些?

热门文章

  1. 云栖科技评论84期:英国零售商找错了“替罪羊”...
  2. 计算机内,二进制小数的表示方法
  3. linux mate中文输入法,树莓派3b基于UbuntuMate下载中文输入法(示例代码)
  4. python基础学习笔记之数据基本类型:逻辑值
  5. 绝对值编码器工作原理是什么?单圈/多圈绝对值编码器有何区别?
  6. 性能之巅-第一章-简介
  7. 安装Android应用至SD卡
  8. zuk android os 流量,ZUK Z1国际版:细数Cyanogen OS的几点不同
  9. epsxe安卓最新版下载_ePSXe模拟器下载-ePSXe安卓中文版下载-电玩咖
  10. 深入RecyclerView(一)