试着解一道腾讯面试题

来源:互联网 发布:linux 查看端口号 编辑:程序博客网 时间:2024/06/02 16:25


帖子问题:
http://topic.csdn.net/u/20081029/22/C8FE34C1-25AB-4B94-986E-4C2FD4CAA664.html

(同学去面试的)
1、设计一个魔方(六面)的程序。
2、有一千万条短信,有重复,以文本文件的形式保存,一行一条,有重复。请用5分钟时间,找出重复出现最多的前10条。
3、收藏了1万条url,现在给你一条url,如何找出相似的url。(面试官不解释何为相似)


想了一中午,写了一下午(真服了自己,这么钻牛角尖,汗~),成果如下:

[原创] 解答一下吧,不知道看的算不算晚。
第1题:就是个数组和发生上下左右移动时候相关的数据变换问题;
第3题:正则表达式的应用问题,还涉及到一些思路问题;

重点第2题,我的解法如下:
思路:由于大量的数据,同时基于存储条件限制,尽量利用二分法,然后采用hash/binary结构,尽量避免循环。

------------------------------ Logic & Steps ------------------------------
/*
* 1. 对于1000万条存储在[硬盘, 文本文件]的短信记录,则设-> n = 10,000,000 (10 million)
* 2. 已知一条短信的长度是0 - 70 字符之间(最多70个字母,35个汉字),则设-> ArrayList<ArrayList> SMS[70] (1-70个不同长度,空短信另计)
*
* 3. 取 (第一个) 字符的[最后一位(bit)],为其建立-> ArrayList<ArrayList> bitFirstChar (取值0, 1)
* 4. 取 (最后一个) 字符的[最后一位(bit)],为其建立-> ArrayList<ArrayList> bitLastChar (取值0, 1)
* 5. 取((长度+1)除2) 字符的[最后一位(bit)]((i+1)/2),为其建立-> ArrayList<Dictionary> bitMidChar (取值0, 1)
*
* 6. 检查 (第一个) 字符[byte],为其建立-> Dictionary hashFirstCharacter<char, Dictionary> (首字相同放一起)
* 7. 检查 (最后一个) 字符[byte],为其建立-> Dictionary hashLastCharacter<char, Dictionary> (末字相同放一起)
* 8. 检查 ((长度+1)除2) 字符[byte],为其建立-> Dictionary hashMidCharacter<char, Dictionary> (中间字相同放一起)
*
* 9. 全文[String]比较,为其建立-> Dictionary hashSMS<String, long> (最终计数)
*
* 10. 维持一个全局 Dictionary<String, long> topSMS 遍历检验topSMS[i]中计数最小的String和当前更新的hashSMS[String]的大小,小则替换,否则无操作?或者最后再检查取前十???(这个我没考虑哪个时间开销更小)
*/
------------------------------ Logic & Steps ------------------------------

  1. /*
  2. * TopMostSMSReader pseudocode (C# version)
  3. * This is a demo for Reading top most SMS (or alike) Strings from files. partial code are pseudocode
  4. *
  5. * Author: Leemax Li
  6. * Created: 2008.11.03
  7. * MSN: leemax@live.com ; QQ: 735291192
  8. * Email: 1850018@qq.com
  9. * Last Modify: 2008.11.03 by Leemax Li
  10. */
  11. public class LeemaxTopMostSMSReader implements IDisposable {
  12.   // global variables
  13.   private int _fetchTotal;
  14.   private Dictionary<String, long> _topSMS;
  15.   private long _topTotal, _emptySMSCount;
  16.   private long _totalCount;
  17.   private bool _isUnderGo;
  18.   // constructor
  19.   public LeemaxTopMostSMSReader() {
  20.     _fetchTotal = 10;   // default number of sms fetched
  21.     _topSMS = new Dictionary<String, long>;
  22.     _topTotal = 0; // low efficiency
  23.     _emptySMSCount = 0;
  24.     _totalCount = 0;
  25.     _isUnderGo = false// lock flag, preserved for further use?
  26.   }
  27.   // main entry
  28.   public Dictionary<String, long> CheckNow(String fileName, long maxLine) {
  29.     // local variables
  30.     FileHandle fileSrc = open(fileName);
  31.     String nowSMS = "";
  32.     long currentCount;
  33.     Dictionary hashSMS<String, long>;
  34.     Dictionary hashMidCharacter<char, Dictionary>;
  35.     // ..... initial all members mentioned above
  36.     // for (bit series)  ... for(character series) ... for(hashSMS) ...
  37.     // ...........................................
  38.     // ...........................................
  39.     try {
  40.       // TryLock(this);   // signal sync....
  41.       _isUnderGo = true;
  42.       while (nowSMS = fileSrc.ReadNextLine()) {
  43.         _totalCount++;  // total counter increament
  44.         // condition checks, return if already no valuable candidates
  45.         // if need precise number, just block these checks
  46.         // low efficiency, useless....
  47.         // if (maxLine > 0 && _topTotal * _fetchTotal > maxLine) return _topSMS;
  48.         // an empty sms string
  49.         if (nowSMS = EMPTY) {
  50.           _emptySMSCount++;
  51.           currentCount = _emptySMSCount;
  52.           //CheckTopSMS(___EMPTY_, currentCount);   // low eficiency
  53.           continue;
  54.         }
  55.         if (SMS[nowSMS.length].bitFirstChar[0 or 1].bitLastChar[0 or 1].bitMidChar[0 or 1].hashFirstCharacter[nowSMS[0]].hashLastCharacter[nowSMS[nowSMS.length - 1]].hashMidCharacter[nowSMS[(nowSMS.length + 1) / 2]].hashSMS.HasKey(nowSMS))
  56.         {
  57.           SMS[nowSMS.length].bitFirstChar[0 or 1].bitLastChar[0 or 1].bitMidChar[0 or 1].hashFirstCharacter[nowSMS[0]].hashLastCharacter[nowSMS[nowSMS.length - 1]].hashMidCharacter[nowSMS[(nowSMS.length + 1) / 2]].hashSMS[nowSMS].Value += 1;
  58.         }
  59.         else
  60.         {
  61.           SMS[nowSMS.length].bitFirstChar[0 or 1].bitLastChar[0 or 1].bitMidChar[0 or 1].hashFirstCharacter[nowSMS[0]].hashLastCharacter[nowSMS[nowSMS.length - 1]].hashMidCharacter[nowSMS[(nowSMS.length + 1) / 2]].hashSMS.Add(nowSMS, 1);
  62.         }
  63.         //currentCount = SMS[nowSMS.length].bitFirstChar[0 or 1].bitLastChar[0 or 1].bitMidChar[0 or 1].hashFirstCharacter[nowSMS[0]].hashLastCharacter[nowSMS[nowSMS.length - 1]].hashMidCharacter[nowSMS[(nowSMS.length + 1) / 2]].hashSMS[nowSMS].Value;   // low efficiency
  64.         //CheckTopSMS(nowSMS, currentCount);   // low efficiency
  65.       }
  66.       CheckOutTops();
  67.     }
  68.     catch (Exception ex) {
  69.       // blah...blah...blah...
  70.     }
  71.     finally {
  72.       // UnLock(this);   // signal sync...
  73.       _isUnderGo = false;
  74.     }
  75.     
  76.     return _topSMS;
  77.   }
  78.   private void CheckOutTops() {
  79.     // blah...blah...blah...blah...
  80.   }
  81. // this is not good, should check out after all cleared out
  82. /*
  83.   private void CheckTopSMS(String newString, long newCount) {
  84.     long currentSmallest = _topSMS[0].Value;
  85.     long currentString = _topSMS.Keys[0];
  86.     foreach (KeyValuePair<String, long> currentPair in _topSMS) {
  87.       if (currentPair.Value < currentSmallest) {
  88.         currentSmallest = currentPair.Value;
  89.         currentString = currentPair.Key;
  90.         if (currentString == newString) {
  91.           _topSMS[newString].Value = newCount;
  92.           return;
  93.         }
  94.       }
  95.     }
  96.     // no match found, check the smallest
  97.     if (currentSmallest < newCount) {
  98.       if (_topSMS.Items.Count >= _fetchTotal) _topSMS.Remove[currentString];
  99.       _topSMS.Add(newString, newCount);
  100.     }
  101.   }
  102. */
  103.   // implementation of IDisposable
  104.   public void Dispose() {
  105.     // dispose all members here...
  106.     // delete .... delete .... delete ....
  107.   }
  108.   // attributes and others
  109.   public int ReturnLength
  110.   {
  111.     get { return _fetchTotal; }
  112.     set { if(!_isUnderGo) _fetchTotal = value; else throw new Excetion("....."); }
  113.   }
  114.   public long CurrentLine
  115.   {
  116.     get { return _totalCount; }
  117.   }
  118.   public long CurrentEmptySMSCount
  119.   {
  120.     get { return _emptySMSCount; }
  121.   }
  122. }

