每天一道LeetCode-----给定字符串s和字符数组words,在s中找到words出现的位置,words内部字符串顺序无要求
2017-10-28 23:19
507 查看
Substring with Concatenation of All Words
原题链接Substring with Concatenation of All Words题目意思是给定字符串s和字符数组words,在s中寻找words出现的位置,words内部的字符串顺序没有要求
此问题可以直接顺序搜索,假设
s的长度为m,
words的长度为n,
words中每个单词的长度为w,复杂度是
O((m-n*w)*n),需要利用两个
unordered_map<string,int>,一个记录每个单词总共需要多少个,一个记录当前遍历到的单词数,如果遇到不在
words中的单词,就
break从下一个开始找
另一种方法是使用滑动窗口,也是利用两个
unordered_map<string, int>。原理是当不匹配是移动起始点,每一移动w个距离。不匹配有两种情况
当前单词不是words中的单词,重新开始找,初始化负责记录遍历到的单词数的那个map
当前单词word是words中的单词,但是这个单词已经够了,不再需要这个单词了。此时需要将窗口向右移动,直到出现第一个word为止,从这个word后面开始记录
举个例子,
s = "barfoobarfoothebar"; words = ["bar","bar","foo","the"]; unordered_map<string, int> counts; /* * 记录每个单词需要的次数 * bar foo the * 2 1 1 */ unordered_map<string, int> seen; /* * 记录当前找到的单词数 * bar foo the * 0 0 0 */ int count; /* 记录当前找到的单词数,0,目标大小为words的大小,4 */ int startIndex; /* 开始位置,0,找到就把它添加到结果的vector中 */ /* 1. 从s起点开始找,每3一判断,第一个bar,"bar"是要找的单词(在counts中),给seen对应为加一,此时seen["bar"]=1, count=1; 2. 接着找第二个单词"foo",也在counts中,给seen对应位加一,此时seen["foo"]=1, count=2; 3. 继续找"bar",也在counts中,给seen加一,此时seen["bar"]=2,count=3; 4. 继续找"foo",也在counts中,给seen加一,此时seen["foo"]=2,但是counts["foo"]=1,表示"foo"只需要一个,此时不满足条件,移动 1. 从startIndex开始删除单词,直到找到第一个"foo" 2. 删掉"bar",此时seen["bar"]=1,count=1,startIndex=0+3=3; 3. 删掉"foo",此时seen["foo"]=1,不改变count,因为当不满足时,没有增加count,startIndex=6; 4. 找到第一个"foo"了,继续查找单词 5. 继续找"the",在counts中,给seen加一,此时seen["the"]=1,count=2 6. ... 7. 最终找到count==n,将startIndex=6添加到结果中 8. 再右移一个单词,删掉"bar",此时seen["bar"]=1,count=3,startIndex=9 9. 继续寻找 10. ... 11. 遇到单词"abc",不在counts中,重置seen,count,startIndex 12. 继续寻找 13. ... 14. 结束 */
代码如下
class Solution { public: vector<int> findSubstring(string s, vector<string>& words) { vector<int> res; if(s.size() == 0 || words.size() == 0) return res; unordered_map<string, int> dict; for(auto &str : words) ++dict[str]; int n = s.size(); int cnt = words.size(); int wl = words[0].size(); /* * 每个单词长度为wl,那么只需要循环wl次,每次移动wl个为 * 0, wl, 2*wl, 3*wl ... * 1, 1+wl, 1+2*wl, 1+3*wl... * 2, 2+wl, 2+2*wl, 2+3*wl... * ... */ for(int i = 0; i < wl; ++i) { int left = i; int count = 0; unordered_map<string, int> tdict; //seen /* 每次移动wl个 */ for(int j = i; j <= n - wl; j+=wl) { string str = s.substr(j, wl); /* 如果是需要的单词,就添加到seen中 */ if(dict.count(str)) { tdict[str]++; /* 如果已经不需要了,就不用增加count */ if (tdict[str] <= dict[str]) count++; else { /* 如果当前这个单词是多余的,超出了数量限制,就移动窗口 */ while (tdict[str] > dict[str]) { string str1 = s.substr(left, wl); tdict[str1]--; /* 因为多余的那个单词没有增加count,所以也不需要减count */ if (tdict[str1] < dict[str1]) count--; left += wl; } } /* 如果到所有,右移 */ if (count == cnt) { res.push_back(left); // advance one word tdict[s.substr(left, wl)]--; count--; left += wl; } } /* 不是需要的单词,重置所有 */ else { tdict.clear(); count = 0; left = j + wl; } } } return res; } };
啊啊啊啊下午的心情一点也不好-.-
相关文章推荐
- 每天一道LeetCode-----找到一个字符串在另一个字符串出现的位置,字符串内部顺序无要求
- 每天一道LeetCode-----在字符串s中找到最短的包含字符串t中所有字符的子串,子串中字符顺序无要求且可以有其他字符
- 每天一道LeetCode-----找到给定数组的连续子数组,使这个子数组的和最大,要求复杂度为O(n)
- 每天一道LeetCode-----在给定序列中找到满足nums[i]>nums[i-1]&&nums[i]>nums[i+1]的位置,要求时间复杂度是O(logN)
- 每天一道LeetCode-----给定大小为n+1的数组,元素大小在[1 : n]之间,只有一个元素会重复出现多次,找到重复的那个
- 每天一道LeetCode-----在给定数组中找到一个子数组,使得这个子数组的元素乘积最大
- 每天一道LeetCode-----摩尔投票法寻找给定数组中出现个数大于n/2或n/3的元素
- 每天一道LeetCode-----找到给定序列中所有和为某个值的集合或集合个数,序列中可以有/无重复项,集合元素顺序不同算不同集合等
- 每天一道LeetCode-----找到序列中第一个没有出现的正整数,要求时间复杂度是O(n),空间复杂度是O(1)
- 每天一道LeetCode-----寻找给定字符串中重复出现的子串
- 【C语言】自己编写程序实现strrchr函数,即在给定字符串中找特定的字符并返回最后出现的位置
- 每天一道算法题(二):给定数组Arr和一个整数aim,请返回哪两个位置的数可以加出aim来。
- 每天一道LeetCode-----找到有多少条连续路径的和为给定值,路径不需要从根节点出发到达叶子节点
- 每天一道LeetCode-----将用数组表示的整数加一,两个用字符串表示的(二进制)数相加
- leetcode:给定一个整数数组,除了一个元素外,每个元素都会出现两次。找到那一个。
- 每日一道算法题:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。
- 26.在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符,并返回它的位置
- 【每天一道算法题】给定一个存放整数的数组,要求数组左边为奇数,右边为偶数
- 对于一个字符串,请设计一个高效算法,找到第一次重复出现的字符。 给定一个字符串(不一定全为字母)A及它的长度n。请返回第一个重复出现的字符。保证字符串中有重复字符,字符串的长度小于等于500。
- 在一个字符串中找到第一个只出现一次的字符,要求时间复杂度O(n)