大厂面经----接近30场面试分享

1.序

本人211小硕一枚,经历了春招秋招拿到不少offer,特此把自己从小白到今天的成长经历与面试经历分享与大家,希望能有所帮助。成功上岸腾讯、百度、京东、快手、斗鱼、华为传入接送部、华为公共软件开发部、海康威视、烽火科技、玄武科技等。

2.接近30场面试过程

2.1 快手

快手1面 (60分钟)

1 题目 两数之和
https://blog.csdn.net/weixin_41563161/article/details/104762344
2 Socket协议用什么协议(Socket底层)
https://blog.csdn.net/weixin_41563161/article/details/104779605
3 Java和python的区别
https://blog.csdn.net/weixin_41563161/article/details/104780661
如果让我接触新的语言,我可以接受,并且我会尽快入门,然后参与开发。因为我学习能力还是挺强的。

是以项目驱动技术的,而且我想的是java都没有达到一定的深度,但是如果有需求的我能以最短的时间上手。
4 为什么不全用unity做
因为航天方面的软件有一款公认的也是目前唯一的承认的STK,就是那个传统的客户端,简单的界面,不是全部unity仿真,如果70%的任务全部是非仿真的,所以开发较快,用了WPF;

5组件不是因为svn的问题
是因为模块化,以后需要的话直接拿来复用,因为实验室经常接这种航天类项目,航天类项目的话有一些是可复用的,比如轨道计算,星座覆盖,链路,这些等等。所以用组件的模式
6 java中集合有哪些 Hashmap 和TreeMap区别
7 红黑树的特点
8 mysql数据库索引数据结构 为什么用B+树
9 主键索引和普通索引的区别
10 Arrays.sort()的底层实现
Java Arrays中提供了对所有类型的排序。其中主要分为Primitive(8种基本类型)和Object两大类。
  基本类型:采用调优的快速排序
  对象类型:采用改进的归并排序
源码中的快速排序,主要做了以下几个方面的优化:
  1)当待排序的数组中的元素个数较少时,源码中的阀值为7,采用的是插入排序。尽管插入排序的时间复杂度为0(n^2),但是当数组元素较少时,插入排序优于快速排序,因为这时快速排序的递归操作影响性能。
  2)较好的选择了划分元(基准元素)。能够将数组分成大致两个相等的部分,避免出现最坏的情况。例如当数组有序的的情况下,选择第一个元素作为划分元,将使得算法的时间复杂度达到O(n^2).
  3)根据划分元 v ,形成不变式 v*
 1)当数组大小为 size=7 时 ,取数组中间元素作为划分元。int n=m>>1;(此方法值得借鉴)。
 2)当数组大小size大于7小于等于40时,取首、中、末三个元素中间大小的元素作为划分元。
 3)当数组大小 size>40 时 ,从待排数组中较均匀的选择9个元素,选出一个伪中数做为划分元。
11 文档编写
软件需求书 软件使用说明书 技术说明书 测试报告

12提问的问题
(1)贵司的培养模式
(2)公司内部是否支持内部转岗这样的政策
(3)公司的竞升机制是怎么样的
(4)这是我第一次面试,如果可以,希望您能给我提点建议。如果不方便的话,那就辛苦您花时间来面试我了。谢谢
(5)目前我去了做什么工作。
13为什么没有用到服务式
因为第一个目前没有掌握服务式开发,第二是没有网,那些地方不通网,只能用单机版,而且数据是保密的,不允许外传。
14 如果被问到C#和Vue怎么说
CLR是公共语言运行池。

可能对您要坦白的是前端自从研一接触了4个月之后就没有接触了,因为当时师兄们走,前端差不多也做完了,所以扛起了后台和数据库的任务。前端当时是基于师兄的框架上做的,因为后来因为项目的需要也没有再接触过前端,所以也没有深挖,只是知道怎么用,但是对于自己来说如果有机会进入腾讯的话我可以接受前端,并且自己也喜欢去做前端,相信自己在有后台的基础上可以对前端的开发更加深入。
其实昨天下午收到通知的时候有在想要不要看一下前端的东西,但是想了一下只知道表面的意思没有用的,何况只有一天时间,所以就跟您坦白一下,但是我可以在短时间内入手。

15其它
我喜欢努力极致的做目前所做的事情,就比如大学期间侧重于学生工作,所以就做到了一定的层次然后锻炼了我遇到问题解决问题的能力了。 研究生期间也一样,既然选择了做研究做学问那么就一心把它做好,这也是当时为什么我本科期间基础并不是很好学历也不是很好,但是能在很短的时间内迅速提升起来并且有幸去北京钱学森实验室参与并负责一个项目的原

2.2 腾讯

2.2.1 微信1面 (120分钟)

题目算法
旋转数字的最小数字(注意(1,0,1,1,1))这种情况
合并两个排序链表
二叉搜索树中的第3大个结点 (在面试官提示下进行剪枝)O(1)空间复杂度
1假如没有数据了三次挥手行不行
https://blog.csdn.net/weixin_41563161/article/details/104941167
2 服务器怎么就知道自己没数据了
https://blog.csdn.net/weixin_41563161/article/details/104941167
3 tcp和http有什么联系