------------------------------ Possible Solution Code ------------------------------

 

 

------------------------------ analysis -----------------------------

  1. /*
  2. * 根据 Logic & Steps 中的设计
  3. * 1. N0 = 10,000,000 (10 million) (硬盘读取时间)
  4. * 2. SMS[70]  (不需要遍历, N1 = 10 million / 71 < 140846)
  5. * 3. 取 (第一个) 字符的[最后一位(bit)],bitFirstChar (CPU时间,不需要遍历, N2 = N1/2 < 70423)
  6. * 4. 取 (最后一个) 字符的[最后一位(bit)],(CPU时间,不需要遍历, N3 = N2/2 < 35212)
  7. * 5. 取((长度+1)除2) 字符的[最后一位(bit)]((i+1)/2),(CPU时间,不需要遍历, N4 = N3/2 < 17606)
  8. * 6. 检查 (第一个) 字符[byte],hashFirstCharacter(首字相同放一起)(设为 M = N4)
  9. * 7. 检查 (最后一个) 字符[byte],hashLastCharacter(末字相同放一起)(设为X = N4/ln(N4))
  10. * 8. 检查 ((长度+1)除2) 字符[byte], hashMidCharacter(中间字相同放一起)(设为Y = N4/(ln(N4)*ln(X)))
  11. * 9. 全文[String]比较,hashSMS(最终计数)(设为Z = N4/(ln(N4)*ln(X)*ln(Y)))
  12. *
  13. * 10. 维持一个全局 topSMS 遍历检验(每次检查为:N0*ln(FetchCount)次, 最后遍历 <= N4次)
  14. *
  15. * 时间代价为:O(Program): lnM*lnX*lnY*lnZ
  16. N = 10000000
  17. M = 71428.571428571428571428571428571
  18. lgM = 11.176453228349015489585363863205
  19. X = 6390.9873704292188700245451792576
  20. lgX = 8.7626440534989345490873775956615
  21. Y = 729.34462833478780320337939734221
  22. lgY = 6.5921463615017245913923031187162
  23. Z = 110.63841552338339979745756356137
  24. lgZ = 4.7062673662433216260688480137905
  25. Total Cost = lgM * lgX * lgY * lgZ
  26.            = 3038.3836675663354054154917591655
  27. */

------------------------------- analysis ------------------------------


想了半个小时。。。写了半天~如果只是我自己“自我感觉良好”的话,也请看在我写了一下午6个小时的面子上不要喷我。
欢迎大家探讨~~~
* Author: Leemax Li
* Created: 2008.11.03
* MSN: leemax@live.com ; QQ: 735291192
* Email: 1850018@qq.com
* Last Modify: 2008.11.03 by Leemax Li