标签:false 操作系统 分布 散列 简单 最大的 key htm str
搜索引擎的实现,会用到哪些重要的数据结构
https://www.cnblogs.com/Leo_wl/p/5470570.html
搜索引擎的索引其实就是实现单词-文档矩阵的具体数据结构。单词-文档矩阵从纵向看,可以得知每列代表某文档包含了哪些单词;从横向看,每行代表了哪些文档包含了某个单词。倒排索引是单词到文档映射关系的最佳实现方式。
单词词典:文档集合中出现过的所有单词构成的字符串集合,单词词典内每条索引项记载单词本身的一些信息(唯一单词ID等)及指向倒排列表的指针。单词词典用来维护文档集合中出现过的所有单词的相关信息,同时用来记载某个单词对应的倒排列表在倒排文件中的位置信息。在查询时到单词词典里查询,就能获得相应的倒排列表,并以此作为后序排序的基础。常用数据结构:哈希加链表和树形词典结构。
哈希加链表词典结构的主体是哈希表,每个哈希表项保存一个指针,指针指向冲突链表,相同哈希值的单词形成链表结构。构建过程:对文档进行分词;对于做好的分词,利用哈希函数获取哈希值;根据哈希值对应的哈希表项找到对应的冲突链表;如果冲突链表已经存在该单词不处理否则加入冲突连表。
树形词典结构:使用B树或者B+树的结构。与哈希表不同的是,需要字典项能按照大小排序,即 使用数字或字符序。树形结构中,使用层级查找,中间节点保存一定顺序范围的词典项,最底层的叶子节点存储单词的地址信息。
倒排列表:倒排列表用来记录哪些文档包含了某个单词。倒排列表由倒排索引项组成,每个倒排索引项由文档ID,单词在文档中出现次数TD,单词在文档中哪些位置出现过等信息。包含某单词的一系列倒排索引项形成了某个单词对应的倒排列表。
建立索引:可以使用两遍遍历文档的方法在内存里完成索引的创建。要求内存要足够大。第一遍遍历收集一些全局的统计信息。包括文档集合包含的文档个数N,文档集合内所包含的不同单词个数M,每个单词在多少个文档中出现过的信息DF。
将所有单词对应的DF值全部相加,就可以知道建立最终索引所需的内存大小是多少。获取信息后,根据统计信息分配内存等资源,同事建立好单词相对应倒排列表在内存中的位置信息。第二遍遍历逐个单词建立倒排列表信息。获得包含某个单词的每个文档的文档ID,以及这个单词在文档中的出现次数TF,然后不断填充第一遍扫描时所分配的内存。当第二遍扫描结束的时候,分配的内存正好被填充满,每个单词用指针所指向的内存区域“片段”,其起始位置和终止位置之间的数据就是这个单词对应的倒排列表。
设计实现一个HTTP代理服务器
基本原理:代理服务器作为真实服务器的一个代理端,客户端的请求信息不是直接发送到其真实请求的服务器而是发送到代理服务器,此时代理服务器是作为一个服务器,之后代理服务器通过解析客户端的请求信息,再向真实服务器发送请求报文,获得请求的信息,此时代理服务器是作为一个客户端。
使用代理服务器的好处是:1. 在请求客户端和真实服务器之间添加了一层,这样就可控的对于请求的响应报文做一些限制或者是改变,例如网站过滤、钓鱼网站等,使得响应到客户端的信息是代理服务器处理过的;2、还有就是请求报文先发送到代理服务器,这样代理服务器可以设立缓存,通过对请求报文解析后代理服务器可以通过查找本地缓存,如果有缓存好的,并且通过向服务器发送是否更新的信息后得到没有修改后就可以直接从代理服务器将响应报文返回给客户端,这样减少了服务端的负载,减少了流量。
https://blog.csdn.net/rocketeerLi/article/details/83717613
实现一个web服务器
以FTP服务器为例
首先创建一个服务器socket,然后bind地址,listen监听,然后把socket加入多路转接监听链表。当有连接到达的时候,我们对socket调用accept,返回一个已连接套接字描述符,然后根据用户传输过来的文件名去查找文件,读取文件内容并回送给用户。
accept之后创建一个线程,如果使用线程池的话就从池中取一个空闲线程,然后把已连接文件描述符传给这个线程,然后让线程去处理这个用户请求,一个线程处理一个用户请求。
设计一个cache缓存web服务器的网页访问记录,该如何实现这个数据结构?
用队列,根据last visited排序,先进先出;队列每一个元素包含键值两部分,值就是访问的记录。再用一个hash表保存键值,这个值呢是指向队列元素的指针。
把一个文件快速下发到100w个服务器(不会)
(面试官之后说你可以想想迅雷是怎么做到下载速度那么快的)
树状: 1. 每个服务器既具有文件存储能力也应具有文件分发能力。
2. 每个服务器接收到文件之后向较近的服务器分发,具体类似多叉树,应该挺快的。
索引状:1. 设置1000个缓存服务器,文件先下发到这些缓存上。(具体多少缓存、分几层缓存和具体业务有关。) 2. 每个缓存服务器接收1000个服务器取文件。
将微信用户分为两组,组内的微信用户互相不为好友;用并查集
我当即说出来逐次探测,又被逼问时间复杂度,O(n2)
dfs:微信用户之间的关系图包含很多连通分量的无向图,保存原始关系图G0(邻接矩阵)。拷贝一份可以修改的关系图G1,遍历图G1中每个节点并标记,若节点没有边,则不处理;若节点只有一条边,则将该节点的唯一邻接节点在G0中查找它的所有邻接节点,若hashmap中已有该节点或者有该节点的邻接节点,返回false;否则在图中将该节点的所有边断开,将该节点加入hashmap中;若节点只有多条边,则对该节点自身做上述处理;程序到最后则返回true;还可以用并查集
并查集:
Pre[100],initial(int n),find(int x),unite(int x,int y)
https://blog.csdn.net/hlk09/article/details/81462771
朋友之间的点对点关系用图维护,怎么判断两人是否是朋友;求朋友圈的个数
Dfs 并查集,
http://www.cnblogs.com/grandyang/p/6686983.html
XX市有多少钢琴调音师傅?(费米问题)
首先从XX市有多少台钢琴开始,其次弄清楚需要多少调音师才能让这些钢琴保持音准。先列出一些知道的数据,然后是一些假设:
一、钢琴需要多久进行一次调音
二、为一台钢琴进行调音需要多长时间
三、一位钢琴调音师一年平均工作多少小时
四、纽约有多少架钢琴
范围1到1000的数,原本有1000个,互不重复,现多出来1个重复的数,怎么找到它
解答:求和相减,把给定的 1001个数相加的和减去(1+2+…+1000)即可得到答案。
1-100顺序排列,丢失了一个怎么找到(二分法)
二分法,比如第一次的话,你取arr[50],看看是不是50,如果是,说明缺失的数在后面,如果是49,则缺失的数在[0-49]位置,包括49,依次类推即可
先手必胜策略问题:n本书,每次能够拿X-X本,怎么拿必胜,拿到最后剩下的算胜利。
N个糖果,每次只能取1个到6个,不能不取,你先取,请问是否有必胜策略,怎么取。
每次取到只剩7的倍数个糖果即可。因为剩下的为7的倍数时可以保证对方不能一次性取完。当取到最后剩下7个时,对方不能取完,然后自己可以取完。
第一个人摆在正中心(同心圆),然后不管第二个人怎么摆,第一个人都和他玩中心对称。
一个矩阵,从左上角到右下角,每个位置有一个权值。可以上下左右走,到达右下角的最短路径怎么走。
如果只可以向右和向下走可以考虑dp
本题中,可以dfs递归实现。面试官说要优化。说了一下用迪杰斯特拉的思路,说可以。
迪杰斯特拉:https://blog.csdn.net/chen134225/article/details/79886928
四辆小车,每辆车加满油可以走1公里,车子之间可以互相加油,问怎么能让一辆小车走最远。说了好几种方案,面试官引导我优化了一下,但是还是不满意,最后他说跳过。
答:四辆车跑1/4*1公里的时候,把其中一辆车的油分给其他三辆车,此时其他三辆车都满油,抛弃分油车;三辆车继续跑1/3*1公里的时候,把其中一辆车的油分给其他两辆车,此时其他两辆车都满油,抛弃分油车;两辆车继续跑1/2*1公里的时候,把其中一辆车的油分给另一辆车,此时最后1车满油,抛弃分油车,最后一辆车继续跑1公里;
最远跑(1/4+1/3+1/2+1)*公里。
秒杀系统的架构设计
https://blog.51cto.com/13527416/2085258?cid=700792
两个大文件存url,找相同url ,两个50亿url文件,找到相同url,内存4g
如何判断一个图是否连通?(开始说DFS,面试官说不满意,后来说并查集)
图的遍历方法有dfs,bfs先遍历一遍图,判断是否所有的节点都遍历到
并查集的方法合并节点,最后数一共有多少集合,如果集合是1,证明连通。
洗牌发牌算法。 说了两种办法
答:1. 每次从未处理的数据中随机取出一个数字,然后把该数字放在数组的尾部,即数组尾部存放的是已经处理过的数字。这是一个原地打乱顺序的算法,算法时间复杂度O(n)。python的shuffle实现方式。
采用分页法,1MB的内存,每4KB为单位进行,设置一个映射表,非连续性分配。
最坏的情况,只有一个4KB产生碎片。
用bitmap(位图);
根据待排序集合(QQ号)中最大的数,开辟一个位数组,用来表示待排序集合中的整数;待排序集合中的所有数字在位数组中的对应位置置1,其他的置0;
排序过程:将所有的位都置为0;通过读入文件中的每个QQ号检验每一位,如果该位为1,输出对应的整数。,将每个对应的位都置为1;
位图排序时,我们需要考虑:给出一个数,如何找到其对应位图的位置,方法就是首先找到该数对应的字节,然后在找到该数对应的位。例如一个QQ号是:983262245,则将bit的98326625位进行标记。bitset是C++提供的一种位集合的数据结构,它让我们可以像使用数组一样使用位,可以访问指定下标的bit位。因此将通过bitset容器进行存储42亿个qq号码。由于一个字节可以存放8个QQ号码,则4000000000/8/1014/1024 = 500.679Mb,内存合适,通过bit位下表来判断QQ号码是否存在。
bitset<40亿> bit;// 40亿的位图 bit.set(63834199);//将QQ号放入位图对应的位置中 bit.test(qq) 测试qq号是否存在。
https://blog.csdn.net/hpugym/article/details/80008946
蚂蚁爬杆:n只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行。当蚂蚁爬到竿子的端点时就会掉落。由于竿子太细,两只蚂蚁相遇时,他们不能交错通过,只能各自反向爬回去。对于每只蚂蚁,我们知道它距离竿子左端的距离为Xi,但不知道它当前的朝向,请计算所有蚂蚁落下竿子所需的最短时间和最长时间。
最短时间:如果每只蚂蚁一开始就向着距离自己最近的竿子那一端爬,具体来说,在坐标0~L/2之间的蚂蚁朝着左端爬,L/2~L之间的蚂蚁朝着右端爬,那么蚂蚁之间就不会相遇(因为蚂蚁的速度是一样的)。所以在所有蚂蚁都处于自己最短的时间中只需要取出用时最长的那一个时间作为最终整体的最短用时即可。
最长时间:对于最长时间,得考虑相遇,因为只有不断相遇,不断折返,才能增加蚂蚁的爬行时间;但是如果我们可以不考虑蚂蚁的身份,将所有蚂蚁都视作相同无差别的,相当于每只蚂蚁是独立运动的,每次遇到别的蚂蚁后,就是变身一次而已,并不会影响其运动方向与轨迹。这样的话,求整体最长时间,就只需要求每只蚂蚁最长使用的情况下的最大值即可。
从50亿的整数集合里找出中位数.
这里我说出来了两种方法. 分治法 和 位图法
高德地图是怎么知道高速路哪里堵车了,并且还能标记出来准确的路段? 提出你的设想.
通过用户终端反馈的数据进行分析的。汽车的导航、手机用的导航等等,都会定时往服务器上传数据,后台通过你通过该段距离所用的时间,来进行判断是否拥堵。
问微信的朋友圈数据在后台应该怎么存放,主要要考虑的存放和读取(你朋友读取),不是系统设计,主要问你用的存储结构就行。
朋友圈用hash表和stack保存,每次更新后你朋友的数据那里会有一个queue去保存你这个新的朋友圈的信息。
如果采用LRU的方法,QQ用户的数据在后台存放管理?
我的理解就是理解成怎么实现对内存里的进行LRU。刚开始的想法有些漏洞,后来自己改进加面试官稍微提醒了一下最后结果感觉他还是比较满意的。
用hash表和链表结合,hash的key用时间结点,这样就能保证查询和插入删除操作都不会特别耗时。再次重申不一定是正确答案,你可以找其他大佬商量探讨
给定两个线段的端点坐标,如何判断它们是否相交。(用向量叉乘)
http://acm.hdu.edu.cn/discuss/problem/post/reply.php?postid=32179&messageid=1&deep=0
你觉得王者荣耀是基于TCP还是UDP,为什么?(其实答案是有安全保障的UDP,楼主答上了是这个)然后问道具体怎么设计的。(答得不太好)。
TCP使用场景:当对网络通信质量有要求时,比如:整个数据要准确无误的传递给对方,这往往对于一些要求可靠的应用,比如HTTP,浏览器,QQ文件传输;
UDP使用场景:对当前网络通讯质量要求不高的时候,要求网络通讯速度尽量的快,实时,这时就使用UDP ,如QQ语音,QQ视频,王者荣耀。
一个5L的桶子和6L的桶子,打出3L水
用装满水的5L倒进6L里,此时6L里还能装1L水,将5L再装满,倒进6L里,5L只能倒进1L,所以还剩下4L,同理,倒空6L,将剩余的4L倒入,再将5L装满,倒入6L里,由于6L只能再装入2L的水,所以,此时5L剩余部分为3L
要是设计一个高并发服务器,可以从哪些角度去优化。
https://blog.csdn.net/belalds/article/details/81106866
场景题:现在要完成一个微博评论的部分,想在用户进入新闻时优先看到自己好友对此新闻的评论,好友可能有多条评论,怎么设计结构。微博新闻评论设计
每一条新闻对应一个map<int,vector<int>>,key是用户id,value中包括了这个用户所有评论在新闻中的位置。每一条新闻对应一个hashmap存放新闻中的评论位置和评论内容,当前用户访问时,对他的每一个好友id在map里面查找,并对应显示。感觉面试官还比较满意,不过忘记说应该有评论和评论id的对应了,可能关系不大。
假如有一亿QQ用户,每个用户都有500好友,每个人都可能玩很多腾讯出的游戏,问如何存储能使获取一个人的好友玩的游戏列表。
用key-value存储,bitmap。使用memcached或redis, redis与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
1000w(L)个整数排序,范围0到100w(S),8g内存
计数排序 时间:O(1000W+100W) 空间:O(100w)
首先需要两个辅助数组,第一个数组A要记录最终排好序的输出数列(输出数组),大小为n;第二个数组B要记录比某个数小的其他数字的个数,大小应当为K;
1、扫描整个集合S,对每一个Si∈S,找到在线性表L中小于等于Si的元素的个数T(Si);
2、扫描整个线性表L,对L中的每一个元素Li,将Li放在输出数组的第T(Li)个位置上,并将T(Li)减1。
设计题,给每个组分配不同的IP段,怎么设计一种结构使的快速得知IP是哪个组的(想用Trie树,面试官让我再优化一下。使用hash,取得ip地址的网络号,使得同一组的ip地址hash值相同。
设计一个类似搜索扣扣好友列表,例如输入a显示前缀为a的所有好友,我说对好友列表用字典树Trie树排序,然后面试官说如果给搜索字段很长的话性能不好,然后我说了用文件索引,然后查找索引。
Trie,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种前缀的字符串。
十亿个ip地址排序.
之前在网上查了腾讯很喜欢问这种题目,主要是map reduce和bitmap两种思路去答就可以了.(bitset)
问题:依次访问完一串页面 a-b-c 之后,点击浏览器的后退按钮,就可以查看之前浏览过的页面 b 和 a。当你后退到页面 a,点击前进按钮,就可以重新查看页面 b 和 c。但是,如果你后退到页面 b 后,点击了新的页面 d,那就无法再通过前进、后退功能查看页面 c 了。
解答思路:1. 使用两个栈,X 和 Y,把首次浏览的页面依次压入栈 X,当点击后退按钮时,再依次从栈X中出栈,并将出栈的数据依次放入栈 Y。点击前进按钮时,依次从栈 Y 中取出数据,放入栈 X 中。当栈 X 中没有数据时,那就说明没有页面可以继续后退浏览了。当栈 Y 中没有数据,那就说明没有页面可以点击前进按钮浏览了。
2. 通过页面 b 又跳转到新的页面 d 了,页面 c 就无法再通过前进、后退按钮重复查看了,所以需要清空栈 Y。
https://www.cnblogs.com/wuyepeng/p/9740963.html
创建两个Map,一个(ipMap)用来存放用户Ip和访问次数,访问时间等主要信息,另一个(limitedIpMap)用来存放被限制的用户IP。Map的key为用户的IP,value为具体内容。当用户访问系统时,通过IPFilter检查limitedIpMap中是否存在当前IP,如果存在说明该IP之前存在过恶意刷新访问,已经被限制,跳转到异常提示页面;如果limitedIpMap
中不存在则检查ipMap中是否存在当前IP,如果ipMap中不存在则说明用户初次访问,用户访问次数+1,初始访问时间为当前时间;如果存在则检查用户访问次数是否在规定的短时间内进行了大量的访问操作;如果是,则将当前IP添加到limitedIpMap中,并跳转到异常提示页面,否则不进行操作,直接放行本次请求。
Trie字典树+堆(Top K)吧,然后balabala(第三次。。。感觉面试官不是很满意我的答案)
https://www.cnblogs.com/chenyang920/p/5940190.html
用trie字典树存储大量字符串,以用户输入为前缀,前缀固定时,存储相对来说比较热的后缀。那又如何统计热词呢? TOP K算法统计热词。
最大的前 20 个:建立小顶堆,先拿20个数建堆,然后依次添加剩余元素,如果大于堆顶的数(20最小的),用这个数替换堆顶,并调整结构使之仍然是一个最小堆,这样,遍历完后,堆中的20个数就是所需的最大的20个。建堆时间复杂度是O(logK),算法的时间复杂度为O(nlogK)(n为1亿,m为20)。
注:如果数据量大的时候,可以先将数据根据哈希算法打散到各个小文件。每个小文件里,进行同样的操作。接着再把所有小文件的前20个取出。效果应该同理吧。
只要第二十个:利用快速排序;
字符串排序,我采用的是哈希切分,打散至小文件。接着多路归并。
(将大文件切割成小文件,每个小文件内归并排序;对所有的小文件进行归并排序——多重归并排序)
Bitmap、Bloom过滤器
将文件通过哈希函数散列成多个小的文件,由于哈希函数所有重复的URL只可能在同一个文件中,在每个小文件中利用一个哈希表做次数统计。就能找到重复的URL。这时候要注意的就是给了多少内存,我们要根据文件大小结合内存大小决定要分割多少文件;本题中分割成4个文件
把一个红球单独放到一个盒子,另外49个红球和50个篮球放在一个盒子,0.75
函数返回true与false概率不同,但是函数两次返回为tf与ft的概率是一样的。如果返回结果是tt或ff那么继续调用两次。直至出现tf或ft
微信的附近的人这个功能,如果让你实现,你准备怎么做,
地理位置网格分块,存块ID,然后四叉搜索。你的经纬度换算成网格ID,同网格的人撸出来,临近网格的人撸出来,搞定。把地理位置分块,怎么把经纬度转化成网格 ID 呢。本质上就是hash
客户端固定时间发送经纬度(x,y)到服务器s,服务器存储每个登陆的用户的经纬度到表t中,表t按照经纬度分表,将地图分成一个个的小格子。当用户点击“附近的人”时,对用户(x,y)进行计算,最多一次查询其中的4个格子(子表),计算两点间距离获取结果(有点像桶排序)。性能上可以将表t替换为内存结构,容灾即可。
从实际的微信提供的功能来看,附近的人并不太多,估计是其对地图划分的格子很小。
MongoDB的LBS功能实现附近的人
https://www.nowcoder.com/discuss/165952?type=0&order=0&pos=414&page=1
如何设计一个好的字符串hash函数
对于一个Hash函数,评价其优劣的标准应为随机性或离散性,即对任意一组标本,进入Hash表每一个单元(cell)之概率的平均程度,因为这个概率越平均,两个字符串计算出的Hash值相等hash collision的可能越小,数据在表中的分布就越平均,表的空间利用率就越高。
C++ 11 定义了一个新增的哈希结构模板定义于头文件 <functional>:std::hash<T>,模板类,(重载了operator()),实现了散列函数: unordered_map和unordered_multimap 默认使用std::hash; std::hash;实现太简单
同时,C++ STL 里面实现了一个万用的hash function 针对任何类型的
boost::hash 的实现也是简单取值。
DJBHash是一种非常流行的算法,俗称"Times33"算法。Times33的算法很简单,就是不断的乘33,原型如下:
hash(i) = hash(i-1) * 33 + str[i],Time33在效率和随机性两方面上俱佳
https://blog.csdn.net/g1036583997/article/details/51910598
标签:false 操作系统 分布 散列 简单 最大的 key htm str
原文地址:https://www.cnblogs.com/wangxf2019/p/12089584.html