经验之谈
1、学习算法的经验分享
1)、多写自己的博客 积累起来,可以让自己学得更清楚
2)、掌握算法的学习体系和内在逻辑,不瞎做题
2、很忙,没时间学习,怎么协调时间?
1)、早上7点左右起来学习一个小时,然后9点到公司去上班
2)、晚上20:30左右下班,21:00继续学习到12点左右,12.30睡觉
3)、专注学习,该社交社交,该健身健身,结束了快速把心收回来,该干嘛干嘛
怎么学习算法?
1、学习算法的误区
1)、学而不思,或者思而不学
如果刷过一定量的题,一定会发现大量的考察点是重复的,很多问题本质上是一个东西,所以题目是月刷越少的。
做题应该以半小时为界限,如果办小时还没有还想不到怎么做,就应该找被人的解析来学习。
2)、真正坚持和学习的时间太少
3)、总想着异步登天,一劳永逸
有的人希望算法能达到熟记的程度,抬手就能来,这是不可能的,我们重点在于理解清楚,面试的时候给你点时间就能想明白、写出来,而不是全部记熟才算。
不要只盯着难题,不重视基础问题。
4)、避免算法毒文章引起的焦虑。
很多文章会推荐一堆的书特别是《算法导论》,这本书虽然叫导论,但是比一般的
算法书要难很多,没有足够的数学功底根本看不了。气垫不高的人看了会迅速失去信心,因此这本书对大部分人来说,根本不适合。
5)、面试算法和工程算法有很大差异。工程算法会使用大量hash,更注重简单很稳定性;而面试算法更考察思维能力
6)、虽然大部分都不会在工作中用,但是算法本身就是思维能力的一种证明。
7)、不要死记硬背代码,而是将技巧总结出来,最后将题目归类总结出本类题型的解题套路。
2、面试&算法
1)、社招面试的考察点主要有3个:
- 基本功是否扎实,基本功不扎实,写的代码可能到处是bug
- 编码规范性如何,如果很混乱,边界、异常处理不清楚,那承担的任务肯定不能让人放心
- 思维能力如何,是否能短时间内解决问题。这反应的就是平时遇到问题是否能够很好的解决掉,而不是天天无能为力
因此面试算法的特点:
- 让面试者能在20-40min左右完成
- 基本数据结构的变形题,有思维含量,但不会太难太偏
- 代码精简,一般50行以内就能解决问题
2)、面试什么时候会出很难的算法题?
- 校招,筛人
- 先做笔试题或者上级编程再去面试的时候
- 没那么想要你,可能公司都快不行了,招人只是个噱头,公司的起起伏伏、生生死死太厉害了。这也说明,很多时候不见得是你的问题,而是对方的问题。
- 面试官经验不够,不会出题,出题较偏。面试是一个双向选择的过程
——》我们学习算法更多的是将算法面试的成功从全靠运气变成80%的题目都会做,这就够了。
3)、那算法掌握多少算合适呢
数据结构以及相关变形、拓展问题要掌握,大约150到核心题目。
高级专题要掌握滑动窗口、BFS、前缀树、数字和部分数学问题、回溯贪心、动态规划等大约200道核心题目。
4)、现实中,一个问题一个解法,但是有很多问题的处理思路往往是一样的,所以很多人不断将一些通用方法进行总结和归纳就产生了对特定场景的解题思路,例如暴力无法解决的问题可以考虑使用回溯思想,为了防止数组中频繁对大量元素进行移动而产生了双指针思想。而将一些常用思想汇集起来就是我们常常说的算法,例如广度优先搜索、回溯、贪心、动态规划等等。
3、面试时怎么写算法
面试更多考察思维水平,而且很多时候靠的是面试官对你的一个感觉,因此要注意与面试官交流,让其有个好的面试映象。
1、理解问题,复述问题从而明确问题,防止理解错误
2、进一步确认问题,并大胆说出想法,逐步找到最优想法
很多面试官不见得会将问题描述很清楚,这时候你的思考和引导会极大影响面试官对你的认可程度。
3、先写整体,再考虑边界
代码里重要的扣分点就是边界情况的处理和特殊常场景的解决,很多人都会栽在这里。
4、评判性能,优化解法
一般写完算法之后都会和面试官简单聊一下当前算法的复杂度情况。平时刷算法的时候也要注意每个解法的空间复杂度和时间复杂度
另外再强调一下,代码写的时候命名要专业一点,不要随便int a,b这种。命名问题很大程度反应了这个人的专业程度。
4、正确的刷题姿势
1、按专题刷题
2、用大白话理解问题
算法不会,我们会感觉是自己不行,但是很多时候是因为别人写的东西为了提高逼格,罗列一堆晦涩的专业名词。专业名词是减少专业人士之间的废话的,而不是给小白看的。我认为这也是国内很多教材让人看不懂的原因。
3、多画图
任何算法都是一个图,只有这个图在大脑里勾勒清楚了,才叫学到家了。比如二叉树
的层次遍历执行过程是怎么样的?元素大致怎么移动的怎么将每层分开?这些想清楚了,过几个月仍然会记得。而不是没行代码都记得才叫练算法。
图勾勒出来之后,以后花在算法上的精力会越来越少,自然可以那时间准备架构等更高级的东西,从而才能拿到更高的薪资。而不是每次都为基本问题搞不定而浪费时间。
5、 学习方法
1)、 学习数据结构和算法的过程,是非常好的思维训练的过程,所以,千万不要被动地记忆,而是要学习:
- 它的“来历”
- “自身的特点”
- “适合解决的问题”
- “实际的应用场景”
2)、边学边练,适度刷题:
“边学边练”这一招非常有用。建议你每周花1~2个小时的时间,集中把这周的三节内容涉及的数据结构和算法,全都自己写出来,用代码实现一遍。这样一定会比单纯地看或者听的效果要好很多!
3)、多问、多思考、多互动
4)、打怪升级学习法
知识需要沉淀,不要想试图一下子掌握所有: 在学习的过程中,一定会碰到“拦路虎”。如果哪个知识点没有怎么学懂,不要着急,这是正常的。因为,想听一遍、看一遍就把所有知识掌握,这肯定是不可能的。学习过程是反复迭代、不断沉淀的过程。可以先沉淀一下,过几天再重新学一遍。所谓,书读百遍其义自见。
数据结构与算法基础
1、什么是数据结构与算法
从广义上讲,数据结构就是指一组数据的存储结构。算法就是操作数据的一组方法。
从狭义上讲,也就是我们专栏要讲的,是指某些著名的数据结构和算法,比如队列、栈、堆、二分查找、动态规划等。
那数据结构和算法有什么关系呢?为什么大部分书都把这两个东西放到一块儿来讲呢?这是因为,数据结构和算法是相辅相成的。**数据结构是为算法服务的,算法要作用在特定的数据结构之上。**数据结构是静态的,它只是组织数据的一种方式。如果不在它的基础上操作、构建算法,孤立存在的数据结构就是没用的。
2、复杂度
数据结构和算法解决的是如何更省、更快地存储和处理数据的问题,因此,我们就需要一个考量效率和资源消耗的方法,这就是复杂度分析方法
1)、20个最常用的、最基础数据结构与算法
10个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie树;
10个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法。
2)、大O时间复杂度实际上并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势,所以,也叫作渐进时间复杂度(asymptotic time complexity),简称时间复杂度。
时间复杂度的全称是渐进时间复杂度,表示算法的执行时间与数据规模之间的增长关系。
空间复杂度全称就是渐进空间复杂度(asymptotic space complexity),表示算法的存储空间与数据规模之间的增长关系。
如何求时间复杂度
只关注循环执行次数最多的一段代码
大O这种复杂度表示方法只是表示一种变化趋势。我们通常会忽略掉公式中的常量、低阶、系数,只需要记录一个最大阶的量级就可以了。所以,我们在分析一个算法、一段代码的时间复杂度的时候,也只关注循环执行次数最多的那一段代码就可以了。
加法法则:总复杂度等于量级最大的那段代码的复杂度
那我们将这个规律抽象成公式就是:
如果T1(n)=O(f(n)),T2(n)=O(g(n));那么T(n)=T1(n)+T2(n)=max(O(f(n)), O(g(n))) =O(max(f(n), g(n))).
乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
如果T1(n)=O(f(n)),T2(n)=O(g(n));那么T(n)=T1(n)*T2(n)=O(f(n))*O(g(n))=O(f(n)*g(n)
常见复杂度量级
按数量级递增:
常量阶: O(1),只要代码的执行时间不随n的增大而增长,这样代码的时间复杂度我们都记作O(1)
对数阶: O(logn)
线性阶: O(n)
线性对数阶:O(nlogn)
平方阶: O(n ^ 2)、 立方阶 O(n^3)……k次方阶 O(n^k)
指数阶: O(2^n)
阶乘阶: O(n!)
对于这些复杂度量级,可以粗略地分为两类,多项式量级和非多项式量级。其中,非多项式量级只有两个:O(2^n)和O(n!)。把时间复杂度为非多项式量级的算法问题叫作NP(Non-Deterministic Polynomial,非确定多项式)问题。当数据规模n越来越大时,非多项式量级算法的执行时间会急剧增加,求解问题的执行时间会无限增长。所以,非多项式时间复杂度的算法其实是非常低效的算法。因此,不需要过多关注非多项式量级,重点关注几种重要的多项式量级。
最好、最坏、平均、均摊
为了表示代码在不同情况下的不同时间复杂度,需要引入三个概念:最好情况时间复杂度、最坏情况时间复杂度、平均时间复杂度。只有在不同的情况下,时间复杂度有量级的差距,我们才会使用这三种复杂度表示法来区分。
顾名思义,最好情况时间复杂度就是,在最理想的情况下,执行这段代码的时间复杂度。
同理,最坏情况时间复杂度就是,在最糟糕的情况下,执行这段代码的时间复杂度。
我们都知道,最好情况时间复杂度和最坏情况时间复杂度对应的都是极端情况下的代码复杂度,发生的概率其实并不大。为了更好地表示平均情况下的复杂度,我们需要引入另一个概念:平均情况时间复杂度,后面我简称为平均时间复杂度。(找出所有的输入情况及相应的发生概率,然后再计算加权平均值。)
均摊时间复杂度:对一个数据结构进行一组连续操作中,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度比较高,而且这些操作之间存在前后连贯的时序关系,这个时候,我们就可以将这一组操作放在一块儿分析,看是否能将较高时间复杂度那次操作的耗时,平摊到其他那些时间复杂度比较低的操作上。而且,**在能够应用均摊时间复杂度分析的场合,一般均摊时间复杂度就等于最好情况时间复杂度。**均摊时间复杂度其实就是一种特殊的平均时间复杂度,没必要花太多精力去区分它们。