只接受发布货源信息,不可发布违法信息,一旦发现永久封号,欢迎向我们举报!
1064879863
16货源网 > 餐饮行业新闻资讯 > 软件开发 >  大家都是如何刷 LeetCode 的?


大家都是如何刷 LeetCode 的?

发布时间:2019-09-02 02:27:34  来源:网友自行发布(如侵权请联系本站立刻删除)  浏览:   【】【】【
聊天的时候朋友说这个题目挺有趣的然后就去试试看了,做过开心,做不过没所谓。
大家都是如何刷 LeetCode 的?

聊天的时候朋友说这个题目挺有趣的


然后就去试试看了,做过开心,做不过没所谓。

根据自己的情况进行刷题吧,那个地方比较薄弱,按照同类题进行刷更有效果,leetcode这方面做的很好,体验极好。

从第一题Two Sum开始,默默刷了一年多,算不上经验吧,就是我自己的一点碎碎念。没什么条理,想到哪儿写到哪儿。


刷题我见过两种流派,一种【兔系】,一种【龟系】

【龟篇】

我自己是比较偏“龟系”的刷法【传送 >ciaoshen.com】从一开始为了找工作,每天4,5题,到后来慢慢变成一种习惯,每天早上起来,喝两口咖啡先来一发。我个人比较信奉Peter Norvig的 “十年理论”。之前Dave Thomas提出的 ”Code Kata“ 也是类似的概念,核心理念就是 “刻意训练” 。现在刷leetcode就是我坚持的“刻意训练”的一部分。日常工作里调调参数,修修Bug,用用框架实际上达不到”刻意训练“的标准。像leetcode这样的OJ正好提供了这样一个”道场“不是很好吗。

我们有的时候过分注重了算法题的“算法意义”,而忽略了”工程意义“。题刷多了就知道,常用套路其实来来回回就那么几个。但明确了算法,能不能准确地实现,做到bug free又是另一回事。再进一步,数据结构用的合不合理,也会影响最终效率。代码写出来,别人好不好懂,又是另一个层面的要求。最后要参加面试,又必须在规定时间里完成,不但要写的快,代码还要干净,符合工程规范。

所以”龟系“刷法的精髓就是每个题目要做干净。不要满足于一种解法,各种解法都写一写。我现在accept了350+题,用了1000多种方法。平均每题2~3个Solution。基本每题都做到beats 90+%

350+Problems / 1000+Solutions

最好不要满足于accept,要追求最高效率。做一题就要杀死一题。leetcode不是给了运行时间的分布吗,基本上每个波峰都代表了一种特定复杂度的算法,中间的起伏体现的就是具体实现细节的差距。每次都要向最前面的波峰努力啊>.<。追逐最前一个波峰的过程不但锻炼算法,还锻炼数据结构,锻炼对库函数的熟悉程度。经常比较不同数据结构不同库函数的效率,时间久了能产生一种直觉,以后一出手就是最优选择。(小贴士:点开竖直的分布条,是可以看到对应代码的,对学习高手的解法很有帮助。)

但“龟系”不是说在一道题上耗死。越是龟系越要注意时间上要掌握好分寸,能解出来最好,解不出来也不要倔强。我觉得比较好的一个平衡点差不多是“一个小时”。如果一个小时还是解决不了可以点开右边Related Topics链接看提示。还是不能解决就看讨论区。

现在一年多坚持下来,最大的收获不是知道了多少算法套路,而是代码硬能力上的进步。之前经常会卡在一些实现细节的地方,现在只要整体方向确定下来业务逻辑捋清楚,具体实现编码反而是最轻松的工作。这就是为什么大厂面试要考算法。功底好的工程师才有精力腾出来考虑工程,产品方面的问题。

【兔篇】

“兔系“更加符合”刷题“的说法,就是按标签刷,按公司刷。今天做binary tree就一下子做10,20题。很多人可能对这个做法有点抵触,觉得太功利,没有思考的过程。当初我也有这个偏见。但后来发现很多最后拿到FLAG offer的大神都这么干。而且过程之暴力令人发指。记得有个大神刷到第三遍,每天可以做80+题。拿到题根本不思考,直接在自带编辑框开始码,而且还基本做到bug free。

我也不知道他是不是在吹,但“兔系”的精髓就是要暴力,天马流星拳,大力出奇迹。有的人提倡”不要看答案“。这种观点我觉得是对的,像我自己就很少看答案。但作为兔系选手,讲求的就是要疯,不如一上来就看答案,就照着答案写。这个做法看起来不靠谱,其实它有内在的合理性:大部分算法都不是我们发明的。什么动态规划,二叉树,线段树,并查集,贪心算法,到后来所谓的不看答案自己做出来,其实都是在用固定套路。到最后你看那些acmer高手,看似思路很快,其实就是知道的套路比你多,而且不是多一点。所以既然明确了是为了找工作的目标,那就放下矜持,放下承见,拿到offer比什么都强,哪怕是以一种羊癫疯的姿势。


最后,刷题呢工具一定要用起来。比如我用Java刷,什么ant, gradle, junit, log4j, slf4j都用起来。可以省去很多搭环境,搭框架的时间,把精力都集中在解决算法上。leetcode最近出了一个Playground我就觉得很好呀,直接在网页上写代码省去了很多麻烦。但我也提个小意见,就是如果能更完整地支持vim就更好了。现阶段我还是不得不自己开编辑器。这里给大家安利一个一键生成"Solution/Test"框架的小工具leetcode-helper

helloShen/leetcode-helper

下载地址(最新v0.55):

  • 【leetcode-helper-v0.55.tar】
  • 【leetcode-helper-v0.55.tar.gz】
  • 【leetcode-helper-v0.55.zip】


一行命令ant generate,生成支持Junitlog4j/slf4jSolution/Test/TestRunner 骨架类,

一行命令生成Solution以及Junit单元测试骨架

一行命令ant compile test,实现编译以及JUnit单元测试。

一行命令编译,运行JUnit单元测试

而且附带了一个leetcode常用数据结构包com.ciaoshen.leetcode.util。 像常用的比如ListNodeTreeNode的基本实现都有了。

现在每天早上拿着我的煎饼果子和咖啡,一键生成骨架,开编辑器就坐下来写算法,然后一键测试,提交。然后该干嘛干嘛。leetcode真的成了我的一种生活方式。不求名,不求利,但求无愧于心,干一行爱一行。

