hash 算法面试题解析

面试题:

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

思路:

300万个字符串最多(假设没有重复,都是最大长度)占用内存3M*1K/4=0.75G。所以可以将所有字符串都存放在内存中进行处理。

可以使用key为字符串(事实上是字符串的hash值),值为字符串出现次数的hash来统计每个每个字符串出现的次数。并用一个长度为10的数组/链表来存储目前出现次数最多的10个字符串。

这样空间和时间的复杂度都是O(n)

代码实现:

package org.enyes.algorithm.hash;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
 
public class SearchTimeCounter
{
   private int maxCount = 10;
   
   private Map<String, Integer> searchTimeMap = null;
   
   public SearchTimeCounter()
    {
       searchTimeMap = new HashMap<String, Integer>();
    }
   
   public SearchTimeCounter(int size)
    {
       searchTimeMap = new HashMap<String, Integer>(size);
    }
   
   public void addSearchString(String searchString)
    {
       Integer searchCount = searchTimeMap.get(searchString);
       searchTimeMap.put(searchString, searchCount == null ? 1 : searchCount +1);
    }
   
   public void printTopSearch ()
    {
       List<Map.Entry<String, Integer>> result = newArrayList<Map.Entry<String, Integer>>(maxCount);
       Map.Entry<String, Integer> ct = null;
       int minIndex = -1;
        Iterator<Map.Entry<String,Integer>> it = searchTimeMap.entrySet().iterator();
       while (it.hasNext())
       {
           ct = it.next();
           if (minIndex == -1)
           {
                result.add(ct);
                minIndex =minSearchIndex(result);
           }
           else if (result.get(minIndex).getValue() < ct.getValue())
           {
                result.set(minIndex, ct);
                minIndex =minSearchIndex(result);
           }
       }
       System.out.println(searchTimeMap.size());
       System.out.println(result);
    }
   
   private int minSearchIndex(List<Map.Entry<String, Integer>>topSearchList)
    {
       int size = topSearchList.size();
       if (size < maxCount)
        {
           return -1;
       }
       int minIndex = 0;
       for (int i = 1; i < size; i++)
       {
           if (topSearchList.get(i).getValue() <topSearchList.get(minIndex).getValue())
           {
                minIndex = i;
           }
       }
       return minIndex;
    }
}


代码测试:

package org.enyes.algorithm.hash;
 
import java.util.Random;
 
import org.junit.Test;
 
public class SearchTimeCounterTest
{
    private static final char[] CHARS = "qazwsxedcrfvtgbyhnujmikolp".toCharArray();
   
    private Random random = new Random();
   
    @Test
    public void testGetTopSearch()
    {
        long startTime = System.currentTimeMillis();
        int count = 1000 * 10000;
        for (int i = 0; i < count; i++)
        {
            getRomdonString();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("随机生成[" + count + "] 条随机数,cost time [" + (endTime -startTime) + "]ms");
        startTime = System.currentTimeMillis();
        SearchTimeCounter counter = newSearchTimeCounter();
        for (int i = 0; i < count; i++)
        {
           counter.addSearchString(getRomdonString());
        }
        counter.printTopSearch();
        endTime = System.currentTimeMillis();
        System.out.println("total cost time [" + (endTime- startTime) + "]ms");
}
   
    private String getRomdonString()
    {
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < 4; i++)
        {
            result.append(CHARS[random.nextInt(26)]);
        }
        return result.toString();
    }
}

结果:

随机生成[10000000] 条随机数,cost time [4344]ms

456976

[jeuw=45, njwf=44, govv=44,ghkf=45, pdpj=44, lcyz=44, qwsb=44, shqc=45, elbc=47, dgvi=45]

totalcost time [7969]ms

由于采用随机数,所以产生的字符串频率都差不多。从结果看:随机产生1000W随机字符串话费了4秒,产生了45W的字符串总数,总耗时8秒,包括随机产生字符串的4秒。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值