LeetCode 30 Substring with Concatenation of All Words(AC自动机+滑动窗口)
2016-03-23 16:01
453 查看
题意:给出一个字符串,和一个字典,字典中有若干个单词(可能有重复单词),每个单词的长度相等,现在要求所有字典中全部单词的任意组合在字符串中的起始下标。
思路:首先先说一下用ac自动机复杂度可以优化到O(n)啊!!!!!!看了votes最高的答案,复杂度是O(n*k)(n为字符串长度,k为字典中单词长度)。
现在 说一下做法,设字符串长度为n,字典中有m个单词,每个单词长度为w。
朴素的做法是对于每个位置,对于从它向后的m*w个位置进行判断,看看是否符合要求,这样做的时间复杂度为O(n*m*w),
那么怎么优化呢,可以用滑动窗口的思想,用两个指针标记一下窗口的起止位置,在窗口中的单词为当前符合要求的单词序列,每次根据情况判断当前右指针指向的单词是否符合条件,一下使窗口正确滑动就行了,这样做的话时间复杂度可以优化到O(n*w)
然后就是用ac自动机了,因为上一步每次还要判断单词是否是字典中的一个合法单词,所以复杂度中多了一个w,如何去掉它呢,可以用ac自动机预处理一下,
处理一下字符串中每一个位置是哪个单词的开始位置,然后我们每次就不用用O(w)的时间去判断当前有指针所指单词是否是一个合法单词了,O(1)判断一下就行了,ac自动机预处理的复杂度为O(m*w+n),所以总的复杂度为O(m*w+n),比最高票答案要好很多啊!!!!!!!!!!
代码写得有点挫
思路:首先先说一下用ac自动机复杂度可以优化到O(n)啊!!!!!!看了votes最高的答案,复杂度是O(n*k)(n为字符串长度,k为字典中单词长度)。
现在 说一下做法,设字符串长度为n,字典中有m个单词,每个单词长度为w。
朴素的做法是对于每个位置,对于从它向后的m*w个位置进行判断,看看是否符合要求,这样做的时间复杂度为O(n*m*w),
那么怎么优化呢,可以用滑动窗口的思想,用两个指针标记一下窗口的起止位置,在窗口中的单词为当前符合要求的单词序列,每次根据情况判断当前右指针指向的单词是否符合条件,一下使窗口正确滑动就行了,这样做的话时间复杂度可以优化到O(n*w)
然后就是用ac自动机了,因为上一步每次还要判断单词是否是字典中的一个合法单词,所以复杂度中多了一个w,如何去掉它呢,可以用ac自动机预处理一下,
处理一下字符串中每一个位置是哪个单词的开始位置,然后我们每次就不用用O(w)的时间去判断当前有指针所指单词是否是一个合法单词了,O(1)判断一下就行了,ac自动机预处理的复杂度为O(m*w+n),所以总的复杂度为O(m*w+n),比最高票答案要好很多啊!!!!!!!!!!
代码写得有点挫
class Solution { public: vector<int> findSubstring(string s, vector<string>& words) { struct Aho_Corasick { int sz; int ch[10000][27]; int val[10000]; int f[10000]; int lens; unordered_map<int, int> flag; int idx(char c) {return c - 'a';} Aho_Corasick(string s) { sz = 1; lens = s.length(); memset(ch[0], 0, sizeof(ch[0])); }; void insert(string str, int v) { int u = 0, n = str.length(); for(int i = 0; i < n; i++) { int c = idx(str[i]); if(!ch[u][c]) { memset(ch[sz], 0, sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v; } int getFail() { queue<int> q; f[0] = 0; for(int c = 0; c < 26; c++) { int u = ch[0][c]; if(u) { f[u] = 0; q.push(u); } } while(!q.empty()) { int r = q.front(); q.pop(); for(int c = 0; c < 26; c++) { int u = ch[r][c]; if(!u) { ch[r][c] = ch[f[r]][c]; continue; } q.push(u); int v = f[r]; while(v && !ch[v][c]) v = f[v]; f[u] = ch[v][c]; } } } void find_T(string s, int lenw) { int j = 0; for(int i = 0; i < lens; i++) { int c = idx(s[i]); j = ch[j][c]; if(val[j]) flag[i-lenw+1] = val[j]; } } }; vector<int> ans; Aho_Corasick ac = Aho_Corasick(s); int cnt = words.size(); int lenw = words[0].length(); unordered_map<string, int> dic; unordered_map<int, int> num; int id = 0; for (int i = 0; i < cnt; i++) { if(!dic.count(words[i])) dic[words[i]] = ++id; num[dic[words[i]]]++; } for (int i = 0; i < cnt; i++) ac.insert(words[i], dic[words[i]]); ac.getFail(); ac.find_T(s, lenw); for (int i = 0; i < lenw; i++) { int left = i; int word_cnt = 0; unordered_map<int, int> tmp_cnt; for (int j = i; j < ac.lens; j+=lenw) { if (!ac.flag[j]) { left = j + lenw; word_cnt = 0; tmp_cnt.clear(); } else { int v = ac.flag[j]; tmp_cnt[v]++; word_cnt++; if (tmp_cnt[v] > num[v]) { do { tmp_cnt[ac.flag[left]]--; left += lenw; word_cnt--; } while (ac.flag[left-lenw] != v); } if (word_cnt == cnt) ans.push_back(left); } } } return ans; } };
相关文章推荐
- jQuery实现仿微软首页感应鼠标变化滑动窗口效果
- leetcode 179 Largest Number
- leetcode 24 Swap Nodes in Pairs
- leetcode 2 Add Two Numbers 方法1
- leetcode 2 Add Two Numbers 方法2
- leetcode----Longest Substring Without Repeating Characters
- TCP/IP滑动窗口
- [LeetCode]47 Permutations II
- [LeetCode]65 Valid Number
- [LeetCode]123 Best Time to Buy and Sell Stock III
- [LeetCode] String Reorder Distance Apart
- [LeetCode] Sliding Window Maximum
- [LeetCode] Find the k-th Smallest Element in the Union of Two Sorted Arrays
- [LeetCode] Determine If Two Rectangles Overlap
- [LeetCode] A Distance Maximizing Problem
- leetcode_linearList
- leetcode_linearList02
- 021-Merge Two Sorted Lists(合并两个排好序的单链表);leetcode
- LeetCode[Day 1] Two Sum 题解
- LeetCode[Day 2] Median of Two Sorted Arrays 题解