刷了一年半,目前刷过了800+的题。
周赛迄今参加了75次,其中9次前50,18次前100,28次前200.
北美生物医学的Phd,工作非cs领域。高中有一点信息学竞赛的基础,高考之后到phd毕业之前的4+3+6=13年没做过一道算法题。

———————

2018.11.30 更新: 在十一月的一次LC周赛(本人的第81场周赛)中取得了第三名。同时这个月底签了狗家。刷题并不是人生的全部,打算金盆洗手了。

———————

2019.2.27 更新

2018年9月份的时候建了一个微信群,严格要求每日打卡和周末的比赛。如果想参加,并且确定能坚持至少两周以上,可以私信我加微信。

官慧峰:LeetCode每日打卡和竞赛群

我学完了c++,数据结构,算法就开始刷leetcode上的算法题。

我是按照tag来刷,刚开始的时候看了一下tag里的分类,选择从递归开始,因为对我来说递归好理解比较简单,所以从自己喜欢的类型,是希望这是一个好的开始。

选好tag后,我从hard题(不带锁)开始做,因为喜欢从难到易。

第一题leetcode就是是Number of Atoms,我做题是在纸上画一个大概流程,画了图后会有一个对程序比较直观的理解,然后顺便写上伪代码,伪代码就是有方框图有标记一些变量该用什么循环之类的关键词,如果遇到卡壳的地方,我会google,然后看一下人家的解题(先不去理解,因为还要再挣扎一下看自己能不能解决这个卡壳),一眼快速扫过看看有没有关键词提示词,举个例子比如看到了map,那我就回顾一下之前所学过关于map的内容,再看一下自己的伪代码有没有用得上的或者需要修改的,有需要的话就会用上。有时候有些语法的东西忘了,我就顺便看一下《c++ primer》相关的知识点,假如这次看了某章某节,就在用mind node里的树状笔记补上。

目前才做完recursion的两题hard题,没有让我灰心丧气不想做题。不过我的c++用的不是很熟练,希望刷完hard题之后我的代码能力会提高。

下一个tag就是刷map的题,因为map刚复习过;或者动态规划吧,因为动态规划也会用到递归,而且题比较多,跃跃欲试中。明天就可以开始啦,期待地搓搓手。

图是我的c++ primer笔记。

为了找工作,16年开始使用leetcode刷题,有一些心得体会可以分享。

刷题前的背景

  • 本科EE。上过的相关课程:cpp,数据结构与算法,算法设计与分析。

刷题工具

  • 国际版 leetcode.com。国内版leetcode虽然题目一样,周赛一样,但是没有上线discuss板块,题目的官方参考solution也不如国际版及时。当然国内版也以肉眼可见的速度在完善。
  • 我在网页编辑器里直接码,没有用IDE。这也许不是个好方法,有很多人推荐用IDE+框架(好处是有代码补全;拼写检查;debug也更方便也更高效,等等)。
  • 网站 Reference - C++ Reference ,记不住STL数据结构用法时查阅。
  • 纸和笔:想不明白的时候在纸上写写画画,帮助思考。
  • 手机:倒计时功能提示时间,时间到了之后如果没有思路,或WA,或TLE,就到Discuss讨论区取经。

我的刷题经历大概有下面几个阶段:

第一阶段,16年夏天,刷题顺序是easy >> medium >> hard,题目范围是前300道。

  • easy部分,熟悉了cpp的语法以及STL的用法(经常遇到记不住function名字的情况,我会查阅 Reference - C++ Reference 这个网站)。这部分题目基本能独立写出来。
  • medium部分,重温了基础的数据结构和算法,重点总结了各种常见数据结构和算法。
  • hard部分,很多题没有思路,需要看Discuss。
  • 刷题节奏大概是easy阶段每天12道,medium阶段一天能做8道,hard阶段随缘2~4道。(早八点到下午六点,中间只有吃饭没别的活动了,晚上跟着ucb的cs61b学学java)每道题AC后,会检查运行时间。慢的话就去discuss上学习大神们的解法思路,然后自己写一遍提交。查看discuss的情况还包括:自己的代码写的很繁杂,逻辑不清晰,自己又理不顺时;题目的tag里提示有别的解法时;想了半小时以上没思路时。
  • 这个刷题顺序的缺点是,难以发现同类题目的共性。后来我在第二阶段按照Tag又刷一遍。

第二阶段,17年春夏,按题目Tag(bfs, dfs, dp ...)把做过的题再做一遍并总结,每个类别写了点笔记。这一遍总结了很多常用的算法snippet和套路,基本烂熟于心。对于每个Tag,也是按easy>>medium>>hard的顺序过的。这一阶段感受到水平显著提高:

  • 思路和code变得更简洁:大部分题目代码量控制在50行以内。
  • 能够bug free且快速地写出常用的代码块(比如union find,dfs/bfs几个变种, binary search, partition 等等)。总结的snippet和套路使我能够bug free的解决medium题目。
  • 得益于上面一条,medium类型解题时间缩短。
  • 能够选用更简单的数据结构,使得运行时间更快。

第三阶段,18年秋季开始至今,每周参与leetcode contest,保持手感。虽然水平差只能过三道题(hard题要么没思路要么TLE),但也乐在其中。赛后写篇笔记,分析一下遇到的问题。这阶段应该不能算是刷题了(我理解的刷题是短时间内做很多题)。不过一年contest做满的话也有200多道题了。


2月6号更新:

终于能做完四道题了,最近的周赛题目有点水。

中国版的网站看起来不比国际版差了。题目页面有了评论区,还可以切换中英文。

感觉上班没啥劲的时候就刷一刷。工作跟别人互怼了之后就刷一刷。


进展缓慢,快一年半了,才600道。https://code.dennyzhang.com

用python刷题,一天三道,先刷easy。基本上每道题都会想出几种不同方法——常规方法,技巧方法,One line方法。

从2018.9.26开始,每天坚持下去,目前已经养成了每天必刷的习惯。因为工作也找到了,只是把Leetcode当成一种兴趣习惯来,每天花个半小时到一小时,足矣。

https://github.com/EachenKuang/LeetCode

现在先用python刷,等刷完一圈再使用Java来试试。目前的进度大概有100道了,保守估计等明年毕业之前应该可以结束。

然后二刷!

———————————————

