程序员练习算法的几个实用技巧

上周在公司内部分享了自己练习算法的心得和经验,有小伙伴表示分享的内容给他带来了价值,也很具备参考意义,于是就算法写成文章分享出来,近几个月来,自己每周都会花1、2小时在 Leetcode 上面练习算法,短短几个月下来也陆陆续续交出 40~50 的解题作业,算是一个小小的里程碑吧,以下是我最近的刷题记录:

所有的解题记录我传到了的公开的 Github 项目,有兴趣的可以访问链接看看

偶尔在算法群里也有小伙伴总是在问:“刷题太难了,自己总是虎头蛇尾,你们是怎么坚持下来的 ?,有什么方法吗?”,其实很多人刚开始都是热情满满,然后马上就三分钟热度了,这其实也很正常,我也通过自己几个月的探索和坚持,踩了不少坑,所以总结了不少我个人觉得行之有效的刷题经验,跟大家分享一下,也避免大家后续再走弯路

总体大纲如下:(预计 5分钟能读完)

  1. 为什么要练习算法 ?

  2. 如何有效的练习算法 ?

  3. 最后总结(关键的关键)

为什么要练习算法 ?

相信高手都明白算法和数据结构是基本功,但是还有很多刚入行的新人不是很明白,我的个人观点如下:

  • 程序员的基本功:长期的练习算法会让你关注程序实现效率,既时间和空间复杂度,没有算法训练的程序员只能写出垃圾的代码

  • 学习算法不容易过时:例如 快速排序 是在 1960 年发明出来的,相比流行的框架,语言和新技术而言,算法很难过时,更值得学习

  • 更容易理解热门的技术:例如比特币(基于链表实现),区块链如何保证安全交易(一致性共识算法),等等……简直不胜枚举

  • 我们生活在一个概率的世界,如果有算法和数学的思维,更容易在概率的世界中找到最优解,例如:打牌,做决策等等。。。

常用的编程语言大多都是对数据结构的封装,所以很多面试官特别喜欢问以下的问题,例如:

  • LinkedList 和 ArrayList 的区别,数组和链表的扩容方式(考察你对数组和链表的理解)

  • HashMap 的内部结构(考察你对数组 + 链表组合模式的理解)

  • HashMap 为什么使用红黑树(考察你对多种树的数据结构的理解)

  • 快速排序和归并排序的区别(考察你对排序算法的理解)

  • 二叉树的前序,中序,后序等(考察你对树的遍历的理解)

  • 等等 ……

而且根据我了解的很多面试官其实根本不在乎你使用什么编程语言,熟练使用什么技术框架,这些只是“术”的层面,他们更加在乎你是否具备解决问题和抽象问题的能力,这些才更加具备长期的价值,更加接近“道”的层面,那么如何考察呢 ?就是通过算法,最好是通过在白板上给出解题的过程和思路,例如 Google 就特别喜欢这样做。闲话扯的有点远,我们下面进入正题

如何有效的练习算法 ?

一:端正心态和学习态度

我觉得既然下定决定要去学习,那么首先要调整的就是心态,这个社会大部分人都很浮躁,想要速成,但是学习是不可能速成的,需要先定好目标,然后一步一步向前行,首先我先推荐一本书《异类》

这本书通过各种案例向大家传递了关于“一万小时“的理论,而且不是勤勤恳恳的重复的一万小时,必须是有目标,有阶段,不断按曲线成长的”一万小时“,不然的话你也只是在感动自己而已,任何不经思考的学习和练习都是徒劳

如果要按照这个理论,就是说一个普通人,每天要花 3-4 小时的学习成长,差不多持续十年,你才有可能成为行业的高手和专家,所以要明白很多成功都不是偶然的,很多看似轻松达成某些成就的人,背后都付出常人无法理解的痛苦和努力,就像那些看上去身材很好的人,他们显得很年轻,穿衣服也很好看,但是你没有看到他们咬紧牙关在锻炼的时间,bob 大叔在《程序员的职业素养》一书中也说过一句话”任何专业人士都需要保持刻意连续,钢琴家,医生,律师,拳击手,吉他手,乐队等等,想要成为专业人士都必须保持刻意的练习“,所以大家应该明白学习没有捷径,想要成为专业人士,就要付出相应的努力

二:用玩游戏的心态来学习

学习和看书那么苦,那么累,还要坚持那么久,我们能不能想一些方法来减轻这种痛苦的感受?

答案是有的,也是我自己认为行之有效的一种,那么就是:用玩游戏的心态来学习(关于游戏如何利用反馈机制让人上瘾的细节我就不详细说明了,不了解的同学有兴趣自行去 Google 了解反馈机制对大脑的刺激)

那么具体如何操作呢 ?我简单总结以下两点:

回想一下你是如何成为 英雄联盟/王者荣耀 高手的 ?

主要分以下几步:

  1. 主动尝试:进入游戏随便选择一个英雄,简单看看技能尝试玩一玩

  2. 熟悉常用技巧:慢慢熟悉使用英雄所需要装备,顺便熟悉地图,例如躲草丛

  3. 开始学习如何见招拆招:开始了解敌方英雄的技能和套路,并且熟悉对线的技巧

  4. 主动学习和练习:对于自己还未熟悉的英雄和技能反复练习,慢慢形成长期记忆