HTTP是应用层协议,定义的是传输数据的内容的规范

不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。

TCP即传输控制协议(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通讯协议。
HTTP协议中的数据是利用TCP协议传输的,所以支持HTTP也就一定支持TCP
应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受计算连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传输给IP层,有它来通过网络将包传送给接收端实体的TCP层。

当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据流分割成适当长度的报文。之后TCP把数据包传递给IP层,由它来通过网络将包传送给接收端实体的TCP层。
Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
https://blog.csdn.net/weixin_41563161/article/details/104941167
4 http请求方法 (深入的)head是干什么的
https://blog.csdn.net/weixin_41563161/article/details/104946065
5 线程如何结束
https://blog.csdn.net/weixin_41563161/article/details/104942044
1使用标志位
这种方法是我尝试终止线程时最初采用的方法,使用起来很方便,原理也很简单,只要在while循环里持续判断一个Boolean变量的值就可以了,一旦满足离开循环的条件,那么就可以离开线程的方法体,结束线程。
2 使用Interrupt方法(中断)

1.线程处于阻塞状态,如使用了sleep,同步锁的wait,socket中的receiver,accept等方法时,会使线程处于阻塞状态。当调用线程的interrupt()方法时,会抛出InterruptException异常。阻塞中的那个方法抛出这个异常,通过代码捕获该异常,然后break跳出循环状态,从而让我们有机会结束这个线程的执行。通常很多人认为只要调用interrupt方法线程就会结束,实际上是错的, 一定要先捕获InterruptedException异常之后通过break来跳出循环,才能正常结束run方法。
2.线程未处于阻塞状态,使用isInterrupted()判断线程的中断标志来退出循环。当使用interrupt()方法时,中断标志就会置true,和使用自定义的标志来控制循环是一样的道理。

3为什么要区分进入阻塞状态和和非阻塞状态两种情况了,是因为当阻塞状态时,如果有interrupt()发生,系统除了会抛出InterruptedException异常外,还会调用interrupted()函数,调用时能获取到中断状态是true的状态,调用完之后会复位中断状态为false,所以异常抛出之后通过isInterrupted()是获取不到中断状态是true的状态,从而不能退出循环,

6 如何保证线程安全性
1、synchronized 锁(偏向锁,轻量级锁,重量级锁)
2、volatile 英[ˈvɒlətaɪl]锁,只能保证线程之间的可见性,但不能保证数据的原子性
3、jdk1.5 并发包中提供的 Atomic 原子类 CAS
4、Lock 锁
5. 多实例、或者是多副本(ThreadLocal): 当使用 ThreadLocal 维护变量时,ThreadLocal
为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副
本,而不会影响其它线程所对应的副本
6.1实现线程同步的几种方式总结
1 通过Object的wait和notify
2 通过Condition的awiat和signal
3 通过一个阻塞队列
4通过同步辅助类CountDownLatch
5 通过同步辅助类CyclicBarrier
7 深拷贝浅拷贝
https://blog.csdn.net/weixin_41563161/article/details/101628243
1哪些地方用到深拷贝 浅拷贝
深拷贝和浅拷贝相当于是对象拷贝,引用拷贝的话是共用同一个对象,地址是相同的,对象拷贝的是创建了新的对象。又分为深拷贝和浅拷贝。

浅拷贝 (浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象)
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。"里面的对象“会在原来的对象和它的副本之间共享。

深拷贝 对引用类型的成员变量也进行引用对象的复制 clone() 实现Serializable

8 线程池
9 核心线程是干嘛的
10 voliate 只用它保持线程安全行不行
11 GC
12 Full Gc期间整个虚拟机是什么状态

CMS那一块
13 Java 有哪些锁 p131
在并发编程中,经常遇到多个线程访问同一个 共享资源 ,这时候作为开发者必须考虑如何维护数据一致性,在java中synchronized关键字被常用于维护数据一致性。synchronized机制是给共享资源上锁,只有拿到锁的线程才可以访问共享资源,这样就可以强制使得对共享资源的访问都是顺序的,因为对于共享资源属性访问是必要也是必须的。
对象锁和类锁
根据使用方式的不同一般我们会将锁分为对象锁和类锁,两个锁是有很大差别的,对象锁是作用在实例方法或者一个对象实例上面的,而类锁是作用在静态方法或者Class对象上面的。一个类可以有多个实例对象,因此一个类的对象锁可能会有多个,但是每个类只有一个Class对象,所以类锁只有一个。 类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定的是实例方法还是静态方法区别的 。

对象锁 类锁
同一对象 不同加锁的非静态方法 互斥
同一对象 一个加锁 一个不加锁非静态方法 不互斥
不同对象 不同加锁的非静态方法 不互斥

两个对象 两个静态加锁方法 (与对象无关) 互斥
把一个方法写成静态, 一个不静态, 都加锁(静态与非静态方法不共用锁) 不互斥

1可重入锁

2可中断锁
lockInterruptibly()的用法时已经体现了Lock的可中断性。
3公平锁
公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。
非公平锁即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。
在Java中,synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。

4 读写锁
读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。
正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。
ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。
可以通过readLock()获取读锁,通过writeLock()获取写锁。

读锁的共享锁可保证并发读是非常高效的,读写,写读 ,写写的过程是互斥的。
https://www.cnblogs.com/aspirant/p/6930436.html

5 自旋锁
如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。

首先是一种锁,与互斥锁相似,基本作用是用于线程(进程)之间的同步。与普通锁不同的是,一个线程A在获得普通锁后,如果再有线程B试图获取锁,那么这个线程B将会挂起(阻塞);试想下,如果两个线程资源竞争不是特别激烈,而处理器阻塞一个线程引起的线程上下文的切换的代价高于等待资源的代价的时候(锁的已保持者保持锁时间比较短),那么线程B可以不放弃CPU时间片,而是在“原地”忙等,直到锁的持有者释放了该锁,这就是自旋锁的原理,可见自旋锁是一种非阻塞锁。

二、自旋锁可能引起的问题:
1.过多占据CPU时间:如果锁的当前持有者长时间不释放该锁,那么等待者将长时间的占据cpu时间片,导致CPU资源的浪费,因此可以设定一个时间,当锁持有者超过这个时间不释放锁时,等待者会放弃CPU时间片阻塞;
2.死锁问题:试想一下,有一个线程连续两次试图获得自旋锁(比如在递归程序中),第一次这个线程获得了该锁,当第二次试图加锁的时候,检测到锁已被占用(其实是被自己占用),那么这时,线程会一直等待自己释放该锁,而不能继续执行,这样就引起了死锁。因此递归程序使用自旋锁应该遵循以下原则:递归程序决不能在持有自旋锁时调用它自己,也决不能在递归调用时试图获得相同的自旋锁。
14 Wait 和notify分别是干嘛的

Object.nofity() 的文档明确说一个随机的线程将被唤醒,但具体情况将由实现者决定,因为Object.nofity()是一个native方法。(具体的jvm来实现)
Condition.signal() 的文档则说一个被选定的线程将被唤醒。

可以清晰的看到notify()方法是按先进先出的顺序唤醒的,即是公平的。本实验在Java 1.8 HotSpot 下测试,可以看出Java 1.8 HotSpot把notify()实现为公平的方式。

15 类加载
16 双亲委派模型

17 Socket如何解决丢包
18 其它 网络通信的方式

heissen,dubbo,webservice,thrift
dubbo
Dubbo(读音[ˈdʌbəʊ])是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 [1] Spring框架无缝集成。
webservice
Web Service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的交互操作的应用程序。
Thrift
是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。
19 CAS Synchronized Voliate
synchronized
synchronized英[ˈsɪŋkrənaɪzd] 同步代码块的语义底层是基于对象内部的监视器锁(monitor),分别是使用 monitorenter 和 monitorexit 指令完成。其实 wait/notify 也依赖于 monitor 对象,所以其一般要在 synchronized 同步的方法或代码块内使用。monitorenter 指令在编译为字节码后插入到同步代码块的开始位置,monitorexit 指令在编译为字节码后插入到方法结束处和异常处。JVM 要保证每个 monitorenter 必须有对应的 moniorexit。
cas

volatile

2.2.2 腾讯云盘1面(40分钟)

1 打印字节数
https://blog.csdn.net/weixin_41563161/article/details/104993568

2 arraycopy

public class Test6 {
   
    public static void main(String[] args) {
   
        int[] formArray={
   101,102,103,104,105,106};
        int[] toArray={
   201,202,203,204,205,206,207};
        System.arraycopy(formArray, 2, toArray, 3, 2);
        for(int i=0;i<toArray.length;i++){
   
            System.out.println(i+":"+toArray[i]);
        }
    }

    public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
   
     // TODO 请完成实现部分
    }

}