11.26

目前已经突破200道了,开始以专题的形式刷,string刷到median,array马上结束easy题了。

做了个图解LeetCode题目的项目,26000star。

MisterBooo/LeetCodeAnimation

刷 LeetCode 的大局观

目前主流的刷题流派有两种,一种【龟系】,一种【兔系】

”龟系“刷法的精髓就是每个题目都做干净。不满足于一种解法,各种解法都写一写。这种流派适合不太急于准备算法面试的小伙伴,追求算法的干净优雅。

“兔系“刷法的精髓是暴力,按照标签来刷,使用固定套路来刷。比如小吴之前分析的那道拍案叫绝的算法题,如果告诉你是标签是异或,你马上能 AC 。这都是套路。

每个标签内部可以按照 Easy 、Medium、Hard 的顺序做,算法练习是一个系统工程,不要一开始就追求难题,先熟悉熟悉套路,循序渐进的去做,后面所谓的难题也就不在话下。

建议小伙伴第一遍刷题可以使用兔系法。

看懂题目

万事开头难,看懂题目是做好一道算法题最开始也是最重要的一步。

我将 LeetCode 上的题大致分为三种类型:

?考察数据结构,比如链表、栈、队列、哈希表、图、Trie、二叉树等

?考察基础算法,比如深度优先、广度优先、二分查找、递归等

?考察基本算法思想:递归、分治、回溯搜索、贪心、动态规划等

一些算法题目会在标题或题目描述中给出明确的题目类型信息,比如二叉树的重建、链表的反转。

而有一些题目中则在条件中给予暗示 :

?设计一个 O(nlogn) 的算法(分治:在一颗搜索树中完成任务,对于数据排序)?给定一个有序数组(二分法)?无需考虑额外的空间(用空间换时间上的优化)?数据规模大概是 10000(O(n^2)就可以)?问题可以被递归解决(动态规划)

无论怎样,当你拿到一道算法题的时候,希望你能先去弄明白这道题目要考察的是什么,是简单的数据结构还是复杂的算法思想。

先去理清题目背后解法要用的技术,这样,这道算法题目才有做下去的可能。

不要忽视暴力解法

一般来说,BAT 等大厂的算法面试题基本上都是 Medium 级别及以下,并希望面试者能在 20 分钟以内给出一个「相对正确」的回答。

为什么说是 相对正确

每一道算法题得解法都有很多种,并不是说你没有给出完美解或者最优解你就是错的。

“正确” 本身是一个相对概念。

在算法面试或者平时的算法练习时,如果没有头绪,可以尝试使用暴力解法。

(不要忽视暴力解法。暴力解法通常是思考的起点。)

当你使用了暴力解法之后,可以与面试官进行沟通优化,把这个过程看作是和面试官一起探讨一个问题的解决方案的过程,这也可以让面试官了解你的思考问题的方式。这也是一个“正确”的回答方式。

先实现功能再去优化。

Done is better than perfect



实际编写

到这一步就是算法的落地了:将上面的思考结果思路转换为代码。

在编写的过程中需要注意题目中的边界条件,比如数组是否为空,指针是否为 NULL;同时也要注意代码的规范性:变量名,模块化,复用性。

做好总结[1]

一定要做好总结,特别是当没有解出题来,没有思路的时候,一定要通过结束阶段的总结来反思犯了什么错误。解出来了也一定要总结题目的特点,题目中哪些要素是解出该题的关键。不做总结的话,花掉的时间所得到的收获通常只有 50% 左右。

在题目完成后,要特别注意总结此题最后是归纳到哪种类型中,它在这种类型中的独特之处是什么。经过总结,这样题目才会变成你在此问题域中的积累。

做好总结,让每道题都有最大的收获。一个月之后自己的状态应该会有很大变化。

最后,承认刷 LeetCode 很吃力很正常

你我都是普通的程序员,不像那些玩 ACM,拳打 LeetCode,脚踩剑指 offer,我们得接受现实:刷题,就是很痛苦很打击的过程。

但,一遍一遍的刷,多刷一题就多掌握一题,你总会比别人更强一点。

大家一起加油:)


我按标签用动画整理了一下 LeetCode 的题目,可以按需查看。

链表算法面试问题?看我就够了!几道和「二叉树」有关的算法面试题几道和散列(哈希)表有关的面试题几道和「堆栈、队列」有关的面试算法题有点难度,几道和「滑动窗口」有关的算法面试题几道和「黑洞照片」那种海量数据有关的算法问题几道 BAT 算法面试中经常问的「字符串」问题

我的专栏:

和程序员小吴一起学算法


?? 看完三件事:

如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个忙:

  1. 点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-
  2. 关注我和专栏,让我们成为长期关系
  3. 关注公众号「五分钟学算法」,第一时间阅读最新的算法文章,公众号后台回复 1024 送你 50 本 算法编程书籍。

lz在加拿大。

先贴一个自己的刷题的进度吧:

到目前为止,一共刷了428题。

通过刷题,拿了很多公司(IBM, Google, Amazon, Microsoft, Zenefits, Splunk)的面试以及offer。这428题不是简单的刷一遍就过去的,而是反复练习,直到代码最优,解法最优(有时候甚至觉得自己的代码精简到一个符号都无法减少的地步)。所以有时候面试官问问题,问题还没说完,我就知道应该如何表述自己的心路历程,然后慢慢地给出最优解。


而这一切的关键就在于:做笔记!

下面是我的笔记截图:

对于遇到的每个题目,事后我都做上标记:普通题目,难题、好题。此外,每个题目都分为以下几个步骤做好详细的笔记:

1. 原题目

2. 自己的第一遍解法

3. 网上好的解法

4. 自己可以改进的地方

