非985,211毕业成功入职字节跳动,我有一份算法面试指南分享给你!

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

算法基础知识总结这部分主要有以下几个内容:常见的数据结构及其实现、算法时间复杂度的计算以及常见的算法思想,其中常见的算法思想中有递归、分治、贪心、动规等等。
很显然,一篇文章是不可能将所有算法基础知识都整理出来的,下面我们主要从算法面试的角度依次谈谈这些算法基础知识,很多其他的算法例如图中的算法或者算法思想例如回溯、分支限界等都不在本文中介绍。

1.1 常见的数据结构及其实现
众所周知,数据结构是算法的基石,如果不懂二叉堆这个数据结构怎么写得出堆排序算法呢?

常见的数据结构主要有数组、链表、栈、队列、二叉堆、树、图等,其中栈和队列的题目经常出现在笔试试卷中,而且实际算法面试中二叉堆和图考得很少,经常出现的是数组、链表和二叉树这几种数据结构类型的题目。

(1) 数组虽然是最基础的数据结构,但是能考的东西却非常多,例如最常见的排序算法、找数组中第k大的数字、找两个有序数组的中位数等
[我的面试经历:美团二面遇到合并排序,友盟实习生面试二面遇到找两个有序数组的中位数]

(2) 链表因其特殊的结构也是常考点,例如反转链表、链表元素排序、合并两个有序链表、判断链表是否有环、有环的话环的起点在哪里等
[我的面试经历:腾讯实习生笔试题遇到判断链表是否有环]

(3) 二叉树由于其天然的递归结构,是最适合考查递归思想的数据结构,例如判断二叉树是否平衡、判断二叉树是否相同、判断二叉树是否对称等
[我的面试经历:神马实习生一面遇到判断二叉树是否是平衡二叉树]

(4) 栈和队列也是很重要的数据结构,但是它们往往只是作为前期的笔试题,栈经常出的题目就是给出一个栈的入栈序列,问下面哪个不可能是这个栈的出栈序列。栈和队列作为算法题并不多,常见的就是如何用两个栈来实现一个队列或者利用一个辅助栈来将一个栈中的元素排序
[我的面试经历:有道一面遇到利用一个辅助栈来将一个栈中的元素排序]

1.2 算法时间复杂度的计算

一般算法面试的时候,面试官在你给出了解法之后都会问下你这个解法的时间复杂度是多少,如果时间复杂度较高他就会要求你想出一个更优的解法,所以平时有必要练习下算法时间复杂度的计算。算法的运行时间主要有三种表示符号,但是最常见的就是大O表示法。此外,算法导论中介绍了三种时间复杂度的计算方法,分别是代换法、递归树法和主定理法

下表是常见的算法时间复杂度值及其相应的算法问题举例,例如平方阶时间复杂度是一些基于比较的排序算法的时间复杂度,例如选择排序、冒泡排序等。nlgn阶时间复杂度是随机数字序列的最优排序算法的时间复杂度,例如快速排序等。

下表是常见的递推公式对应的算法时间复杂度和算法问题举例,例如合并排序是nlgn阶,握手问题是平方阶,汉诺塔问题是指数阶等。这个建议结合具体的例子记忆一下,以便快速反应。

下表是主定理法在三种情况下的求值公式。主定理通常可以解决类似 T(n) = a T(n/b) + f(n) 这种递归形式的问题,即将规模为n的问题划分为a个子问题,每个子问题的规模是n/b,这里a和b是正常数,划分原问题和合并结果的代价用函数f(n)描述。

1.3 常见的算法思想

(1)Induction(推导)、Recursion(递归)、Reduction(规约)和Divide and Conquer(分治)

这四个思想比较接近,在《Python Algorithms》这本书中都有提到,我放在一起介绍:

  • **Induction(推导)是指数学意义上的推导,类似数学归纳法,主要是用来证明某个命题是正确的。**首先我们证明对于基础情况(例如在k=1时)是正确的,然后证明该命题递推下去都是正确的(一般假设当k=n-1时是正确的,然后证明当k=n时也是正确的即可)

  • **Recursion(递归)经常发生于一个函数调用自身的情况。**递归函数说起来简单,但是实现不太容易,我们要确保对于基础情况(不递归的情况)能够正常工作,此外,对于递归情况能够将递归调用的结果组合起来得到一个有效的结果。

=> 不难发现,Induction(推导)和Recursion(递归)其实彼此相互对应,Induction是自下而上的推导(例如从n-1到n),而Recursion是自上而下的递归(例如从n到n-1)。

  • Reduction(规约)是指问题转换,将一个未知的问题转换成我们能够解决的问题。

  • Divide and Conquer(分治)指将原问题划分成几个小问题,然后递归地解决这些小问题,最后综合它们的解得到问题的解。

=> 仔细分析可知,Induction(推导)、Recursion(递归)和Divide and Conquer(分治)其实都是某种形式上的Reduction(规约),也就是说它们的本质都是对问题进行规约!

这四个概念有一个共同特点:**它们都专注于求出目标解的某一步,我们只需要仔细思考这一步,剩下的就能够自动完成了。**有点晕?_? 好吧,其实你可能已经对上面几个概念很熟悉了,只是平时没有这么去想过,下面我们举最常见的排序问题为例来阐述下其中的算法思想。

**我们如何对排序问题进行Reduction呢?**很显然,有很多种方式:

  • 假如我们将原问题reduce成两个规模为原来一半的子问题,然后合并子问题的解,这是我们最为常见的二分分治策略,这样我们就得到了合并排序

  • 假如我们每次只是reduce一个元素,并假设前n-1个元素都排好序了,那么我们只需要将第n个元素插入到前面的序列即可,这样我们就得到了插入排序

  • 假如我们每次还是reduce一个元素,这次我们找到其中最大的元素然后将它让在最后一个还没有放置元素的位置上,一直这么下去我们就得到了选择排序

  • 假如我们每次还是reduce一个元素,这次我们找到第k大的元素,然后将它放在位置k上,一直这么下去我们就得到了快速排序

