• 常见算法整理(二)


    1、从300万字符串中找到最热门的10条

    搜索的输入信息是一个字符串,统计300万输入信息中的最热门的前10条,我们每次输入的一个字符串为不超过255byte,内存使用只有1G。请描述思想,写出算法(c语言),空间和时间复杂度。

    255字节*300万=7,5500,0000字节=755,000K=755M=0.75G
    所以完全可以放入内存处理,建立一个字符串的Hash数组,然后遍历所有字符串,相应的加一处理,然后排序即可,算法负责度极为O(n)

    2、如何找出字典中的兄弟单词。给定一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的兄弟单词。现在给定一个字典,用户输入一个单词,如何根据字典找出这个单词有多少个兄弟单词?

    首先定义一个key,使得兄弟单词有相同的key,不是兄弟的单词有不同的key。例如,将单词按字母从小到大重新排序后作为其key,比如bad的key为abd,good的key为dgoo。
      使用链表将所有兄弟单词串在一起,hash_map的key为单词的key,value为链表的起始地址。
      开始时,先遍历字典,将每个单词都按照key加入到对应的链表当中。当需要找兄弟单词时,只需求取这个单词的key,然后到hash_map中找到对应的链表即可。

    3、找出数组中出现次数超过一半的数,现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数。

    答案1:
      创建一个hash_map,key为数组中的数,value为此数出现的次数。遍历一遍数组,用hash_map统计每个数出现的次数,并用两个值存储目前出现次数最多的数和对应出现的次数。
      这样可以做到O(n)的时间复杂度和O(n)的空间复杂度,满足题目的要求。
      但是没有利用“一个数出现的次数超过了一半”这个特点。也许算法还有提高的空间。
    答案2:
      使用两个变量A和B,其中A存储某个数组中的数,B用来计数。开始时将B初始化为0。
      遍历数组,如果B=0,则令A等于当前数,令B等于1;如果当前数与A相同,则B=B+1;如果当前数与A不同,则令B=B-1。遍历结束时,A中的数就是要找的数。
      这个算法的时间复杂度是O(n),空间复杂度为O(1)。
    1 2 1 3 1 5 4 1 1 1 1 8 9
    b=0 b=0 b=0 b=0 b=0 b=0 b=0 b=0 b=1 b=2 b=3 b=2 b=1
    a=1 a=2 a=1 a=3 a=1 a=5 a=4 a=1 a=1 a=1 a=1 a=1 a=1

    4、找出被修改的数字

    n个空间(其中n<1M),存放a到a+n-1的数,位置随机且数字不重复,a为正且未知。现在第一个空间的数被误设置为-1。已经知道被修改的数不是最小的。请找出被修改的数字是多少。

    例如:n=6,a=2,原始的串为5,3,7,6,2,4。现在被别人修改为-1,3,7,6,2,4。现在希望找到5。

    回答:
      由于修改的数不是最小的,所以遍历第二个空间到最后一个空间可以得到a的值。
      a到a+n-1这n个数的和是total=na+(n-1)n/2。
      将第二个至最后一个空间的数累加获得sub_total。
      那么被修改的数就是total-sub_total。

    5、给40亿个不重复的unsigned int的整数,没排过序的,然后再给几个数,如何快速判断这几个数是否在那40亿个数当中? 

    这是我非常喜欢的一道题。
    答案:
      unsigned int的取值范围是0到2^32-1。我们可以申请连续的2^32/8=512M的内存,用每一个bit对应一个unsigned int数字。首先将512M内存都初始化为0,然后每处理一个数字就将其对应的bit设置为1。当需要查询时,直接找到对应bit,看其值是0还是1即可。

    6、在一个文件中有10G个整数,乱序排列,要求找出中位数。内存限制为2G。

    回答:
      不妨假设10G个整数是64bit的。
      2G内存可以存放256M个64bit整数。
      我们可以将64bit的整数空间平均分成256M个取值范围,用2G的内存对每个取值范围内出现整数个数进行统计。这样遍历一边10G整数后,我们便知道中数在那个范围内出现,以及这个范围内总共出现了多少个整数。
      如果中数所在范围出现的整数比较少,我们就可以对这个范围内的整数进行排序,找到中数。如果这个范围内出现的整数比较多,我们还可以采用同样的方法将此范围再次分成多个更小的范围(256M=2^28,所以最多需要3次就可以将此范围缩小到1,也就找到了中数)。

    7、将多个集合合并成没有交集的集合。

    给定一个字符串的集合,格式如:{aaabbbccc},{bbbddd},{eeefff},{ggg},{dddhhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaabbbcccdddhhh},{eeefff},{ggg}。
      (1)请描述你解决这个问题的思路;
      (2)请给出主要的处理流程,算法,以及算法的复杂度
      (3)请描述可能的改进。

    回答:
      集合使用hash_set来表示,这样合并时间复杂度比较低。
      1、给每个集合编号为0,123...
      2、创建一个hash_map,key为字符串,value为一个链表,链表节点为字符串所在集合的编号。遍历所有的集合,将字符串和对应的集合编号插入到hash_map中去。
      3、创建一个长度等于集合个数的int数组,表示集合间的合并关系。例如,下标为5的元素值为3,表示将下标为5的集合合并到下标为3的集合中去。开始时将所有值都初始化为-1,表示集合间没有互相合并。在集合合并的过程中,我们将所有的字符串都合并到编号较小的集合中去。
       遍历第二步中生成的hash_map,对于每个value中的链表,首先找到最小的集合编号(有些集合已经被合并过,需要顺着合并关系数组找到合并后的集合编号),然后将链表中所有编号的集合都合并到编号最小的集合中(通过更改合并关系数组)。
      4、现在合并关系数组中值为-1的集合即为最终的集合,它的元素来源于所有直接或间接指向它的集合。
      算法的复杂度为O(n),其中n为所有集合中的元素个数。
      题目中的例子:
      0:{aaabbbccc}
      1:{bbbddd}
      2:{eeefff}
      3:{ggg}
      4:{dddhhh}
      生成的hash_map,和处理完每个值后的合并关系数组分别为
      aaa:0。[-1,-1,-1,-1,-1]
      bbb:0,1。[-1,0,-1,-1,-1]
      ccc:0。[-1,0,-1,-1,-1]
      ddd:1,4。[-1,0,-1,-1,0]
      eee:2。[-1,0,-1,-1,0]
      fff:2。[-1,0,-1,-1,0]
      ggg:3。[-1,0,-1,-1,0]
      hhh:4。[-1,0,-1,-1,0]
      所以合并完后有三个集合,第0,1,4个集合合并到了一起,
  • 相关阅读:
    Python 编码转换与中文处理
    odoo 基本知识
    odoo xml 时间搜索条件
    在Ubuntu Kylin 16.04 LTS 上源码方式安装odoo
    安装hive
    linux中不同颜色的文件代表什么不同的类型
    PDF神器
    网盘搜索网站
    搭建Hadoop的全分布模式
    虚拟机中操作系统的克隆方法及ip修改及硬件地址修改
  • 原文地址:https://www.cnblogs.com/liqiu/p/3421505.html
Copyright © 2020-2023  润新知