5. 进一步精简优化自己的代码直至代码简无可简(这是非常关键的一步,到达这一步,才会发现获得能力的提升远远要超过简单地把题目解出来

6. 获得的思考(或者学习到的地方,可以是算法、数据结构或者Java的特性—例如Stream等等)


每一个题目都经过至少一遍这样的迭代。这样几遍下来,我对于每个题目都有了更加深刻的理解,大部分的题目我都有自信能够写出最优解甚至代码都是最优化的(至少比论坛回复里面的最高票答案还要精简)。


举个例子,Two Sum问题。

我最早的解法是暴力搜索。当时的代码(C++)是这样的:

class Solution {
public:
  vector twoSum(vector &numbers, int target) {
    // Start typing your C/C++ solution below
    // DO NOT write int main() function
    vector index(2, 0);
    if (numbers.empty() || numbers.size() == 1)
      return index;
    
    for (int i = 0; i < numbers.size()-1; ++i) {
      // j should start from i+1
      for (int j = i+1; j < numbers.size(); ++j) {
        if (numbers[i] + numbers[j] == target) {
          index.clear();
          index.push_back(i+1);
          index.push_back(j+1);
          break;
        }
      }
    }
    return index;
  }
}

这个解法不仅复杂度高,而且代码冗长繁琐。


后来看了网上高票答案的解法,知道了用hashmap来做,于是写出了优化的代码(Java):

public int[] twoSum(int[] nums, int target) {
    Map map = new HashMap<>();?
    int[] result = {-1, -1};??
    for (int i = 0; i < nums.length; ++i) {?
        if (map.containsKey(target - nums[i])) {?  
            result[0] = map.get(target - nums[i]);?
            result[1] = i;?
            break;?
        }??
        map.put(nums[i], i);?
    }??
    return result;?
}

再后来,对代码进行了一些细节的简化:

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map map = new HashMap();
        
        for (int i = 0; i < nums.length; ++i) {
            if (map.containsKey(target- nums[i])) {
                return new int[]{map.get(target- nums[i]), i};
            }
            map.put(nums[i], i);
        }
        return int[]{-1, -1};
    }
}

至此,代码几乎达到最精简状态。(中间有略去几次迭代)总之,不断地学习别人的代码,改进自己的代码,不断地锤炼自己的代码,直至算法最优化,代码最简洁!潜移默化中,不仅对题目解法有了更深刻的理解(什么是最优解),而且也知道如何用最简洁的代码实现这个最优解。

再举个极端的例子吧,179. Largest Number,这个题目我最后精简成的代码如下:

public String largestNumber(int[] nums) {?
    return Arrays.stream(nums)?
    .mapToObj(String::valueOf)?
    .sorted((s1, s2) -> (s2 + s1).compareTo(s1 + s2))?
    .reduce((s1, s2) -> s1.equals("0") ? s2 : s1 + s2).get();?
}

我本人不是算法高手,算是勤能补拙类型。这样长期坚持下来,慢慢地感觉自己编程能力提升了很多。不仅面试的时候得心应手,而且在工作中提交code review的时候,往往有自信说自己的代码是简单,干净与优雅的。

力扣君认真看了大家关于这个问题的回答, 不仅感叹小伙伴刷题热情之高以及脑洞之大。

力扣尤其对高票答案中胖君的兔系龟系刷题流派影响深刻, 龟系法注重把题目做干净, 每道题不断改进, 追求最完美的解法. 而兔系注重刷题的速度, 看似囫囵吞枣, 实则奥妙无比. 这两种方法都不失为刷题的好方法。

许多小伙伴也曾经在我们后台分享了他们独特且有效的刷题方法, 下面我们总结了一些刷力扣不错的方法。

刷题队列法和刷题栈大法

建立一个题目队列, 先把力扣一些比较好的题目push进队列里, 然后平常有空的话, 就将队列头的题目pop出来, 然后就做这一道题, 如果这一道题做不出来或者做得出来但感觉不太熟练就重新push回去队列. 如果成功做出这道题, 就寻找一些相关类似题目push进队列里。

不断重复这个过程, 假以时日, 一个力扣大佬就会诞生了. 这个方法好在哪里呢? 好在题目只要曾经进入过队列, 就一定会被刷到, 不熟悉的题目会被刷到熟悉为止, 而且刷题的范围就像树木的枝叶一样, 不断延伸开来. 说不定, 刷题队列法也能加深你对队列的理解程度呢。

同理, 刷题栈法也是类似, 不过与队列法有些许区别. 这么说吧, 队列法注重刷题的范围, 而刷题栈基本上则会一个类型(tag)刷到底, 小伙伴有没有联想到什么?

将力扣融入生活大法

每天起床第一眼, 先看一道力扣题。

刷力扣的最高境界, 就是将力扣融入生活, 遇到一道很难很难的力扣题, 不急着看题解, 而是把题目记下来, 有空的时候就想一下. 比如等车时候想一下, 做地铁的时候想一下, 虽然有时候会想好几天, 但灵光一闪, 顿悟出答案来那种畅快感, 我相信体验过的小伙伴都懂。

以赛代练大法

力扣(LeetCode)每周日都会举行力扣周赛, 题目水准高且难度具有阶梯型, 全球玩家同步进行, 其中不乏一些全球知名的程序员参加, 非常有挑战性。

而且力扣还有虚拟竞赛功能, 可以模拟一场历史比赛来进行训练, 用比赛促进刷题, 也不失为一种好方法。

如果你想体验紧张刺激的做题过程, 或者想模拟一下真实面试时的环境, 不妨这个周日就来体验一下我们的竞赛哦, 偷偷说一句, 周赛名列前茅的同学能获得大量LeetCoin, LeetCoin可以换取精美的LeetCode周边哦。

最后

力扣在探索板块中新上线了一个很有用的的卡片

探索算法面试题汇总 - 力扣 (LeetCode)

这个“面试高频题”卡片汇总了大部分面试中常见的算法题, 如果小伙伴想在最近的春招拿到心仪的Offer, 不妨来尝试一下, 说不定可能会刷到下次面试的题目哦!

除此之外,力扣君在之前的文章中也分享过不少如何有效刷力扣的方法,感兴趣的同学也可以戳以下链接直达。

LeetCode按照怎样的顺序来刷题比较好?刷 LeetCode 吃力正常吗?怎么很快的上手leetcode,先做简单的题目吗?

自己日常刷题经过是这样的:

  1. 拿到题目,看一眼Difficulty,然后自己思考一下解题思路。如果解不出来,就记下在哪里卡住了,难点在哪。
  2. 如果对应的题目有Solution,就看Solution,没有的话就点Discuss,按Most Votes排序,看排名最高的解法。
  3. 对比一下自己的解法与最优的解法的差别,总结一下为什么没想起来,记录下来这个思考的过程。
  4. 关掉别人的代码,开始Coding,Debug,Submit。

