楼主: wnbaicai
跳转到指定楼层
上一主题 下一主题
收起左侧

G家实习电面挂经

🔗
Jasonyuan 2016-11-9 12:28:54 | 只看该作者
本楼:
全局:
谢谢楼主!
回复

使用道具 举报

🔗
sccnju 2016-11-9 12:50:07 | 只看该作者
全局:
看了下楼主的经理感觉我基本上跪了,下周三面好紧张。碰到第二轮这种题目就毫无办法了。。。。
回复

使用道具 举报

🔗
zzgzzm 2016-11-9 13:21:25 | 只看该作者
全局:
wnbaicai 发表于 2016-11-9 12:26
给跪了,我能说我扫了一遍没看懂么,等有空了再研究下...

假设s="abcdefgh", dict ="abd","cegh","ea". 那么要匹配s的最长subsequence 只有2种情况:包括首字母”a"或不包括。若不包括,那就在原字典中匹配”bcdefgh"的最长subsequence   。若包括,那么只看字典中首字母为”a"的单词并去掉该字母,也就是用“新”字典{“bd"}去匹配”bcdefgh"的最长subsequence。这个trie 的引入完全是为了如何快速的得到“新”字典。理论上完全可以用loop over string list来完成,但时间复杂度会相当高,而且会不停地建新的字典占空间。这种在tree node和线性index 二维DP我是头一次用,感觉应该很对这个字典问题的路。不确定是否还有其他捷径,但感觉时间复杂度应该已经优化了。
回复

使用道具 举报

🔗
zzgzzm 2016-11-9 13:30:37 | 只看该作者
全局:
zzgzzm 发表于 2016-11-9 13:21
假设s="abcdefgh", dict ="abd","cegh","ea". 那么要匹配s的最长subsequence 只有2种情况:包括首字母”a ...

Trie 实际上就是用Node* (integral type)去代替了原始的复杂字典结构vector <string>,并利用child node关系才得以实现在字典维度的DP。DP的边界条件就是空字典匹配任何string 都是0,任何字典匹配空string都是0.
回复

使用道具 举报

🔗
oldwhite 2016-11-9 14:00:14 | 只看该作者
全局:
为什么感觉你们讨论的那么复杂呀,我写了一下判断subsequence的函数。什么fancy structure都没用。O(|S|)的时间就行了,S是input String. 然后再按lz的思路给字典按长度排序,然后总时间是O(|S|* |D|)。 |D|表示字典的size,也就是单词数。

/* return true when S could be trimmed to get v, false otherwise
   Time Complexity: O(|S|); Space: in space */
Boolean stringContains(String S, String v){
        // not topological sort,
        // deal with corner case
        If (S==null | v==null) return false;
        If (v.length() == 0) return true;
// If (S.length() == 0) return false;
If (v.length() > S.length()) return false;


// Go through each char in v
Int indexM = -1;
For (int i=0; i<v.length(); i++){
        indexM = S.indexOf(v.charAt(i), indexM+1);
        if(indexM < 0)
                Return false;
        // taking care of boundary condition
        if(indexM == S.length()-1 && i < v.length() - 1)
                Return false;
}
Return true;
}
回复

使用道具 举报

🔗
zzgzzm 2016-11-9 14:48:31 | 只看该作者
全局:
oldwhite 发表于 2016-11-9 14:00
为什么感觉你们讨论的那么复杂呀,我写了一下判断subsequence的函数。什么fancy structure都没用。O(|S|)的 ...

...这是正解了。忽略我的trie 吧,我居然将subsequence match 的算法想成是O(M*N)的(那个应该是看match 了多少次吧),所以用了trie. .....纯娱乐吧
回复

使用道具 举报

🔗
catinclay 2016-11-9 23:43:05 | 只看该作者
全局:
oldwhite 发表于 2016-11-9 14:00
为什么感觉你们讨论的那么复杂呀,我写了一下判断subsequence的函数。什么fancy structure都没用。O(|S|)的 ...

这不就是楼主的方法吗...貌似面官觉得复杂度太高?
回复

使用道具 举报

全局:
谢谢楼主的面经,我也是首面G家。。下周就要面了。。。同基础薄弱。。。只求好运吧!希望你也能有好运!
回复

使用道具 举报

🔗
文体两开花 2016-11-10 02:58:32 | 只看该作者
全局:
同打星际,同面google实习
回复

使用道具 举报

🔗
zzgzzm 2016-11-10 03:41:23 | 只看该作者
全局:
oldwhite 发表于 2016-11-9 14:00
为什么感觉你们讨论的那么复杂呀,我写了一下判断subsequence的函数。什么fancy structure都没用。O(|S|)的 ...

即使用O(|s|)时间判断字典中每个单词w是否是s的sunsequence,那么总时间O(|s|*|D|)也会有很多浪费的地方。例如当字典中2个单词有公用prefix的时候,这时公共的prefix只需要在s中查找一次,所以这个O(|s|*|D|)的是个很大的上界(与|s|成正比)。
为了避免重复prefix matching,还是应该将字典中所有长度不超过|s|的单词建立一个Trie,pre-calculate 每个字母在s.substr(j)中的初始位置,然后DFS在Trie中寻找最长matching.
时间复杂度:建立Trie = O(L), L=字典中所有长度不超过|s|的单词总长;
pre-calculate 每个字母在s.substr(j)中的初始位置=O(|s|);
DFS: O(Trie node个数) <= O(L)
总复杂度 = O(|s| + L). 这个比O(|s|*|D|)是小很多的,尤其是|s|很大而字典单词并不长的时候。
  1. // pos[c][i]: position of first occurrence of c in s.substr(i)
  2. unordered_map<char, vector<size_t>> pos; // default -1 if not found

  3. // r: current matched prefix represented by TrieNode
  4. // start: position in s matched so far
  5. // len/maxLen: max/length of subsequence matched so far
  6. void dfs(Node* r, size_t start, int len, int& maxLen) {
  7.   if (!r || start == -1) return;
  8.   if (r->isWord) maxLen = max(maxLen, len);
  9.   for (char c = 'a'; c <= 'z'; c++) dfs(r->next[c - 'a'], pos[c][start], len + 1, maxLen);
  10. }

  11. int longestSubsequence(string& s, const vector<string>& dict) {
  12.   int ls = s.length(); if (!ls) return 0;
  13.   // generate pos map index: time O(ls)
  14.   for (char c = 'a'; c <= 'z'; c++) {
  15.     for (int start = 0; start < ls; ) {
  16.       int i = start; while (i < ls && s[i] != c) i++;
  17.       for (int j = start; j <= min(i, ls-1); j++) pos[c][j] = i<ls? i : -1;
  18.       start = i + 1;
  19.     }
  20.   }   
  21.   int maxLen = 0; dfs(createTrie(dict, ls), 0, 0, maxLen);
  22.   return maxLen;
  23. }

  24. // Create trie for words with length <= maxDepth
  25. // Time: O(L) L= total word length in dictionary with length <= maxDepth
  26. Node* createTrie(const vector<string>& dict, int maxDepth) {
  27.   auto r = new Node(), cur = r;
  28.   for (const auto& w : dict) {
  29.     if (w.length() > maxDepth) continue;
  30.     for (char c : w) {
  31.       int i = c - 'a';
  32.       if (!cur->next[i]) cur->next[i] = new Node();
  33.       cur = cur->next[i];
  34.     }
  35.     cur->isWord = true;
  36.   }
  37.   return r;
  38. }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表