刷了一个月leetcode算法,成功收下阿里巴巴、网易等大厂的offer

前言
有人调侃我们说:
这些其实都是初级程序员面临的困境,当你提高自身能力,登上更高的层级之后,无论薪资还是发展都会有很大的提升 。
那么问题来了,怎么才能度过初级程序员的瓶颈,进阶成为高薪工程师呢?
随着互联网寒潮的到来, 越来越多的互联网公司提高了面试的难度,其中之一就是加大了面试当中手撕算法题的比例 。这里说的算法题不是深度学习,机器学习这类的算法,而是排序 , 广度优先 , 动态规划这类既考核数据结构也考核编程能力的题目 。刷题的网址非常的多,其中以是最为出名的 。
在刷题上 , 我花了大量的时间,蹚了许多的坑,总结了一下,主要有这三个问题:
刷过的题老是忘 , 第二次刷的时候还是不会做刷题的速度很慢,即使花一天时间 , 也常常只能刷五六道坚持不下来,老是刷到一半就停滞下来了 , 当我第二次再来刷的时候,前面刷过的题都又忘的差不多
说出来都是泪 , 感觉刷题这个路是真的难走 , 花了很多时间,但是感觉没有什么收获 。所以最近我一直在反思自己刷题的方法,希望能够提高刷题的效率和速度 。当我总结了以下方法以后,我很明显的感受到自己的刷题速度从以前周末的一天五六道提升到周末一天刷十五六道以上,速度相比以前提升的非常明显 。
本文采用Java语言来进行描述 , 帮大家好好梳理一下数据结构与算法,在工作和面试中用的上 。亦即总结常见的的数据结构,以及在Java中相应的实现方法,务求理论与实践一步总结到位 。
常用数据结构
【刷了一个月leetcode算法,成功收下阿里巴巴、网易等大厂的offer】数组
数组是相同数据类型的元素按一定顺序排列的集合,是一块连续的内存空间 。数组的优点是:get和set操作时间上都是O(1)的;缺点是:add和操作时间上都是O(N)的 。
Java中,Array就是数组,此外,使用了数组Array作为其实现基础,它和一般的Array相比,最大的好处是 , 我们在添加元素时不必考虑越界,元素超出数组容量时,它会自动扩张保证容量 。
和相比,主要差别就在于多了一个线程安全性 , 但是效率比较低下 。如今java.util.包提供了许多线程安全的集合类(比如 ),所以不必再使用了 。
链表
链表是一种非连续、非顺序的结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 , 链表由一系列结点组成 。链表的优点是:add和操作时间上都是O(1)的;缺点是:get和set操作时间上都是O(N)的,而且需要额外的空间存储指向其他数据地址的项 。
查找操作对于未排序的数组和链表时间上都是O(N) 。
队列
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作,亦即所谓的先进先出(FIFO) 。
Java中,实现了Deque,可以做为双向队列(自然也可以用作单向队列) 。另外实现了带优先级的队列,亦即队列的每一个元素都有优先级 , 且元素按照优先级排序 。

栈(stack)又名堆栈,它是一种运算受限的线性表 。其限制是仅允许在表的一端进行插入和删除运算 。这一端被称为栈顶,相对地,把另一端称为栈底 。它体现了后进先出(LIFO)的特点 。
Java中,Stack实现了这种特性,但是Stack也继承了,所以具有线程安全线和效率低下两个特性 , 最新的JDK8中,推荐用Deque来实现栈 。
集合
集合是指具有某种特定性质的具体的或抽象的对象汇总成的集体,这些对象称为该集合的元素,其主要特性是元素不可重复 。
在Java中 ,  体现了这种数据结构,而是在的基础上构建的 。继承了 , 使用确定在集合中的位置,使用链表的方式确定位置,所以有顺序 。实现了 接口,是排好序的集合(在 基础之上构建),因此查找操作比普通的要快(log(N));插入操作要慢(log(N)),因为要维护有序 。
散列表
散列表也叫哈希表,是根据关键键值()进行访问的数据结构,它通过把关键码值映射到表中一个位置来访问记录 , 以加快查找的速度,这个映射函数叫做散列函数 。
Java中实现了散列表,而比它多了一个线程安全性,但是由于使用了全局锁导致其性能较低,所以现在一般用来实现线程安全的(类似的,以上的数据结构在最新的java.util.的包中几乎都有对应的高性能的线程安全的类) 。实现接口,能够把它保存的记录按照键排序 。保留了元素插入的顺序 。是一种改进的,它对key实行“弱引用”,如果一个key不再被外部所引用 , 那么该key可以被GC回收,而不需要我们手动删除 。

树(tree)是包含n(n>0)个节点的有穷集合 , 其中:
树这种数据结构在计算机世界中有广泛的应用,比如操作系统中用到了红黑树 , 数据库用到了B+树,编译器中的语法树,内存管理用到了堆(本质上也是树) , 信息论中的哈夫曼编码等等等等,在Java中和用到了树来排序(二分查找提高检索速度),不过一般都需要程序员自己去定义一个树的类,并实现相关性质,而没有现成的API 。
下面用Java来实现各种常见的树 。
二叉树
二叉树是一种基础而且重要的数据结构,其每个结点至多只有二棵子树,二叉树有左右子树之分,第i层至多有2(i-1)个结点(i从1开始);深度为k的二叉树至多有2(k)-1)个结点,对任何一棵二叉树,如果其终端结点数为n0 , 度为2的结点数为n2,则n0=n2+1 。
二叉树的性质:
满二叉树、完全二叉树
满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点;
完全二叉树:若设二叉树的深度为h,除第 h 层外 , 其它各层 (1~(h-1)层) 的结点数都达到最大个数,第h层所有的结点都连续集中在最左边,这就是完全二叉树;
满二叉树是完全二叉树的一个特例 。
二叉查找树
二叉查找树,又称为是二叉排序树( Sort Tree)或二叉搜索树 。二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
二叉查找树的性质:对二叉查找树进行中序遍历,即可得到有序的数列 。二叉查找树的时间复杂度:它和二分查找一样,插入和查找的时间复杂度均为O(logn),但是在最坏的情况下仍然会有O(n)的时间复杂度 。原因在于插入和删除元素的时候,树没有保持平衡 。我们追求的是在最坏的情况下仍然有较好的时间复杂度,这就是平衡二叉树设计的初衷 。
平衡二叉树
平衡二叉树又被称为AVL树,具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树 。它的出现就是解决二叉查找树不平衡导致查找效率退化为线性的问题,因为在删除和插入之时会维护树的平衡,使得查找时间保持在O(logn),比二叉查找树更稳定 。

堆是一颗完全二叉树,在这棵树中 , 所有父节点都满足大于等于其子节点的堆叫大根堆 , 所有父节点都满足小于等于其子节点的堆叫小根堆 。堆虽然是一颗树,但是通常存放在一个数组中,父节点和孩子节点的父子关系通过数组下标来确定 。
堆的用途:堆排序,优先级队列 。此外由于调整代价较小 , 也适合实时类型的排序与变更 。
最后
写着写着就发现要想总结到位是一项非常庞大的工程 , 路漫漫其修远兮,吾将上下而求索 。
我个人认为,作为技术人就要保持终生学习的态度,让学习力成为核心竞争力,才能不被时代所淘汰 , 而高效的时间支配能让你变得更加优秀,所以,我在这里将这份耗时两个月搜集的算法刷题书籍,送给有需要的人,希望这些资料能对大家有所帮助
《算法的乐趣》
《算法》
《算法刷题版》