附上自己总结的几条经验:

  • 先刷两个Top专题。Leetcode 上有个List选项,里边有两个专题,分别是Top 100 Liked QuestionsTop Interview Questions。这两个List中有很多重复的题,加起来一共150道左右。都是经典的题目,将这150道刷完基本上所有的题型都见过了,而且多数经典题目都会涉及,是提升最快的一个方法。
  • 注意记录、总结与复习。自己写过的代码一定要保存下来,刷题的时候也要记下主要思路和注意点,这样在复习的时候也能对比发现自己哪里还能改进,之前犯得错误有没有重犯。可以将相互关联的题目对比着一起看,方便总结与记忆。一定要时常复习刷过的题,复习比一味的追求数量更重要。
  • 做好Easy,没必要死扣Hard。LeetCode上很多Easy的题目看似简单,实则想要写出Perfect的代码并非易事。多思考如何优化Easy,Medium的解法实际上比花精力解Hard题更能提高自己。况且面试的时候Hard被问的概率太小了。
  • 切忌眼高手低。不要想着自己知道思路解法了就是会了,一定要亲自Coding,手撸出来。我在刷的过程中就经常在Debug的时候才发现自己忘记考虑了某些条件。不把代码写出来,只看别人的答案对自己是没有多大的提高的,只有亲自AC了题目,才能算做过一道题。

最后附上我的刷题仓库,欢迎Start https://github.com/mJackie/leetcode

给大家分享一个GitHub上关于LeetCode的攻略~

GitHub上有个叫lucifer的中国小哥哥,将Leetcode题库中数百道题目的解题过程全盘分享,解题思路和代码都有。

民间曾一度流传,leetcode上,基本就是互联网大厂拿来应聘面试者的考题了。

来看看。

比课后答案详细

打开这套资源,首先你会发现它是份纯中文的攻略,语言友好度分。

内容共分为四部分:

一是leetcode经典题目的解析,包括思路、关键点和具体的代码实现。

二是对于数据结构与算法的总结

三是anki卡片, 将leetcode题目按照一定的方式记录在anki中,方便记忆

四是计划, 这里会记录将来要加入到以上三个部分内容

目前,小哥哥表示,目前一二部分还在陆续更新,三四部分还在计划中。

经典题目解析是重头戏,小哥哥的介绍得非常详细。

leetcode上的题目有数百道,小哥将其分为了简单、中等、困难三种难度,估摸着自己水平后,你可以直接选择最适合自己的题目,最大化利用学习时间。

每一道题都有对应的编号,戳进后呈现方式直白清晰明了。

比如在第20题“有效括号”中,作者先放上了leetcode里的题目地址,贴上了题干的描述:

这道题在“简单”难度行列,主要是判断在各种情况下字符串是否有效。小哥哥先提示了这道题的解题思路,认为应该就字符串为左半边还是右半边有括号进行分类讨论:

还推荐了邓俊辉老师此前讲解类似问题的答疑视频。

给出了动图方便进一步理解:

思路讲解过后,如果你还是不太明白,可以看看下面小哥哥提示的关键点分析

最后,小哥哥放出了自己的答案,附上了自己的代码:

到此,这道题就算解得差不多了,这看起来课后习题上的参考答案丰富多了~

还没完,如果你想在此题的基础上继续深究下去,还可以看看小哥哥给出最后的扩展建议

在数据结构与算法总结部分,小哥哥目前介绍了五个知识点,分别为数据结构、二叉树的遍历、动态规划、哈夫曼编码和游程编码和布隆过滤器。

每一个知识点的介绍篇幅不长,图文并茂。

和其他的知识点介绍资料不同,在介绍这几个知识点时,小哥哥用题库中的具体例子进行了分析:

剩下的题目,差不多也是以这种方式介绍的。通过一道题,让你把整个知识点完全吃透。

学完这套题,大厂离你就更近一步了。

传送门

想get这套解题思路,可前往Github上的原帖:

https://github.com/azl397985856/leetcode

此前,GitHub上还有一个用动画的形式呈现解LeetCode题目思路的资源,现在已经快2万星了。

一并推荐给大家:

https://github.com/MisterBooo/LeetCodeAnimation


量子位 · QbitAI
?'?' ? 追踪AI技术和产品新动态

量子位

欢迎大家关注我们,以及订阅我们的知乎专栏

一个普通小程序员,现在大概刷了三百多道题了吧。这个水平应该也不算高。断断续续的刷的,主要看忙不忙,说实话,让我回头再去看前面的题,我也不一定能做出来,所以我这个应该不是什么好的方法,只是给大家一个普通的参照而已。

之前没有太多算法的概念,刷这些题着实花了大量的时间和精力。

我是从前往后按顺序一题一题刷的,当然充值才能看的跳过了, 。先是自己思考,动手做,这一步花了很多冤枉时间,因为本身头比较铁,即使做不出来的题,也要想很久,最怕的就是那种有点思路,不过思路是错的,真的是花大把的时间去试了。然后,不管自己写没写出来解法,再去看题解、讨论区,或者网上大神的解法。所有的不同算法,或者算法差不多,有这些巧妙用法的代码,都搞懂,然后自己再逐个写一遍。

大概就是这样,磕绊着刷了这些题。到现在的话,明显的提升就是解题思路,从前大部分中等难度的都做不出来,现在大部分都能做出来了,而且很多情况,解法都能跟标准解法之一相同。然后,对于算法复杂度的概念也有了很多提高,几乎不会再考虑暴力求解的解法,什么样的解法更好,复杂度更低,也能更清楚了。

自我感觉的一个问题,就是做的总结不够,很多时候,看了半天讨论区的代码,然后,又费力写了四五种解法的代码之后。就疲于再去做总结了。

还有就是对所谓算法和数据结构本身的了解还不够,可以说是基础比较薄弱,相信这个时候看一本算法导论之类的书,能够获得很多收获。这个问题导致的是,在动态规划,搜索树之类的经典的算法和数据结构的应用上总是翻跟头,即使做过了这么多同类型的,还是要翻。还有一些应用比较高阶的数据结构的算法,只能做到知其然,知其所以然就很难了。

刚好利用这个机会给自己也做个总结,希望对题主或者看到的朋友有些帮助吧

7月10日更新。

最近发现自己的进度已经过半了,所以按约更新刷题经验。