3 旋转数组
4 多线程

2.2.3 腾讯一面 PCG 90分钟

1 题目
:运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key):如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) : 如果密钥不存在,则写入(设置或插入)其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
评价:对 LRU 机制比较熟悉,算法阐述比较清晰,写代码过程没有像第一题一样的混乱。

解决方案:
//定义链表节点
class Node{
   
int key;
int value;
Node pre;
Node next;
public Node(int key,int value){
   
this.key = key;
this.value = value;
}
}
public class LRUCache{
   
Map<Integer,Node> cacheMap = new HashMap<>();
//定义哈希表
Node head = null;
//定义头节点
Node tail = null;
//定义尾节点
int nodeLength =0;
//容量
//put操作
public int get(int key){
   
if(cacheMap.containsKey(key)){
   
//如果存在的话
Node node =cacheMap.get(key);
removeNode(node);
//进行移除
setHead(node);
//把节点放到首部
return node.value;
//返回节点
}
return -1//不存在返回-1;
}
//移除链表中的节点
public void removeNode(Node node){
   
if(node.pre != null){
   
//如果前节点不为空
node.pre.next = node.next;
}else{
   
//前节点为空
head = node.next;
}
if(node.next != null){
   
//后节点不为空
node.next.pre = node.pre;
}else{
   
后节点为空
tail 
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haikuotiankongdong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值