赞
踩
注:部分图片来自网络,如侵必删!
自我介绍:在这次自我介绍中,不仅是心态上,还是语言表达上,都比一面时要进步很多。
这次面试过程中,面试官倒是直接提示:结合你的技术解决了什么问题来说
由于上次一面已经回答过一次这个问题了,所以这次更得心易手,顺便结合了更多遇到的问题
面试官问我这个问题,大概是因为上次一面的时候,我没有回答出吧
那天笔者回去之后又仔细研究了一下 Redis,可是 Redis 的五种基本数据结构和一面时回答的没有问题,即string、list、hash、set、zset 这五钟,以及最后额外补充了一下 bitmap
bitmap 是我故意引出来的,因为笔者刚好前几天了解了一下 bitmap 的使用以及应用场景等等,最后也证实引入 bitmap 是一个正确的选择。
在本次问题中,面试官主要是追着业务场景进行追问
如,BitMap 可以做什么?朋友圈点赞等功能。
在朋友圈点赞数,如何统计热点数据:用该用户 ID 作为 key,把点赞的 ID 作为 offset,最后使用 bitcount 进行统计。
在海量的数据上,你会如何处理:这里回答的不是很好。
redis 实现排行榜:由于笔者对 Redis 的理解不够深入,所以,在这道题上我回答不出来。我向面试官重述一遍问题的时间里(就是给自己多一点时间思考其他的解决方案),突然想到了另一种和关系型数据库有关的解决方案,详细细节见下文。
等等
BitMap 的基本思想就是用一个 bit 位来标记某个元素对应的 value,而 key 即元素。由于采用了 bit 作为单位来存储数据,因此使用 BitMap可以大大节省地节省存储空间。
BitMap 并不是一种数据结构,实际上它就是字符串,但是可以对字符串的位进行操作,可以把 BitMap 想像成一个以 bit 为单位的数组,数组的每个单元存储 0 和 1,数组的下标叫做偏移量。
通过 bitcount 可以很快速的统计,比传统的关系型数据库效率高很多
比如统计年活跃用户数量
用用户 ID 作为 offset,当用户在一年内访问过网站,就将对应的 offset 的 bit 值设置为 “1”
通过 bitcount 来统计一年内访问过网站的用户数量
比如统计三天内活跃用户数量
时间字符串作为 key,比如 ”20220323:active“、”20220324:active“、“20220325:active“;
用户的 ID 就可以作为 offset,当用户访问过网站,就将对应的 offset 的 bit 值设置为 “1”
统计三天的活跃用户,可以通过 or(也就是 “或” 运算) 进行计算,bitop or
连续三天访问的用户数量,可以通过 and (也就是 “且” 运算) 进行计算,bitop and
三天都没有访问的用户数量,可以通过 not (也就是 “非” 运算) 进行计算,bitop not
BitMap - Redis 布隆过滤器(应对缓存穿透问题)
什么是缓存穿透?
- 一个查询请求过来,先去访问 Redis,发现 Redis 不存在
- 查询数据库,而数据库也查询不到数据,则不写入 Redis
- 下一次请求继续循环…
这种情况,由于 Redis无法缓存数据,导致每次请求都会直接到数据库,数据库压力剧增,导致宕机
处理方案1:保存 key,value 为 null
处理方案2:布隆过滤器
通过对目标数据的表示 hash 为位的下标,目标数据存在则 1,不存在则 0
注意事项:
布隆过滤器的重复率依靠的是 hash 算法,所以越完善的 hash 算法,分配的数据越均匀,冲突率越低。
由于笔者对 Redis 的理解不够深入,所以,在这道题上我回答不出来。我向面试官重述一遍问题的时间里(就是给自己多一点时间思考其他的解决方案),突然想到了另一种和关系型数据库有关的解决方案,就如下回答:因为最后所有的数据都是要保存进数据库里,所以我们可以在数据库中执行 select top … sorted by … asc 进行查询得到排行榜数据。
结果果不其然,面试官直接给我把问题提升到了海量数据,如何处理。遇到这种问题,我直接条件反射的说到了索引、分库分表。但是面试官说如果分库分表之后,ID 重构问题,这个问题把我问懵住了(其实可以用雪花算法,就可以避免 ID 重构问题)。
最后我只好回答:这个问题,我不知道解决,可以请教面试官会如何解决这种问题吗?
!!!斯,当时我也不知道为什么我要去问这个问题,哈哈哈哈哈哈。但是我说我不会之后,面试官似乎没有听到,要我重说一遍,我想着:没听到就算了吧,当然最后面试确实是给了我思路:用 Sorted Sets。(这个一开始是有想法的,只是当时的问题是围绕着 BitMap 展开的,所以我以为必须要使用 BitMap 去解决这个业务问题)
sorted set 与 set 结构一样,都不允许重复的元素,但是与 set 不同的是 sorted set 除了 member(元素)之外,每个 member 都会关联一个分数 score。sorted set 根据 score 对元素进行升序排列,如果有多个元素的分数相同,那么按照 member 的字典升序排列,sorted set 中元素不允许相同,但 score 允许相同
sorted set 有两种实现方式,一种是 ziplist 压缩表,一种是 zset(dict、skiplist),redis.conf 有两个配置来控制,当 sorted set 中的元素小于 128 时(即元素对 member score 的个数,共 256 个元素),使用 ziplist,若 ziplist 中所有元素的总长度超过 64 字节时使用 zset
ziplist 是一个双向链表按照 score 升序排列,当插入一个(member score)对时,ziplist 中插入两个数据项,数据在前,score 在后。ziplist 只能顺序(正 逆)查找,每一步前进两个数据项(member score)
该算法题,就是寻找一个无序数组里,第 N 大的数据(含重复数据)
也就是 [7, 6, 9, 10, 10, 3, 6] 3
返回 9
在阅读完题目之后,我就知道这个算法题是很简单的,只需要排序就可以了,当然如果是简单的冒泡排序肯定会给面试官留下一个很差的印象,所以我打算手写 快排。
当我把 快排 的整体代码思路写好之后,想着:我想把题目 ac 之后,再考虑用自己的 快排吧,因为在 java.util.Arrays 类中为我们提供了一个 sort 方法。但最后,我 ac 之后,面试官就不要我继续写下去了,我只好给他讲一下快排的思路加点印象分。
public class Solution { /** * 本题就比较简单,只需要将无序数组排序之后,返回 n - N 下标的数即可 */ public int methods(int[] a, int N) { int n = a.length; // Arrays.sort(a); sort(a, 0, n - 1); return a[n - N]; } private static void sort(int[] nums, int left, int right) { if(left > right){ return; } int i = left; int j = right; int value = nums[left]; // 基准 while (i < j) { while (value <= nums[j] && i < j) j--; while (value >= nums[i] && i < j) i++; if (i < j) { int temp = nums[j]; nums[j] = nums[i]; nums[i] = temp; } } nums[left] = nums[i]; nums[i] = value; sort(nums, left, j-1); sort(nums, j+1, right); } }
略
本次面试主要分为两大模块:业务模型、算法题
总体上比较轻松,这里要大大地夸一下美团的面试官!!!人太好了,不管是一面的,还是二面的,都尽力包容我的不足,给我充分的自信去展示自己的优点。但这次面试过程中,还是有比较不满意的地方:感觉没有展示出我的优势或者说特长。
为什么这么说呢?
一是在业务处理,这一块呢,我提出的方案不够好,并且犹犹豫豫的,给面试官一个不好的感受;二是,算法题比较简单,唯一可能可以体现出我的算法能力的就是快排,但是也没有机会写出来,虽然面试结束后做了出来,但心里还是比较落空空的,没有实感。
总结这次面试,我是有一定的运气成分在的。原因是,在面试的前一天,我恰好因为一面 Redis 回答的不够好,又认真的学了一下,最后证实确实是有效地。哈哈哈,但这不能成为我技术差、对 Redis 理解不够深入的理由。所以还是要好好继续学习!!希望能够收到三面通知,并这次面试之后,继续进步!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。