除了之前分享的经验外,我认为还有几点比较重要:

  1. 总结题目的套路。拿到题目后,可以快速分析出题目的类型。回忆到之前做过类似的题目,尝试用同样的套路解决。
  2. 讲解交流的能力。我们刷题的最终目的是为了准备面试。面试过程中,除了快速写出bug-free的代码外,与面试官之间的交流也尤其重要。思路清晰时,准确向对方表达出自己的想法。没有思路时,尝试从面试官那里获得一定的提示。如果有志于外企的话,用英文表达计算机术语和算法也是一定要练习的。我的做法是,做题的时候精品照LeetCode的Solution写出自己的思路。如果觉得自己写的还不错的话,可以发个discuss表现一下。不过以我的经验来看,除了新题的discuss会被人看外,老题的基本上无人问津。
  3. 根据数据规模一步一步优化算法的能力。Leet Code的题目大多会给出输入的数据规模,我们可以根据这个估计所需算法的时间复杂度。一般情况下,10的6次方 是可以过的。比如,输入的规模是10^3, 那么解答的复杂度必须是n^2以内的才行。

谢邀。

既然题目是分享自己的刷题经验,虽然我的经验可能比不上高赞答案全面,但是可能对和我有类似背景和需求的同学有所帮助。

首先展示一下自己的刷题进度

接下来,介绍下自己的背景和需求。

背景:我本硕都是计算机专业,算是典型的科班出身的程序员。所以基本的数据结构和算法,编程语言还是有一定基础的。大四时先后在一家 创业公司 和 快手的推荐系统组 实习过,有一定的工程经验。预计21年毕业,找工作面试集中于20年的春夏,找实习集中于19年的冬天和20年的春天。所以距离最近的挑战只有半年时间可以利用,Google 20年summer intern的面试今年12月份就开始了。
需求:首先找一个20年暑期的实习,再利用实习的经历转正 和 寻求全职的工作。岗位的话,目标是 外企的SDE,坐标北京。梦想公司是 Google,微软。

刷了半年题,还没到一半。
由于每天时间有限,基本上没有其他due的话,上午会安排3个小时刷题,还有一些水课也是我的刷题时间。另外每周日的上午会参加Weekly contest。参加contest有很多好处:

  1. 1个半小时内完成4题,限时且有竞争;
  2. 每次比赛会有排名,可以通过排名 或 Contest Rating看到自己一直以来的进步。有比较强的正反馈。
  3. 题目是最新的。所以讨论区相对比较活跃,回复也比较及时。

我刷题的大顺序是由易到难,按Acceptance Difficulty。我认为我的时间是充足的,由易到难的话容易形成正反馈,获得源源不断的动力。每天刷的题目最好是同一类型或者是前后相关的,这样可以有针对性的练习,形成更深的记忆。

一个很重要的经验是,刷题最好有伙伴。我本科舍友是打ACM的,ICPC world final排名14。虽然他可能看不上LeetCode的题目,但为人很好,如果问他一些刷题经验的话,他也会倾囊相助。比如,他会告诉我 Kick start的话,Round D和E比较重要(中国区比较看这2轮),前面的可以当作练手。实验室的同学在我的带动下也逐渐开始刷题了。不过比较积极的只有一个,我平时会和他交流一些题目和进度。这样有 peer pressure也会更有动力,不是坏事。

刷到400题后,发现自己进入了瓶颈期,简单的题都刷完了,没刷的题比较难。基本上一道题要半个小时,有时还必需借助题解。不过也有好处,确实可以感觉到,瓶颈期的进步还是可见的,每道题都能学到新的东西。

除了刷LeetCode外,我还会每月参加Google的Kick start比赛。Kick start难度略高于LeetCode,每次3小时3题,难度大于相当于LeetCode的Medium, Hard, Hard+。Google算是我的梦想公司,参加Kick Start主要是为了拿到Google的面试机会。

另一个经验是,最好有自己的一门比较精通的主语言,用来刷题。面试时如果有一门主语言的话,也更有竞争力。我除了刷题,最近也再学习一些语言的知识。从今年元旦开始,先后看了C++ Primer, Effective Modern C++, Effective C++, More Effective C++, C++ Concurrency in Action, C++ 标准库。主要是在商汤实习的工程需要,顺便也帮助了刷题。其实,学习语言的过程中,也是学习数据结构与算法的一个很好途径。比如C++的话,STL中实现了很多经典的算法,通过使用和阅读源码,可以更好地学习算法。比如lower_bound中用到的二分搜索,map中用到的红黑树,sort中实现的排序算法...
说到刷题用的语言,我经历了 Python->Java->C++的转变。去年暑假第一次开始刷题时,选用Python。主要是因为Python相对比较简单,好上手。从大一学会开始用了4年了,而且平时写脚本也比较多。9月份开学后,转投Java阵营。当时的理由是,Java岗位需求最大,找工作更好找,也是LeetCode的首席语言。不过由于不熟悉Java,去年的后半年其实是Python和Java并存的。而且因为去文远知行实习,去年后半年刷题量并不多。从今年1月开始,正式转投C++了。由于有C语言基础,我向来是对C++很亲近的。今年由于商汤的实习需要,正式夯实了C++基础,也有了很强的C++工程经历,所以C++是我的主语言了。刷题也顺带用C++刷了。事实上,大多数题目都是我今年才刷的,也就是用C++刷的。

暂时想到的就这么多,等我刷够一半时,我再来补充一些新的经验。

感觉最重要的是没有时间吧,所以我买了一个K480的键盘,然后在山寨平板上安装了LinuxDeploy,这样就可以随时刷题,地铁里也没问题了。

2019.8.17更新

  • 不要沉迷于技巧

编程世界里琐碎零散的技巧数不胜数,做为求职刷题者时间紧迫,最需要掌握的是通法。

###############################################################

有人说算法导论很好很好,我认真读过1/3吧还做了笔记。然而算法导论更像是证明为主,比如为什么快排是正确的,Ford-Fulkerson为什么可以找到最大流。

Leetcode呢,则是应用这些基本算法解决一些问题。对于这些基本算法基本不考察你裸写,所以如果试图学通算法导论来掌握Leetcode是效益很低的(当然可以培养你的编程素养).

Leetcode的一个显著特点是套路性强,例如双指针系列([1][2])的题目出现了很多次。套路对于高手来说,如果不准备也可能会栽跟头的。所以最好的操作就是针对这些套路进行“5年高考三年模拟"。

