这题蛮有意思的,我刚写完。 其实 idea 挺容易明白,我说一次给你听就明白了,但是没图解释起来比较费劲。这题 最复杂的地方其实就是选择怎么把数据结构结合起来。 一开始我以为要用 dp,其实 greedy 就可以了。 总复杂度是 O(N lg M),N 为 str 的长度,M 为 pattern 的长度。 主要原因有个 lg M 是因为 STL map 里的 find() 函数复杂度为 O(lg M). 我用的是 map + queue + hashtable (有点吓人呵呵,可能我想太复杂了)。 我暂时还没想到怎么提升到 O(N),应该是利用一个更好的数据结构吧。如果有高人知 道怎么提升到 O(N),请指点一下吧~ 这是我做的 test cases: 第一行是 string 和 pattern, 第二行是函数 return 的 start and end position,然后是 shortest substring。 cabeca cae 3 5 eca cfabeca cae 4 6 eca cabefgecdaecf cae 9 11 aec cabwefgewcwaefcf cae 9 12 cwae abcabdebac cda 2 5 cabd abcabdebac cea 6 9 ebac acbdbaab aabd 3 6 dbaa caaec cae 2 4 aec caae cae 0 3 caae acbbaab aab 3 5 baa acbba aab 0 4 acbba acbba aab 贴个代码吧, void findMinWindow(char str[], char pattern[], int &start, int &end) { int len1 = strlen(str); int len2 = strlen(pattern); int minLen = 2147483647; // hash table init all to 0s // is used to check how many letters left // in the pattern to be filled char patHash[256] = {0}; // we keep an array of queues // for each letter queue q[256]; // a map that maps an int to char // the reason an array is not used // is because we want to find the // minimum and maximum index with // valid character from pattern map m; for (int i = 0; i < len2; i++) patHash[pattern[i]]++; // set the rest to -1 so that we know // that letter does not exist in pattern for (int i = 0; i < 256; i++) if (patHash[i] == 0) patHash[i] = -1; for (int i = 0; i < len1; i++) { // replace the character in the queue if (patHash[str[i]] == 0) { int idxToErase = q[str[i]].front(); map::iterator it = m.find(idxToErase); m.erase(it); m[i] = str[i]; q[str[i]].pop(); q[str[i]].push(i); } // push character to queue if (patHash[str[i]] > 0) { q[str[i]].push(i); m[i] = str[i]; patHash[str[i]]--; } // end if // found a window, check for minimum if (m.size() == len2) { int lastIndex = m.rbegin()->first; int firstIndex = m.begin()->first; int len = lastIndex - firstIndex + 1; if (len < minLen) { minLen = len; start = firstIndex; end = lastIndex; } } // end if } // end for } 一些常见面试题的答案与总结 - http://www.ihas1337code.com
x*y
10 楼
面试题不会要求这么复杂的CODE的... 应该有简单写的.
【在 i**********e 的大作中提到】 : 这题蛮有意思的,我刚写完。 : 其实 idea 挺容易明白,我说一次给你听就明白了,但是没图解释起来比较费劲。这题 : 最复杂的地方其实就是选择怎么把数据结构结合起来。 : 一开始我以为要用 dp,其实 greedy 就可以了。 : 总复杂度是 O(N lg M),N 为 str 的长度,M 为 pattern 的长度。 : 主要原因有个 lg M 是因为 STL map 里的 find() 函数复杂度为 O(lg M). : 我用的是 map + queue + hashtable (有点吓人呵呵,可能我想太复杂了)。 : 我暂时还没想到怎么提升到 O(N),应该是利用一个更好的数据结构吧。如果有高人知 : 道怎么提升到 O(N),请指点一下吧~ : 这是我做的 test cases:
s*e
11 楼
我也写了一个code. 有测试ihasleetcode的所有test case答案都一样。 如果没有想错的话应该是O(n) 因为begin和end两个值都最多扫过每一个字母一次 假设都是ascii字符 typedef struct range { int begin; int end; } Range; Range shortestSubstring(const char* str, int strLen, const char* characters, int charCount) { int* needToFind=new int[256]; int* hasFound=new int[256];
【在 s*******e 的大作中提到】 : 我也写了一个code. 有测试ihasleetcode的所有test case答案都一样。 : 如果没有想错的话应该是O(n) : 因为begin和end两个值都最多扫过每一个字母一次 : 假设都是ascii字符 : typedef struct range : { : int begin; : int end; : } Range; : Range shortestSubstring(const char* str, int strLen, const char* characters,
i*e
14 楼
啊! 你的思路我明白了,真的很简洁,简单,根本不用很复杂的数据结构! 没错,你的复杂度是 O(N)的。 应该更清楚的说,是 2*N。 因为 begin 指针最多只能循环 N 次,而 end 指针也是最多只能循环 N 次,加起来就 是 2N. 我总结了一下,主要是我把问题想的太复杂了。 我的思路一直纠结于 begin 和 end 之间的字符串,其实根本没这个必要。 再次赞叹你的思路! 学习了~ 一些常见面试题的答案与总结 - http://www.ihas1337code.com
通过两个map来记录需要找到pattern(NeedtoFind)和暂时找到到pattern(HasFound)。 每次end往前移动一步后,都坚持当前到条件是否满足要求。 题目要求到是,最小长度,通过检查两个map。。。 不知道解释清楚了没有。。。 please correct me if wrong. thx
你解释的和上面storm说的是一样的。 关于paul的链表,我没看仔细,下面是我自己写的。 没想到要写这么久。真的面的时候应该就废了。 很长,有耐心就慢慢看吧。。不知道对了对,意思应该在那了。 早知道应该写成C,可以跑试试看。 这么长,只是为了比begin-end那个少扫一遍。。。 defrecord NodeType ch char pos int prePos *NodeType nxtPos *NodeType preSameChar *NodeType nxtSameChar *NodeType // S2 char to first tracked S2 NodeType (pointing to the start of // a linked list of same char NodeType by nxtSameChar) nodesFoundFirst hashmap // S2 char to last tracked S2 NodeType (pointing to the end of // a linked list of same char NodeType by preSameChar) nodesFoundLast hashmap firstPos *NodeType = null // first tracked S2 char in S1 lastPos *NodeType = null // last tracked S2 char in S1 needToFind hashmap hasFound hashmap count = 0 minLen = 0 init needToFind and hasFound from s2 for i=0 to len(s1) if s1[i] in s2 hasFound[s1[i]]++ newNode = new NodeType(s1[i], i, null, null, null, null) if firstPos is null firstPos = newNode if nodesFoundFirst contains s1[i] oriNodeFirst = nodesFoundFirst[s1[i]] if hasFound[s1[i]]>needToFind[s1[i]] hasFound[s1[i]]-- // delete it from pos linked list if oriNodeFirst == firstPos firstPos = oriNodefirst.nxtPos else oriNodeFirst.prePos.nxtPos = oriNodeFirst.nxtPos if oriNodeFirst == lasPos lastPos = oriNodeFirst.prePos else oriNodeFirst.nxtPos.prePos = oriNodeFirst.prePos // delete it from same char linked list if needToFind[s1[i]] > 1 nodesFoundFirst[s1[i]] = oriNodeFirst.nxtSameChar nodesFoundFirst[s1[i]].preSameChar = null // append to same char linked list if needToFind[s1[i]] > 1 newNode.preSameChar = nodesFoundLast[s1[i]] nodesFoundLast[s1[i]].nxtSameChar = newNode nodesFoundLast[s1[i]] = newNode else nodesFoundFirst[s1[i]] = nodesFoundLast[s1[i]] = newNode else nodesFoundFirst[s1[i]] = nodesFoundLast[s1[i]] = newNode if lastPos is not null lastPos.nxtPos = newNode newNode.prePos = lastPos lastPos = newNode // update min len if countcount++ else if lastPos.pos - firstPos.pos < minLen minLen = lastPos.pos - firstPos.pos