文章目录
- 引言
- 以往面经整理
- 正式面试
- 一面
- 八股
- 1、Java的HashMap介绍一下?
- 2、HashMap冲突会转成红黑树,为什么?
- 3、HashMap是线程安全的结构吗?有其他线程安全的容器吗?
- 4、HashCode和Equals有什么区别?
- 5、equals和==有什么区别吗?
- 6、MySQL中联合索引,有最左匹配原则是什么意思?
- 7、说几个场景,你说一下有没有利用到完全索引
- 8、MySQL有几种类型的索引?
- 9、全文索引是干什么的?(这里抓瞎了)
- 10、B+树索引是怎么实现的?详细说一下B+树的实现
- 11、MySQL的事务隔离级别有哪几种?
- 12、默认的隔离级别是哪个级别?解决了什么的问题?是怎么解决不可重复读的问题?
- 13、缓存用过吗?常用的数据结构有哪些?
- 14、分布式锁有用过吗?redis那个命令可以实现分布式锁的功能? 分布式解锁怎么实现?
- 15、缓存穿透和雪崩是什么概念?怎么解决这两个问题?(穿透和击穿记反了)
- 16、加锁之后,其他的流量是等待还是怎么样?
- 17、如果数据在DB中不存在,一直访问会怎么办?
- 18、如果redis中的数据和DB中的数据不一致怎么解决?
- 手撕——合并有序数组
- 反问
- 二面
- HR面
- 总结
引言
- 投了美团,真好,只有两轮技术面,不像别的公司,有三轮技术面!
以往面经整理
手撕
53、最大子数组和
个人实现
- 虽然想不起来了,但是知道DP,然后按照之前DP的思路,想想看怎么想,怎么把他转成集合问题!
- 这种序列问题,怎么表示集合,就是看序列的左右端点,这个思路还是记得的,然后写出了对应的状态转移方程,就好写了!
class Solution {
public int maxSubArray(int[] nums) {
int m = nums.length;
int[] f = new int[m + 1];
f[0] = nums[0];
int res = nums[0];
for(int i = 1;i < m;i ++){
f[i] = Math.max(nums[i],nums[i] + f[i - 1]);
res = Math.max(f[i],res);
}
return res;
}
}
总结
- 这道题,我完全忘记代码怎么写了,但是还记得怎么分析这种类型的题目,包括怎么指定对应终止节点等,所以刚好能够推理出来,所以还是要记思路,或者说一种思维习惯!
54、最长回文子串
第一次做说没时间
第二次做说没时间
话术都是一样的,这里不知道怎么弄了!笑死了
个人实现
- 做了这么多回,才知道这道题是动态规划,尴尬,之前用暴力搜索总是能够通过的,想想看使用动态规划怎么做?
- 根本没有思路,不知道怎么使用动态规划?
- 序列,最直白的就是序列,我判定一个序列[l,r]是不是一个回文子串,不用遍历,通过【l + 1,r - 1】来实现,那么就是一个二维的dp,f[l][r],如果l和r是的,那就说明两个可以构成回文字符串
- 在定义一下基础的情况
- l == r ,f[l][r] = true;
- l + 1 == r && nums[l] == nums[r],f[l][r] = true;
- 对于任意的情况,就是f[l][r],先判断l是否等于r,然后在判断f[l + 1][r - 1] 的情况
正式面试
一面
- 核心本地商业,到店的平台技术部,做的事直连平台,比如说住宿、门票等。
八股
1、Java的HashMap介绍一下?
简介
- 基于哈希表实现,访问速度快。
- 插入和删除的时间复杂度都是O(1)
- 元素之间没有顺序
- 哈希冲突的解决方式
- Java7采用数组 + 链表的方式实现
- Java8采用 数组 + 链表 + 红黑树 的方式实现
- 链表的长度大于9,自动转成红黑树
- 是否线程安全
- 非线程安全,推荐使用concurrentHashMap
- 数组扩容方式
- 当前存量 和 容量 * 负载因子的比较
- 扩容两倍的方式实现
- 通过按位 与 的方式实现取余运算
2、HashMap冲突会转成红黑树,为什么?
- 原先使用链表的话,冲突元素过多,然后查找效率偏低!
- 红黑树是自平衡的二叉查找树,保证在插入、删除和查找等操作都回保证较高的效率。
3、HashMap是线程安全的结构吗?有其他线程安全的容器吗?
为什么使用ConcurrentHashMap
- 本身不是线程安全的
- Hashtable线程安全,但是运行效率低,底层使用synchronized加锁
- 锁的颗粒度太高
- ConcurrentHashMap使用分段锁,提高并发率的同时,保证线程安全
- 将数据分段存储,每一段配一把锁,一个线程占用锁访问其中一段的时候,不影响其他线程继续访问
- 读数据不加锁,写数据才会加锁
JDK1.8实现
- 实现原理
- 数组+ 链表 + 红黑树
- 通过CAS和Synchronized实现加锁
- 具体加锁过程
- 对应hash位置没有元素
- 使用CAS插入元素
- 对应位置已经有链表了
- 使用Synchronized锁住槽点,防止其他线程操作
- 对应hash位置没有元素
JDK1.7分段锁的实现
- Segment数组将hash表分段
- ConcurrentHashMap对象中,保存了Segment数组,将整个Hash表划分为多个分段
- 每一个分段类似一个HashTable
- 默认支持16个线程并发操作
- ConcurrentHashMap对象中,保存了Segment数组,将整个Hash表划分为多个分段
- 访问流程
- 先根据hash算法定位到对应的Segment,对Segment加锁就行
4、HashCode和Equals有什么区别?
equals
- 用来判断两个对象是否相等,默认情况下是比较两个对象的内存地址是否相等。
hashcode
- 返回对象的散列码,默认是返回对象内存地址转换后的整数值。
两者的关系
- equals和hashcode共同作用,才能保证对象在基于hash的集合数据结构中的正确行为。
- 两个对象是相等的,equals相等的,返回的哈希值必须相等
- 哈希值相等,但是并不一定相等,因为不相等的对象会放在哈希值相同的两个桶中。
5、equals和==有什么区别吗?
equals
- 用来判断两个对象是否相等,默认情况下的比较两个对象内存地址是否相等。
==
- 比较两个对象引用是否指向同一个内存地址,适用于基本数据类型和引用数据类型。
6、MySQL中联合索引,有最左匹配原则是什么意思?
- 复合索引的最左匹配原则,不是说顺序,是说具体的值,where a and b and c 对于索引(a,b,c)是满足最左匹配原则的,但是如果是where c and b就不满足了,因为少了一个。
- 联合索引要遵循最左匹配原则,按照最左有限的方式进行索引匹配,否则会导致索引失效
7、说几个场景,你说一下有没有利用到完全索引
- index(a,b,c)
- where a = 1 and c = 2 and b = 3
- 三个字段都能用到索引
- where a = 1 and b > 2 and c = 3;
- 正常只能用到第二索引,b不是精确匹配
8、MySQL有几种类型的索引?
9、全文索引是干什么的?(这里抓瞎了)
- 提高查询速度
- 数据库存储文本中的关键词的位置信息,是的数据库能够迅速定位并检索出包含特定关键词的记录
- 支持多种数据类型
- 不仅仅局限于text文本类型的数据,还包含BLOB二进制大对象在内的多种数据类型进行全文索引。
应用场景
- 自然语言搜索
- 在搜索引擎中,能够确保用户输入的关键词和数据库中的文本内容进行有效匹配
- 文本挖掘
- 处理大量文本数据的时候,能够的帮助挖掘出文本中的隐藏信息,比如说关键词频率、文本主题等
- 信息检索
- 通过全文索引,能够快速检索出与用户查询相关的文档或者记录,提供准确的检索结果
实现方式
- 通过倒排索引实现
10、B+树索引是怎么实现的?详细说一下B+树的实现
基本构成
-
非叶子节点
- 仅仅包含索引
- 关键字在节点中按升序排列
-
叶子节点
- 所有的数据记录或指向数据记录的指针。
- 叶子节点之间通过指针相连,这些指针按照关键字的顺序排列
特点
- 关键字冗余
- 关键字可以在内部节点和叶子节点中重复
- 内部节点中的关键字是分割子树的指标
- 叶子节点中的关键字则指向数据记录。
- 非叶子节点仅仅包含索引
11、MySQL的事务隔离级别有哪几种?
12、默认的隔离级别是哪个级别?解决了什么的问题?是怎么解决不可重复读的问题?
13、缓存用过吗?常用的数据结构有哪些?
- 用过redis
- 常用的数据结构
- string
- set
- zset
- list
- hash
14、分布式锁有用过吗?redis那个命令可以实现分布式锁的功能? 分布式解锁怎么实现?
用过redis
-
最简化的版本Setnx指令
- setnx参数解析
- 如果key不存在,将key设置为value
- 如果key存在,不会有任何操作,返回0
- setnx不具备原子性,无法支持过期时间
- setnx参数解析
-
完备版本set key value nx ex 2 seconds
- nx
- 使得set nx和setnx具有相同的特性
- key存在的时候无操作,key不存在的时候才能设置新值
- 使得set nx和setnx具有相同的特性
- ex过期时间兜底
- ex增加过期时间,超过过期时间就会自动释放锁
- value实现owner
- 通过value来实现owner字段,保证谁加锁,谁释放锁
- nx
分布式锁的解锁功能
- 解锁步骤
- 先检查锁是不是自己的,然后在释放锁,需要具备原子化
- 通过Lua来专门整合原子操作,保证程序执行不会被打断
- 具体执行如下
既然Redis是单线程的,为什么还需要Lua脚本?
- redis执行命令是单线程的,但是在分布式环境中,客户端和redis服务器之间的交互是异步的。
- 客户端再发送多个命令式,这些命令可能被redis以不同的顺序接受或者执行,通过Lua脚本保证多个命令的原子性和顺序性
15、缓存穿透和雪崩是什么概念?怎么解决这两个问题?(穿透和击穿记反了)
缓存穿透
- 缓存和数据库中都没有的数据,而用户不断发起请求。
- 缓存是被动写的,也就是查不到就去数据库查,然后把数据插入到缓存中,现在就是每次都是查缓存,在数据库也查不到,缓存就被穿透了。
- 有人频繁利用这类DB中没有的数据不断访问,系统会崩溃
解决方案
- 接口层校验,对于访存数据做基础校验
- 对于取不到的数据,设置为key-null,并设置有效时间较短,防止用户在短时间内反复用同一个id暴力攻击
- 布隆过滤器,用于快速判定某一个元素是否在数据库中。
- 将字符串通过hash函数映射到不同的二进制位置,并将该位置设置为1
- 空间时间都很小,但是不完全准
缓存雪崩
- 大量的应用请求因为异常无法在Redis缓存中进行处理,像雪崩一样,直接打到数据库上。
- 雪崩的原因
- 数据大批量到过期时间
- 查询数据量巨大,引起数据库压力过大,甚至宕机
解决方案
- 缓存过期时间设置随机,防止同一时间大量数据过期现象发生
- 加互斥锁重建缓存
- 当线程查询缓存发现数据不存在事,加锁,多个线程抢锁,拿到锁的线程查询数据库,重建缓存,失败则循环重试。
缓存击穿
- 缓存中没有,但是数据库中有的数据。
- 某一瞬间并发用户特别多,同时读缓存没有读到数据,又同时去数据库读取数据,压力瞬间增加,崩溃
解决方案
- 热点数据续期,对于持续访问的数据不断续期,避免过期失效被击穿
- 进程加互斥锁,重建缓存
- 线程查询缓存发现缓存不存在,尝试对线程加锁,拿到锁的线程访问数据库,并重建缓存,其他循环重试。
16、加锁之后,其他的流量是等待还是怎么样?
- 对数据库进行加锁,失败之后,其他进程循等待
17、如果数据在DB中不存在,一直访问会怎么办?
解决方案
- 接口层校验,对于访存数据做基础校验
- 对于取不到的数据,设置为key-null,并设置有效时间较短,防止用户在短时间内反复用同一个id暴力攻击
- 布隆过滤器,用于快速判定某一个元素是否在数据库中。
- 将字符串通过hash函数映射到不同的二进制位置,并将该位置设置为1
- 空间时间都很小,但是不完全准
18、如果redis中的数据和DB中的数据不一致怎么解决?
- 这里是建立在数据库修改了,缓存应该怎么做(这样做能够说出来,直接向上面那样问,有点懵逼!)
解答
-
1、仅仅更新MySQL,不管Redis
- MySQL更新时,redis不做处理,等待缓存过期失效,再从MySQL拉取缓存
- 特点
- 开发成本低,易于实现,而且管理成本低
- 脏数据多:
- 完全依赖过期时间
- 时间短,缓存频繁失效
- 时间长,脏数据较多
- 完全依赖过期时间
-
2、更新MySQL之后,删除redis缓存
- MySQL更新时,直接删除在redis中对应的缓存
- 切记不能用修改,会造成数据不一致性
- 特点
- 更新MySQL是,需要额外操作Redis,带来损耗
- 如果MySQL成功了,但是删除redis失败了,就会退化为方案一,存在过多不一致的数据
- MySQL更新时,直接删除在redis中对应的缓存
-
3、订阅服务,更新到redis
- 创建一个新的服务,订阅binlog日志,解析日志的内容,在更新到redis中,实现缓存一致
手撕——合并有序数组
我靠,给我感动哭了,头一次,面试手撕是做简单题的,头一次,真香!
反问
- 后面还有几面
- 两轮技术面
- 部门base在哪里?
- 北京没了,上海成都都还有!
二面
手撕——复原IP地址
- 复原IP地址
- 这个是单纯的DFS,然后一开始白板写的不习惯,面试官也同意使用IDE,不过需要共享屏幕。最后顺利调通了!
八股+项目
0、项目介绍了十五分钟
- 个人介绍
1、MySQL乐观锁会带来什么问题?
- 乐观锁适用于读多写少的情况,如果发现数据不匹配,会进行数据回滚,降低操作系统的性能。
2、怎么实现分布式锁的?
-
通过redis来实现分布式锁,在服务器端使用jedis客户端实现,主要是通过如下命令
-
完备版本set key value nx ex 2 seconds
- nx
- 使得set nx和setnx具有相同的特性
- key存在的时候无操作,key不存在的时候才能设置新值
- 使得set nx和setnx具有相同的特性
- ex过期时间兜底
- ex增加过期时间,超过过期时间就会自动释放锁
- value实现owner
- 通过value来实现owner字段,保证谁加锁,谁释放锁
- nx
3、一百万个数据,你怎么修改?失败了怎么办?怎么设计?
数据是存在数据库,并且一百万个数据都需要修改
使用事务:
- 确保修改操作在事务中进行,以便在出现错误时能够回滚到修改前的状态。
分批处理:
- 由于数据量庞大,直接一次性修改一百万条数据可能会导致数据库性能下降甚至崩溃。可以将数据分批处理,每批处理几千到几万条数据。
优化查询:
- 确保用于定位需要修改的数据的查询是高效的,可以考虑使用索引来加速查询过程。
结果
- 没想到通过了,真的蛮意外的,在九月之前有一个保底的Offer成就,近似达成了!我靠,好不容易呀!
HR面
总结
- 没想到的!
9/2
- 人生就是这么多意外,四天没约HR面试,然后自动回到人才库,然后光速被其他部门约了,不知道还能不能,被原来的部门捞起来,不知道呀!
- 能试的办法都试了,只能等等人家给我回信了!流程推进真的很费劲!找个工作真的是不容易,不容易,总是遇到各种各样的问题!没有一次是平稳着陆的!好事多磨,好事多磨,在等等吧!
9/3
- 美团已经面过了,二面也过了,但是没有约HR面,直接超时,回到了人才库,离谱!只能重打复活赛了!