互联网上有很多对Leetcode一类题型的的总结(比如[3]),这种文章应该是你准备的重点。题目往往不是凭空产生,而是基于某种套路量产而来,一题一题刷本身是很低效的行为。你应该基于某种题型,跳跃着选题。

Chrome有个插件叫Tampermoney,可以执行用户脚本,我修改了一下别人的脚本[4],原来的脚本是可以直接在网页里搜Python, Java的解答,或者是Google一键搜索, 我把搜索Java换成了搜C++答案。

效果如图

脚本代码:

https://gist.github.com/zjplab/ab5ffdccbfee53b5e2f47390776cde05

当然是用 VS Code 刷啦! 刷题体验如丝般顺滑~

neo-cs:LeetCode for VS Code: 春招 Offer 收割利器

而且还能在 VS Code 里面直接调试,轻松惬意。

neo-cs:如何在 VS Code 中调试 LeetCode 代码

这个 LeetCode for VS Code 插件,就是坐在离我不远(嗯,不到五米)的微软同事写的。真是造福人类啊!

作为 LeetCode 的铁粉并受益的刷题人,我认为掌握一套高效的刷题方法尤其有效,否则很难覆盖日益增多的题库,并且大多数时候刷完不久就会忘掉。所以我把当年刷题的经验分享给你,希望我的方法也对你有用,希望我们能做同事。

我方法的核心实际上和背英语单词类似(详见英语相关的总结 如何正确的从零开始学英语?),总结题型,找到高频题并且不断重复。具体来讲就是

  • 按 tag 分类
  • 艾宾浩斯记忆曲线,不断重复刷过的题
  • 不断总结掌握情况

为什么这么来操作是因为经过很多面试后,发现大多数题型还是比较基本和重要的,分布在 medium 和 advanced medium 之间。而这些题目又可以演变出来很多不同的题,但万变不离其宗,抓住本质并且熟练掌握即可。

1 按 tag 分类

第一件事就是按照 tag 把题目分成不同的 list,一般每个公司为一个 list。一定要根据自己的刷题掌握情况来定制 list,这也是我这个方法保证对你有用的精髓。随便从其他地方的舶来品基本没用,因为只有自己才最了解自己的复习情况。如果你基础比较差,之前没怎么刷过题或者是转专业,我推荐的做法是额外分一个 basic list,意思是所有基础的数据结构/算法都覆盖一遍,这些题是一定要会的,基础中的基础。我把我认为基础的 list 需要 cover 的内容分享在这里(后面是题号):

  • DFS + memo 322
  • Backtracking 22
  • DP (DP <--> DFS + memo) 55
  • BFS 286
  • Partition 86
  • Greedy 421
  • Sliding Window 15
  • Divide and Conquer
  • Graph 207 743
  • Tree
  • Binary Search

这个基础的 list 基本上一定要涵盖这些基础知识点(面试必考)。

2 艾宾浩斯记忆曲线,不断重复刷过的题

第二步就是著名的艾宾浩斯记忆曲线的运用了。考过托福/雅思的细心的同学可能发现了,这个实际上和记忆英语单词有异曲同工之处 -- 先做 list,第二步我们要干嘛?按 list 不断复习,每天循环呀!这里我用我的 Basic List 来举个例子:

请注意观察我的 Legend

一般表格的第一栏是留给 Legend 的,每次刷完我会记录当前的状态,方便日后巩固。

如果是一次过的:就是直接 y;

如果中途有停顿,而且思路也不清晰的,写 ?;

如果怎么想也做不出来,看了答案的或做之前看过答案,就是 ※。

然后根据这些记录的情况,第二天来安排不同的优先级和精力重新刷这些题,大家可以看到 168 我打了三个 ※,说明 3 次都不会,日后还需要继续巩固此类题型。对于那些 y 的题目直接过,基本上半年再来 review 一次。

3 不断总结掌握情况

最后一步也是最重要的一步:总结。我们需要随时记录下当前刷题的状态,然后每天在刷题时做到有的放矢:不浪费每一道新题,不重复任何一道已掌握的旧题。具体操作如下:

那么问题来了,大家猜猜这是哪家公司的 List?

总结需要注意的关键点:

  • 总结 tag -- 这题我有哪些方法,哪个是最优解
  • 总结笔记 -- 有必要的话需要记下来哪里有这题的笔记
  • 总结相似题型
  • 总结关键解题步骤

总结 tag 大致意思是说:这题大概有哪些方法可以搞定,以及自己最喜欢的方法。一般推荐两种方法即可:基本的 brute force + advanced algorithm / data structure。注意这两个都是必要的,我有经历过背下来高级解法,结果基本解法不熟练最后被挂掉的面试。大家可能要问:看讨论区那些 ACM 大神们的奇技淫巧太 NB 了,我是不是要全背下来?我的建议是大可不必,记住一个自己最顺手的即可。而且注意:brute force 一定要熟练,在这个基础之上才能开始研究高级一些的解法。

总结笔记,很多的题做了好多遍也不太会,例如我上面的 31,感觉要刷死人了还是不会。那没有办法,我只能把这个解法单独拿出来,写到纸质的笔记本上,有空就看一遍,推一遍,敲一遍。

总结类似题型,这个也很有用,因为往往类似题型都有一致的解法,只是越往难,越是在基础解法上糅合了其他的算法技巧。有时候 LeetCode 上给的类似题型不准,我一般是参考之后再看看大家的建议,然后把所有的先总结出来,并且把相似的题链接起来。每次练习一起练,找出每种题型的基本差异。例如经典的买股票四连问题,建议大家试试看。

总结关键解题步骤。这一点很有意思,主要是说在遇到难题时,看完大神的解法之后自己总结出几点关键步骤,这样下次要是再卡壳了就可以直接看这个,想想之前自己是怎么解的思路,而不是再去看其他讨论。这样循环往复个 2-3 次就能熟练记下来。例如 42 那题,我就写了一个简单的小提示,确保下次再卡壳可以看这个 tips 而不是翻看答案,从头再来推一边。从而提高刷题效率。


按照这个方法不断练习,我保证你最差可以刷进 flag,因为不管是从以前别人面试我的经历还是现在我面试别人的经历来看,大家最看重的其实还是基础算法知识是否牢固,即 medium 和 advanced medium 能否够对答入流。

