大数据算法2

你见过什么什么热搜么,请问怎么实现

    几个热搜榜的实现都差不多。输出都是要显示一段时间内、一定条件下的前几名搜索词。输入应该是一段时间内、一定条件下的所有搜索词
    主要工作就是从所有搜索词中输出前几名的搜索词
    面试时要说的工作:
    第一步:计数-依次读入每个搜索词,统计出现次数;
    第二步:排序-对于(搜索词,计数) 二元组,根据计数来排序
    第三步:返回排序结果前几名
    这个是最初的想法,可以解决部分问题,是否符合咱们的实际情况,可以进一步分析
。

    如果面试官现场要代码:
        Linux:cat log.txt|sort |uniq -c | sort - nr | head -n 10


进一步分析:
    假设,有n个搜索词,有m次新搜索要计数
    第一步:依次读入每个搜索词,统计出现次数
        空间复杂性:n+m
        时间复杂性:(m*log(m)+n*log(n))

    散列:
        时间复杂性:m*logm > m

这里写图片描述

散列的概念(hash)

经典概念:散列函数
更常见的概念:一下2者的统一
1、一一比较 -> O(1)时间的索引//顺序访问-> 随机访问
2、通过"散列函数",过大的索引存储空间->可存储的索引存储空间

散列的核心价值

查找、访问的时间:O(n) ->O(1)

散列函数

过大的索引存储空间 -> 可存储的索引存储空间
Y = 散列函数(X)

好的散列函数

人的信息 --> 名字  重名不多
人的信息 ---> 你我他 重名太多

如果以人 ---> 名字为散列函数,因为没有重名,所以秒查
如果以人 ---> 你我他为散列函数,YY,Frank,68同学都成了"他"

重名(碰撞)怎么办?–数组 链表 hash

Java里HashMap的核心部分的实现的伪码

class 散列表
    数据:
        散列表数组[{关键词,数据}]//散列值就是散列表数组的下标
    函数:
        散列值  散列函数(关键词)//假设已经有完美的散列函数,空间够用,没有碰撞:
        数据 查找(关键词){
            散列值=散列函数(关键词)
            return 散列表数组[散列值].数据
        }
        更改(关键词,新数据){
            散列值=散列函数(关键词)
            散列表数组[散列值].数据=新数据
        }

回到热搜的例子

伪代码
    //热搜散列表<搜索词,技术>
    例子第一步(热搜散列表,所有的新搜索词)
        For(每个新搜索词)
            if(热搜散列表.查找(新搜索词)==null)//get
                热搜散列表.更新(新搜索词,1)
            else
                热搜散列表.更新新搜索词,热搜散列表.查找(新搜索词)+1)


代码
    static void 例子第一步 (Map<String,Integer> 热搜,String 搜索词日志){
        while(新搜索词=搜索词日志.readLine() != null){
            if(热搜.get(新搜索词)==null)
                热搜.put(新搜索词,1);
            else
                热搜.put(新搜索词,热搜.get(新搜索词)+1);
    }
}


}

时间复杂性  m*lgm - m

散列是空间换时间
思路:大事化小,更具体的方法:复杂问题化简
我们学过找最大值(或最小值),好像复杂性低一些。。。
找最大值的(时间)复杂性是多少呢? n
那如果找最大的2个数呢?
1、先找最大的:时间复杂性 n
2、再找第2大的,时间复杂性还是n
因为热搜只是前k名,所以时间复杂性是k*n.

复杂性m+n的算法

这里写图片描述

鹅肠面试题

42亿条qq,给你4G内存,在O(1)复杂度找出某条qq信息,请给伪代码和代码?

解决1、把散列表放磁盘里
n*n/100条 (n=4亿条左右),有足够的硬盘,但是为了保证效率,必须在内存中使用散列表。

n字节的内存

把第一次散列的散列表读入内存
做第一次散列:所有qq消息散列大小为n/100的空间,必然会发生好多碰撞,比如说某消息第一次散列值为i;把第二次散列用的,索引为i的散列表读入内存,做第二次散列。

什么是二次散列

这里写图片描述

快速排序和合并排序的时间的复杂性是nlogn

冒泡排序的时间的复杂性是n^2
n*n/100条(n=4亿左右),有足够的硬盘,但是为了保证效率,必须在内存中使用散列表。

n字节的内存

做第一次散列:所有与qq消息散列到大小为n/100的空间,必然有好多碰撞,比如说某消息第一次散列值为i
把第二次散列用的,索引为i的散列表读入内存,做第二次散列

QQ消息--> 存在/不存在

//已知
//第一次散列:有一张散列表:
    关键词(key):原QQ消息
    数据(value):1-4百万之间的一个值,这个值被用作第2次散列时,标识从硬盘读哪张散列表。
//第二次散列:其实有大约4亿/100=4百万张散列表,存在硬盘里。根据第一次散列的结果取出相应的表,来进行第2次散列。
    关键词(key):原QQ消息
    数据(value):原QQ消息存在/不存在。
//把第一次散列的散列表读取内存
i=第一次散列表.散列函数(关键词)
//把第二次散列用的,索引为i的散列表“第二次散列表i”读入内存
散列值2=第二次散列表i.散列函数(散列值1)


猜你喜欢

转载自blog.csdn.net/weixin_37243717/article/details/80066223