以上是玩游戏的步骤,那么对于练习算法,我们也可以用同样的步骤:

  1. 主动尝试:首先进入一个刷题网站(Leetcode、牛客等),随便找几个简单题目尝试一下

  2. 熟悉常用技巧:慢慢熟悉常见的数据结构,例如:数组/链表/Queue/Set/Hash/Tree 等等

  3. 开始学习如何见招拆招:熟悉常用算法题的套路和技巧,例如:双指针/哈希/位运算/反转链表/二分/递归等等

  4. 主动学习和练习:对于自己还未熟悉的类型结构反复练习,慢慢形成长期记忆

以上可以发现其实玩游戏的思路可以用在算法练习上,而且效果还不错,不过仅仅做到以上几点,还不能成为一个游戏高手,通常如果你想在游戏里面成为高手还需要做到如下几点,,我称之为:

Feedback 持续反馈:

  1. 多打排位赛和天梯,跟自己等级相同的人对抗(对应到练习算法就是找符合自己难度的题目,多练习)

  2. 多逛论坛和高手讨论,多看前人的攻略并且自己不断的总结心得(相同)

  3. 多看相关的比赛和直播,看高手之间竞技,并且学习套路(相同)

如果能用以上的方法,再加上持之以恒的心态,应该就能成为一个(游戏/算法)的高手了

三:刷题的注意事项

上面总结了如何调整心态,下面我们讲讲在刷题阶段的几点注意事项

我自己刚开始也是没有方法,上来就是一顿猛刷,结果刷了忘,忘了继续刷,结果浪费时间不说,而且自己也没有从中收获到价值,这对于出题的作者和我本人都是双输的结果,而且后面跟几个小伙伴在微信群里面组队刷题的时候,看到很多小伙伴都重复犯了这个错误,甚至有的人从此对算法失去兴趣,可惜可惜……

对于初学者练习算法,我有以下几点建议,简称 CPCT 法:

  1. 认真审题 Clarification:一定要明确作者出题的意图,复杂度的要求等等,例如作者想考察你的二分查找,你非要用暴力破解,虽然也能解题,你失去这道题最精髓的内容

  2. 找到最优解 Possible Solution:上面也说了解题的代码要符合作者对时间/空间的要求,不过这里我建议你分两步走,很多经典的算法题是经过很多年才总结出现了,除非是少部分的天才,大部分人很难在短时间内找到最优解,第一步可以先尝试用最简单的方法把题目解出来,然后再逐步的优化代码,直到达到作者要求的最优解,重复一下上面的观点,每道题的最优方案才是这道题最精华的内容,也是作者最想考察的知识点

  3. 反复练习 Coding:多写代码,多练习,算法就是三分学,七分练

  4. 覆盖测试 Tests Cases :当提交的 Case 被判定不通过的时候,是一件很痛苦的事情,所以提交 Case 前尽量在本地最好足够的测试,这点也可以用在我们平时写代码的习惯上

四:介绍一下复杂度

有一个很经典的算法问题,就是要计算 1+2+3+4….+100 的总和的方法:

因为 100 也不算很大,很多同学估计这样计算:

  • 先计算 1 + 2 得到 3

  • 再用上面的结果计算 3 + 2 得到 5

  • 再用上面的结果计算 5 + 3 得到 8

  • 以此类推,重复 100 次

勉强计算 100 次后,我们得到 5050 的最终结果,

我们再把问题扩大一下,如果要计算的值不是 100, 而是 1 + 2 + 3 + 4 …. 一直到 1000, 或者 10000 呢 ?如果值是 1000,那么就要重复计算 1000 次,如果值是 10000 ,那么就要重复计算 10000 次,负责计算的人估计会崩溃了(没错,计算机也是这么想的),随着 N 越大,要计算的次数越多,这种需要计算 N 次的算法,我们评估它的时间复杂度为:O(n)

这时候还在读小学,并且不愿意透露姓名的高斯同学,发现的计算的规律,并且总结的求和公式:Y = n * (n + 1) / 2

使用这个公式不管要计算的值有多大,得到的结果都是相同,而且永远只需要计算一次,这种方法我们评估它的时间复杂度为:O(1)

这也是算法的目的:在保证结果正确的同时,将时间复杂度和空间复杂度降到最低

常见的大O表示法和常见的术语:

从优 >> 差的复杂度排序:

  1. O(1):常数复杂度

  2. O(log n):对数复杂度

  3. O(n):线性复杂度

  4. O(n log n):nlogn 阶

  5. O(n^2):平方

  6. O(n^3):立方

  7. O(2^n):指数

  8. O(n!):阶乘

最后总结

关键的关键
  1. 多练习,刻意练习(找到自己缺陷,反复练习)

  2. 推荐网站 LeetCode (按照类型分组,按照类型练习)

  3. 切题的方法(吃透所有解法,找到最优解)(注意时间/空间复杂度)(使用你熟悉的语言和编辑器)

  4. Feedback 持续反馈(主动学习)

  5. 重在实践:三分学,七分练(切莫贪多,贵在坚持)

  6. 组队打卡:找到有共同兴趣的朋友一起练习,更容易坚持(想要加入算法打卡群的请给我留言)

给TA买糖
共{{data.count}}人
人已赞赏
经验教程

ocelot 中间件的变化

2021-1-10 20:22:48

经验教程

彻底搞懂JavaScript的闭包、防抖跟节流

2021-1-10 20:26:02

⚠️
免责声明:根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。 本站为个人博客非盈利性站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途,网站会员捐赠是您喜欢本站而产生的赞助支持行为,仅为维持服务器的开支与维护,全凭自愿无任何强求。本站部份代码及教程来源于互联网,仅供网友学习交流,若您喜欢本文可附上原文链接随意转载。
无意侵害您的权益,请发送邮件至 momeis6@qq.com 或点击右侧 私信:momeis 反馈,我们将尽快处理。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索