至于那些脑经急转弯式的 easy 和有很多高级技巧的 hard,实际上我个人感觉不是主要的考察范围。除非是 ACM 参赛者,对于一般的 candidate 编程实际上就是一份工作,既然是这样,那就找到合适的方法来应对。把更多的时间花在更宝贵的事情上,例如你喜欢的人和物上。

祝你刷题快乐,刷好了记得告诉我,来找我内推。

之前刷够 100 题的时候总结了一下,贴到这里分享下。

leetcode 100 斩!从第 1 题开始,到现在也差不多快一年了,回顾纪念一下。

为什么开始刷题?

从大一就知道了 leetcode,但刷题总是三天打鱼,两天晒网,会发现刷过的题,隔一段时间再看还是需要很久才能再想起来,于是就萌发了刷一题总结一题的想法。

另一方面,leetcode 上的 discuss 里一些解,有时候讲解的很少,甚至只丢一些代码,对于我等这种菜鸟有时候看的太废劲了,所以不如自己把各种解法都理清楚,然后详细的总结出来,也方便其他人更好的理解。

刚开始的感觉

大一的时候,听过 ACM,然后暑假也去学校的 ACM 集训试了试,但当时基础太差了,栈和队列都不知道是什么,所以也就没有走上 ACM 的道路。之后就各种学安卓、web、后端的应用开发的一些东西了。后来准备开始刷题是大四毕业的时候了吧。

当时对回溯、动态规划也都只是上课的时候学过,也并不熟练。开始几题的时候,也都很慢,很多都自己想不出来。然后就去看别人的题解。看完以后,就什么都不看,然后按自己的思路再写一遍代码。

尤其是第 5 题,求最长回文序列,现在都印象深刻,记得当时用了好几天才把所有解法总结了出来。

所以大家如果想刷题的话,也不用怕自己基础不好,大不了哪些名词不会就去查,一点点积累就可以,重要的是开始坚持

现在的感觉

从开始可能只是觉得该刷一刷题,到现在可能真的是爱上了刷题。

现在刷题基本可以想出一种思路,有时候甚至和最优解想到了一起,还会想出一些别人没有想到的解法,这种成就感可能就是打游戏超神的感觉吧,哈哈。

此外,看 discuss 的时候,每当看到令人拍案称奇的思路的时候,真的是让人心旷神怡,开心的不得了,就像中了彩票一样的开心,赶快去和同学分享。

有时候也会看到一些让人捧腹的评论,题目是输入一个字符串,输出所有可能的 ip 地址。

Input: "25525511135"  
Output: ["255.255.11.135","255.255.111.35"]


刷题的收获

在总结的过程中,因为力求给他人讲懂,在理清思路的动机的过程中,会发现之前的想法可能是错的,会总结着总结着就明白了另一种解法,或者产生新的想法,或者明白各个解法相互之间的联系,会比仅仅 AC 多出很多收获。

从理清他人的想法,再到自己写出代码,再到把各个解法用自己的理解串起来,会有一种「纸上得来终觉浅,绝知此事要躬行」的感觉。有时候虽然大的框架有了,但是小的细节方面还是需要自己去体会。为什么加这个 if?为什么是小于等于?每一句代码的产生都是有原因的,绝不会是可有可无的代码。

所以虽然一道题从看题,理解,自己考虑,看别人解法,到重新实现,再到总结出来,可能需要 3、4 个小时,甚至 5、6 个小时或者更多,但我觉得是值得的。

此外,也有很多人加自己的微信过来亦或是感谢自己,亦或是指出错误,亦或是询问问题,亦或是没说过话的,哈哈。有微软、谷歌、百度、阿里、腾讯的大佬,有各个大学的学生,甚至巧的是还能加上高中的校友,世界真小,哈哈。


上边是最近加的一些人,每次收到别人的称赞自己也会很开心。此外,博客是直接放在 github 上的,目前也有 450 stars 了,是自己 github 上 start 数最多的项目了,说来也惭愧,希望以后自己努力可以有一个好的开源项目。

刷题的理解

一些人可能会纠结用什么语言去刷,其实没必要纠结的。刷题需要考虑的是算法,而不是语言。算法就像是从家里到超市该怎么走?出门左拐,右拐直走....而语言是我们选择的交通工具,骑车?步行?开车?平衡车?每种交通工具都有自己的优点和缺点,语言也是如此。而好的算法可能更像是,我们偶然发现了一条近路,降低了我们的时间复杂度或者是空间复杂度。

刷了 100 道题了,我觉得必须要掌握的就是递归的思想了,利用这个思想可以解大部分的题了。计算机擅长的就是记忆以及速度,而递归可以把这两个优势发挥到极致。遇到问题以后,我们可以考虑如何把大问题分解成小问题,想出来以后,代码很容易就出来了。

此外,一些递归可以用动态规划的思想改写,从而优化递归压栈所消耗的时间,递归是顶部到底部再回到顶部,而动态规划通过存储,直接从底部到顶部解决问题。

最经典的例子就是斐波那契数列了,求第 n 项数列的值。

斐波那契数列,指的是这样一个数列:1、1、2、3、5、8、13、21、34 …… 在数学上,斐波纳契数列定义如下:F ( 0 ) = 0,F ( 1 ) = 1 , F ( n ) = F ( n - 1 ) + F ( n - 2 )(n >= 2,n ∈ N*);

如果用递归的思想去写,代码简洁而优雅。

long Fibonacci(int n){
   if (n == 0)
        return 0;
   else if (n == 1)
        return 1;
   else
       return Fibonacci(n-1) + Fibonacci(n-2);
}

当然,这样的话太慢了,优化的话,就是把递归过程的结果保存起来,或者就是改写成动态规划,最强的是其实是有一个公式的,直接利用公式就可以。

此外,还有一些题目就是根据题目的理解去写代码了,没有什么特殊的技巧。

未来的打算

当然是继续刷下去了,很开心,每天不刷一刷题会不习惯的,希望大家也早日感受到刷题的乐趣,哈哈。

在线地址:https://leetcode.wang,域名也比较好记,希望对大家会有帮助。

我是用 gitbook 搭建的,我觉得上边「搜索」的插件很好用,可以直接根据关键字搜出来自己想做的题。

知乎专栏也会同步更新:https://zhuanlan.zhihu.com/leetcode1024。

越努力,越幸运,共勉。

责任编辑:
热门阅读排行
© 16货源网 1064879863