怎么样?我们学过的排序算法经过这么reduce基本上都很清晰了,不是吗?

为了能够对问题使用Induction或者说Recursion,Reduction一般是将一个问题变成另一个或者几个只是规模减小了的相同问题。那么,这样做就万事大吉了吗?
其实并不是的,有些时候我们可能还需要考虑Reduction或者说分治策略的子问题平衡性。对于同一个问题,分治时采用 T(n)=T(n-1)+T(1)+n 和 T(n)=2T(n/2)+n 两种解决方案的时间复杂度是不同的,这里就不展开说了。

(2) 贪心

贪心算法顾名思义就是每次都贪心地选择当前最好的那个(局部最优解),不去考虑以后的情况,而且选择了就不能够“反悔”了。如果原问题满足贪心选择性质和最优子结构,那么最后得到的解就是最优解。

贪心算法和其他的算法比较有明显的区别,动态规划每次都是综合所有子问题的解得到当前的最优解(全局最优解),而不是贪心地选择;回溯法是尝试选择一条路,如果选择错了的话可以“反悔”,也就是回过头来重新选择其他的试试。

最能说明贪心算法思想的问题就是背包问题了,这个问题大家也都很熟悉了,而且该问题的变种很多,常见的有整数背包和部分背包问题。问题大致是这样的,假设现在我们要装一些物品到一个书包里,每样物品都有一定的重量w和价值v,但是呢,这个书包承重量有限,所以我们要进行决策,如何选择物品才能使得最终的价值最大呢?整数背包是说一个物品要么拿要么不拿,比如茶杯或者台灯等等,而部分背包问题是说一个物品你可以拿其中的一部分,比如一袋子苹果放不下可以只装半袋子苹果。[更加复杂的版本是说每个物品都有一定的体积,同时书包还有体积的限制等等]

很显然,部分背包问题是可以用贪心法来求解的,我们计算每个物品的单位重量的价值,然后将它们降序排序,接着开始拿物品,只要装得下全部的该类物品那么就全装进去,如果不能全部装下就装部分进去直到书包载重量满了为止,这种策略肯定是正确的。

但是,整数背包问题就不能用贪心策略了。整数背包问题还可以分成两种:一种是每类物品数量都是有限的(bounded),比如只有3个茶杯和2个台灯;还有一种是数量无限的(unbounded),也就是你想要多少有多少,这两种都不能使用贪心策略。0-1背包问题是典型的第一种整数背包问题,看下算法导论上的这个例子就明白了,在(b)中,虽然物品1单位重量的价值最大,但是任何包含物品1的选择都没有超过选择物品2和物品3得到的最优解220;而©中能达到最大的价值是240。

贪心算法其实还是比较好想到的,它真正难的是如何证明这个贪心策略是正确的,还有贪心算法的内在原理“拟阵”,我已忘得一干二净了。建议刷下LeetCode上的贪心题,虽然实际算法面试中很少出贪心题。

(3) 动规

动态规划其实就是一个连续决策的过程,每次决策我们可能有多种选择(0-1背包问题中我们只有两个选择,也就是对于这个物品是拿还是不拿),我们每次选择最好的那个作为我们的决策。所以,动态规划的时间复杂度其实和这两者有关,也就是子问题的个数以及子问题的选择个数,一般情况下动态规划算法的时间复杂度就是两者的乘积。

动态规划有两种实现方式:

  • 一种是带备忘录的递归形式,这种方式直接从原问题出发,遇到子问题就去求解子问题并存储子问题的解,下次遇到的时候直接取出来,问题求解的过程看起来就像是先自顶向下地展开问题,然后自下而上的进行决策;

  • 另一个实现方式是迭代方式,这种方式需要考虑如何给定一个子问题的求解方式,使得后面求解规模较大的问题是需要求解的子问题都已经求解好了,它的缺点就是可能有些子问题不要算但是它还是算了,而递归实现方式只会计算它需要求解的子问题。

递归实现和迭代实现的重要区别在于:递归实现不需要去考虑计算顺序,只要给出问题,然后自顶向下去解就行;而迭代实现需要考虑计算顺序,并且顺序很重要,算法在运行的过程中要保证当前要计算的问题中的子问题的解已经是求解好了的。

下面我们以有向无环图的单源最短路径问题来对比动规的两中实现方式:
假设有如下图所示的图,当然,我们看到的是这个有向无环图是经过了拓扑排序之后的结果,从a到f的最短路径用灰色标明了。

我们有两种思考方式:

1.“去哪里?”:我们顺向思维,首先假设从a点出发到所有其他点的距离都是无穷大,然后,按照拓扑排序的顺序,从a点出发,接着更新a点能够到达的其他的点的距离,那么就是b点和f点,b点的距离变成2,f点的距离变成9。因为这个有向无环图是经过了拓扑排序的,所以按照拓扑顺序访问一遍所有的点(到了目标点就可以停止了)就能够得到a点到所有已访问到的点的最短距离,也就是说,当到达哪个点的时候,我们就找到了从a点到该点的最短距离,拓扑排序保证了后面的点不会指向前面的点,所以访问到后面的点时不可能再更新它前面的点的最短距离!这种思维方式的代码实现就是迭代版本。

用图来表示计算过程就是下面所示:

文末

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

88 (备注Android)**
[外链图片转存中…(img-bSiu1vv7-1713172114040)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值