这篇面经来自一位粉丝的投稿,他在前天也就是6月9号通过了字节跳动的一面,分享了一些面试遇到的问题,然后我整理了出来,希望对即将参加面试的你们有一些帮助。
除了这些之外我还整理了一些别的大厂面试真题
可以分享给大家,需要的朋友转发本文+关注+私信【611】就可以领取了
好,现在我们一道一道的来看问的这些问题
面试自我介绍虽然人人都准备,但是做到让人印象深刻可不容易啊,甚至有的人压根都不重视,只想靠技术折服面试官,当然了,如果真的是很牛的技术大牛,那应该是没问题。
面试是什么?
它是个机会,让面试官更进一步确认你是他们需要的人,你进一步展现你的交际沟通能力。
So
一定一定要记住,自己是在跟人打交道,而不是对机器答问题!
首先,为啥面试官要提这个问题呢?简历里面不是写得好清楚好详细了吗?
其实呢,这个问题,据很多做面试官的朋友所说,要是给面试官一个缓冲的时间来重新熟悉你的简历。
所以,我们要通过自我介绍提醒面试官,你的特点和你为什么特别合适这个职位。当然了,语言尽量简练,咨询了一些资深面试官后我总结了面试的3个要点,给大家参考一下。
时间控制在1分钟,写在纸上就是120-160个字:
这三个点用精炼的语言表达清楚自我介绍这一块基本就没什么问题了。
解决死锁一般有四个阶段,即
死锁预防: 破坏导致死锁必要条件中的任意一个就可以预防死锁。
例如:
使用银行家算法:指在分配资源之前先看清楚,资源分配后是否会导致系统死锁。如果会死锁,则不分配,否则就分配。
死锁检测: 判断系统是否属于死锁的状态,如果是,则执行死锁解除策略。
死锁解除: 将某进程所占资源进行强制回收,然后分配给其他进程。(与死锁检测结合使用的)
在我们运行的用户程序中,凡是与系统级别的资源有关的操作(例如文件管理、进程控制、内存管理等)都必须通过系统调用方式向OS提出服务请求,并由OS代为完成
平常我们的进程几乎都是用户态,读取用户数据,当涉及到系统操作,计算机资源的时候就要用到系统调用了
系统调用的功能大致分为
系统调用的功能与其作用一样——涉及计算机资源的操作
进程是一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。
线程是进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。
与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
基于进程调度的两种方式的调度算法如下:
这里篇幅所限,就只讲一下前面两种吧,其余的如果感兴趣可以自己找资料看看
先来先服务(FCFS)调度算法
1、简介:先来先服务调度算法是一种最简单的调度算法,可用于作业调度,也可用于进程调度。
2、原理:在进程调度中采用先来先服务算法的时候,每次调度就从就绪队列中选一个最先进入该队列的进程,为之分配处理机,即谁第一排队谁就先被执行。
3、优点:
有利于长作业(进程)
有利于CPU繁忙型的作业(进程)
4、缺点:
不利于短作业(进程)
不利于I/O繁忙型的作业(进程)
短作业优先(SJF)调度算法
1、简介:短作业(进程)优先调度算法是指短作业或者短进程的优先调度算法,它们分别作用于作业调度和进程调度,它是先来先服务调度算法的一种优化版本。
2、原理:短进程优先调度算法是从就绪队列中选出一个估计运行时间最短的进程,再将处理机分配给它,直到执行完成,而其他进程一般不抢先正在执行的进程。
3、优点:
算法对长作业(进程)不利(长作业(进程)长期不被调度)
未考虑进程的紧迫程度
由于是估计运行时间而定,而这个时间是由用户所提供的,所以该算法不一定能真正做到短作业优先调度
这里给你们看张图应该就是明白了,面试的时候如果遇到这道题,用自己的话说出来即可
这个你么根据自己的使用情况实话实说就可以了,数组,链表,队列,栈,树,Hash表这些,随便说个两三个就行。
如何理解贪心算法?
假设我们有一个可以容纳 100kg 物品的背包,可以装以下 5 种豆子,每种豆子的总量和总价值各不相同,为了使背包中所装物品的总价值最大,我们如何选择在背包中装哪些豆子?每种豆子又该装多少呢?
实际上,我们只要先算一算每个物品的单价,按照单价由高到低来装就好了。依次是黑豆、绿豆、红豆、青豆、黄豆,所以我们可以往背包里装 20kg 黑豆、30kg 绿豆、50kg 红豆。
这个问题的解决思路本质上借助的就是贪心算法。结合这个例子,总结了一下贪心算法解决问题的步骤:
第一步、
当我们看到这类问题的时候,首先应该联想到贪心算法:针对一组数据,我们定义了限制值和期望值,希望从中选出几个数据,在满足限制的情况下,期望值最大。类比刚才的例子,限制值就是总量不能超过 100kg,期望值就是物品的总价值,这组数据就是 5 种豆子。
第二步、
我们尝试看下这个问题是否可以用贪心算法解决:每次选择当前情况下,在对限制值同等贡献量的情况,对期望值贡献最大的数据。类比刚才的例子,就是每次从剩下的豆子里面,选择单价最高的,也就是重量相同的情况下,对价值贡献最大的豆子。
第三步、
实际上,贪心算法解决问题的思路,并不总能给出最优解。
举个例子,在一个有权图中,我们从顶点 S 出发,找一条到顶点 T 的最短路径(路径中边的权值总和最小)。贪心算法的结局思路是,每次选择都选择一条跟当前顶点相连的圈最小的边,直到找到顶点 T,按照这种思路,找出最短路径:S->A->E->T ,路径长度是 1 + 4 + 4 = 9。显然不是最短的,因为最短的是:S->B->D->T,总长度是 2 + 2 + 2 = 6
为什么贪心算法在这个问题上不工作了呢,主要原因是,前面的选择会影响后面的选择。所以即便我们第一步选择最优的走法,但有可能因为这一步选择,导致后面每一次的选择都很糟糕,最终也自然和最优解无缘了。
霍夫曼编码
接下来看看霍夫曼编码是如何利用贪心算法来实现对数据压缩编码,有效节省数据存储空间的
假设我有一个包含 1000 个字符的文件,每个字符占 1 个 byte (1 byte = 8 bits),存储这 1000 个字符就一共需要 8000 bits,那么有没有更加节省空间的存储方式呢?
假设我们统计发现,这 1000 个字符只包含 6 种不同字符,假设它们分别是 a、b、c、d、e、f。而 3 个二进制 bit 就可以表示8 个不同的字符,所以为了尽量减少存储空间的存储空间,每个字符我们用 3 个二进制位来表示,比如:a(000)、b(001)、c(010)、d(011)、e(100)、f(101),那么存储这 1000 个字符只需要 3000bits 就可以了,比原来的存储节省了很多空间,那么还有没有更加节省空间的存储方式呢?
这个时候就要用到霍夫曼编码了。霍夫曼编码是一种十分有效的编码方法,广泛用于数据压缩中,其压缩率通常在 20%~90% 之间。
霍夫曼编码不仅会考察文本中有多少个不同字符,还会考察每个字符出现的频率,根据频率的不同,选择不同长度的编码。霍夫曼编码试图用这种不等长的编码方法,来进一步增加压缩的效率。
如何给不同频率的字符选择不同长度的编码呢,根据贪心的思想,我们可以把出现频率比较多的字符,用稍微短一些的编码;出现频率比较少的字符,用稍微长一些的编码。
对于等长的编码来说,压缩起来很简单。比如刚才那个例子,用 3 个 bit 表示一个字符。在解压缩的时候,每次从文本中读取 3 位二进制,然后翻译成对应的字符,但是,霍夫曼编码是不等长的,每次应该读取 1 位,还是 2 位还是 3 位等等来解压缩呢,这个问题就导致霍夫曼编码解压缩起来比较复杂。为了避免解压缩过程中的歧义,霍夫曼编码要求各个字符的编码之间不会出现某个编码是另一个编码前缀的情况。
假设这 6 个字符出现的频率从高到低依次是 a、b、c、d、e、f ,我们把它们分别编码成下面这样子,任何一个字符的编码都不是另一个的前缀,在解压缩的时候,每次会读取尽可能长的可解压的二进制串,所以在解压缩的时候也不会有歧义。经过这种编码压缩之后,这 1000 个字符只需要 2100bits 就可以了。
尽管霍夫曼编码的思想并不难理解,但是如何根据字符出现频率的不同,给不同的字符进行不同长度的编码呢?这里的处理稍微有些技巧。
用队列实现栈
#include <iostream> #include "LinkQueue.h" #include "LinkStack.h" using namespace std; using namespace DTLib; template < typename T > class QueueToStack : public Stack<T> { protected: LinkQueue<T> m_queue_1; LinkQueue<T> m_queue_2; LinkQueue<T>* m_pIn; LinkQueue<T>* m_pOut; void move() const //O(n) { int n = m_pIn->length() - 1; for (int i = 0; i < n; i++) { m_pOut->add(m_pIn->front()); m_pIn->remove(); } } void swap() //O(1) { LinkQueue<T>* temp = NULL; temp = m_pIn; m_pIn = m_pOut; m_pOut = temp; } public: QueueToStack() { m_pIn = &m_queue_1; m_pOut = &m_queue_2; } void push(const T &e) //O(1) { m_pIn->add(e); } void pop() //O(n) { if(m_pIn->length() > 0) { move(); m_pIn->remove(); swap(); } else { THROW_EXCEPTION(InvalidOperationException, "No element in current stack ..."); } } T top() const //O(n) { if(m_pIn->length() > 0) { move(); return m_pIn->front(); } else { THROW_EXCEPTION(InvalidOperationException, "No element in current stack ..."); } } void clear() //O(n) { m_queue_1.clear(); m_queue_2.clear(); } int size() const { return m_queue_1.length() + m_queue_2.length(); } } ; int main() { QueueToStack<int> qs; for (int i = 0; i < 10; i++) { qs.push(i); } while(qs.size() > 0) { cout << qs.top() << " "; qs.pop(); } return 0; }
用栈实现队列
#include <iostream> #include "LinkQueue.h" #include "LinkStack.h" using namespace std; using namespace DTLib; template < typename T > class StackToQueue : public Queue<T> { protected: mutable LinkStack<T> m_stack_in; mutable LinkStack<T> m_stack_out; void move() const //O(n) { if(m_stack_out.size() == 0) { while(m_stack_in.size() > 0) { m_stack_out.push(m_stack_in.top()); m_stack_in.pop(); } } } public: void add(const T &e) //O(1) { m_stack_in.push(e); } void remove() //O(n) { move(); if(m_stack_out.size() > 0) { m_stack_out.pop(); } else { THROW_EXCEPTION(InvalidOperationException, "No element in current queue ..."); } } T front() const //O(n) { move(); if(m_stack_out.size() > 0) { return m_stack_out.top(); } else { THROW_EXCEPTION(InvalidOperationException,"No element in current queue ..."); } } void clear() //O(n) { m_stack_in.clear(); m_stack_out.clear(); } int length() const //O(1) { return m_stack_in.size() + m_stack_out.size(); } }; int main() { StackToQueue<int> sq; for(int i = 0; i < 10; i++) { sq.add(i); } while(sq.length() > 0) { cout << sq.front() << " "; sq.remove(); } return 0; }
篇幅所限,我这里就只讲这十个题吧,毕竟面试题实在是太多了,除了这些之外,我还整理了一些别的大厂面试题
我想,可能还有很多人在今年刚过去的金三银四春招中保持着观望的形势,害怕自己的能力不够,或者是安于现状,觉得目前拿着几千的月薪觉得能够接受,那么你就要注意了,这是非常危险的!
我们身为技术人员,最怕的就是安于现状,一直在原地踏步,那么你可能在30岁就会迎来自己的职业危机,因为你工作这么久提升的只有自己的年龄,技术还是万年不变!
我知道,对于一些学历没有优势的人来说,外包是别无选择,但是未来的路究竟要怎么走,取决你的步子迈多开。每个人都有自己的选择,如果你喜欢稳定,那按部就班适合你,但你有想法,不甘平庸,那就别让外包埋没了你。
如果你想在未来能够自我突破,圆梦大厂,那或许以上这份学习资料,你需要阅读阅读,希望能够对你的职业发展有所帮助。
最后,希望未来的我发展顺利,早日拿下p7!同样,也祝愿你实现自己的人生理想,愿我们都越来越好,共勉!
获取方式: 只需你点赞+关注后,Java进阶交流群:714827309 哦-!
获取方式: 只需你点赞+关注后,Java进阶交流群:714827309 进群拿资料哦-!