LeetCode:Substring with Concatenation of All Words (summarize)
You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
For example, given:
S: "barfoothefoobarman"
L: ["foo", "bar"]
You should return the indices: [0,9].
(order does not matter).
算法1
暴力解法,从字符串s的每个位置都判断一次(如果从当前位置开始的子串长度小于L中所有单词长度,不用判断),从当前位置开始的子串的前段部分能不能由集合L里面的单词拼接而成。
从某一个位置 i 判断时,依次判断单词s[i,i+2], s[i+3,i+5], s[i+6, i+8]…是否在集合中,如果单词在集合中,就从集合中删除该单词。
我们用一个hash map来保存单词,这样可以在O(1)时间内判断单词是否在集合中
算法的时间复杂度是O(n*(l*k))n是字符串的长度,l是单词的个数,k是单词的长度
递归代码如下:
class Solution {
private:
int wordLen;
public:
vector<int> findSubstring(string S, vector<string> &L) {
unordered_map<string, int>wordTimes;
for(int i = 0; i < L.size(); i++)
if(wordTimes.count(L[i]) == 0)
wordTimes.insert(make_pair(L[i], 1));
else wordTimes[L[i]]++;
wordLen = L[0].size();
vector<int> res;
for(int i = 0; i <= (int)(S.size()-L.size()*wordLen); i++)
if(helper(S, i, wordTimes, L.size()))
res.push_back(i);
return res;
}
//判断子串s[index...]的前段是否能由L中的单词组合而成
bool helper(string &s, const int index,
unordered_map<string, int>&wordTimes, const int wordNum)
{
if(wordNum == 0)return true;
string firstWord = s.substr(index, wordLen);
unordered_map<string, int>::iterator ite = wordTimes.find(firstWord);
if(ite != wordTimes.end() && ite->second > 0)
{
(ite->second)--;
bool res = helper(s, index+wordLen, wordTimes, wordNum-1);
(ite->second)++;//恢复hash map的状态
return res;
}
else return false;
}
};
非递归代码如下:
class Solution {
private:
int wordLen;
public:
vector<int> findSubstring(string S, vector<string> &L) {
unordered_map<string, int>wordTimes;
for(int i = 0; i < L.size(); i++)
if(wordTimes.count(L[i]) == 0)
wordTimes.insert(make_pair(L[i], 1));
else wordTimes[L[i]]++;
wordLen = L[0].size();
vector<int> res;
for(int i = 0; i <= (int)(S.size()-L.size()*wordLen); i++)
if(helper(S, i, wordTimes, L.size()))
res.push_back(i);
return res;
}
//判断子串s[index...]的前段是否能由L中的单词组合而成
bool helper(const string &s, int index,
unordered_map<string, int>wordTimes, int wordNum)
{
for(int i = index; wordNum != 0 && i <= (int)s.size()-wordLen; i+=wordLen)
{
string word = s.substr(i, wordLen);
unordered_map<string, int>::iterator ite = wordTimes.find(word);
if(ite != wordTimes.end() && ite->second > 0)
{ite->second--; wordNum--;}
else return false;
}
if(wordNum == 0)return true;
else return false;
}
};
OJ递归的时间小于非递归时间,因为非递归的helper函数中,hash map参数是传值的方式,每次调用都要拷贝一次hash map,递归代码中一直只存在一个hash map对象
算法2
回想前面的题目:LeetCode:Longest Substring Without Repeating Characters 和 LeetCode:Minimum Window Substring ,都用了一种滑动窗口的方法。这一题也可以利用相同的思想。
比如s = “a1b2c3a1d4”L={“a1”,“b2”,“c3”,“d4”}
窗口最开始为空,
a1在L中,加入窗口 【a1】b2c3a1d4 本文地址
b2在L中,加入窗口 【a1b2】c3a1d4
c3在L中,加入窗口 【a1b2c3】a1d4
a1在L中了,但是前面a1已经算了一次,此时只需要把窗口向右移动一个单词a1【b2c3a1】d4
d4在L中,加入窗口a1【b2c3a1d4】找到了一个匹配
如果把s改为“a1b2c3kka1d4”,那么在第四步中会碰到单词kk,kk不在L中,此时窗口起始位置移动到kk后面a1b2c3kk【a1d4
class Solution {
public:
vector<int> findSubstring(string S, vector<string> &L) {
unordered_map<string, int>wordTimes;//L中单词出现的次数
for(int i = 0; i < L.size(); i++)
if(wordTimes.count(L[i]) == 0)
wordTimes.insert(make_pair(L[i], 1));
else wordTimes[L[i]]++;
int wordLen = L[0].size();
vector<int> res;
for(int i = 0; i < wordLen; i++)
{//为了不遗漏从s的每一个位置开始的子串,第一层循环为单词的长度
unordered_map<string, int>wordTimes2;//当前窗口中单词出现的次数
int winStart = i, cnt = 0;//winStart为窗口起始位置,cnt为当前窗口中的单词数目
for(int winEnd = i; winEnd <= (int)S.size()-wordLen; winEnd+=wordLen)
{//窗口为[winStart,winEnd)
string word = S.substr(winEnd, wordLen);
if(wordTimes.find(word) != wordTimes.end())
{
if(wordTimes2.find(word) == wordTimes2.end())
wordTimes2[word] = 1;
else wordTimes2[word]++;
if(wordTimes2[word] <= wordTimes[word])
cnt++;
else
{//当前的单词在L中,但是它已经在窗口中出现了相应的次数,不应该加入窗口
//此时,应该把窗口起始位置想左移动到,该单词第一次出现的位置的下一个单词位置
for(int k = winStart; ; k += wordLen)
{
string tmpstr = S.substr(k, wordLen);
wordTimes2[tmpstr]--;
if(tmpstr == word)
{
winStart = k + wordLen;
break;
}
cnt--;
}
}
if(cnt == L.size())
res.push_back(winStart);
}
else
{//发现不在L中的单词
winStart = winEnd + wordLen;
wordTimes2.clear();
cnt = 0;
}
}
}
return res;
}
};
算法时间复杂度为O(n*k))n是字符串的长度,k是单词的长度
【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3807055.html
LeetCode:Substring with Concatenation of All Words (summarize)的更多相关文章
- 【LeetCode】647. Palindromic Substrings 解题报告(Python)
[LeetCode]647. Palindromic Substrings 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/problems/p ...
- Leetcode之回溯法专题-78. 子集(Subsets)
Leetcode之回溯法专题-78. 子集(Subsets) 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums = ...
- Leetcode之回溯法专题-77. 组合(Combinations)
Leetcode之回溯法专题-77. 组合(Combinations) 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合. 示例: 输入: n = 4, k = 2 输 ...
- Leetcode之回溯法专题-46. 全排列(Permutations)
Leetcode之回溯法专题-46. 全排列(Permutations) 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3, ...
- 【LeetCode】376. Wiggle Subsequence 解题报告(Python)
[LeetCode]376. Wiggle Subsequence 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.c ...
- 【LeetCode】649. Dota2 Senate 解题报告(Python)
[LeetCode]649. Dota2 Senate 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地 ...
- 【LeetCode】911. Online Election 解题报告(Python)
[LeetCode]911. Online Election 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ ...
- 【LeetCode】886. Possible Bipartition 解题报告(Python)
[LeetCode]886. Possible Bipartition 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu ...
- 【LeetCode】36. Valid Sudoku 解题报告(Python)
[LeetCode]36. Valid Sudoku 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址 ...
随机推荐
- (Python)list的内建函数 filter(), map(), 和 reduce()
这一节,我们将主要学习用于list的三个内建函数: filter(), map(), 和 reduce(). 1.filter(function, sequence) 逐个从sequence中取一个 ...
- JS实现隔行变色,鼠标移入高亮
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 31.0px Consolas; color: #2b7ec3 } p.p2 { margin: 0.0px ...
- 《CSS3专业网页开发指南》笔记
书本:<CSS3专业网页开发指南>(the book of css3) Peter Gasston 著 李景媛 吴晓嘉 译 第1章: 1.box-sizing : IE8及以上版本 ...
- lvs DR模式
1.单机 director端ifconfig eth0:1 $vip broadcast $vip netmask 255.255.255.255 up ----broadcast广播(单机的时候加这 ...
- 并查集 Union-Find
并查集能做什么? 1.连接两个对象; 2.查询两个对象是否在一个集合中,或者说两个对象是否是连接在一起的. 并查集有什么应用? 1. Percolation问题. 2. 无向图连通子图个数 3. 最近 ...
- Fix network adapter not present problem in cloned CentOS
(You can find a lot of articles on this from the internet. I just put it here for my own record.) It ...
- 配置ubuntu 16.04.1 LTS odoo 10.0开发环境
使用VMware Fusion 8.5.0创建ubuntu 64bit虚拟机:使用ubuntu-16.04.1-desktop-amd64.iso镜像缺省安装ubuntu,用户名odoo,密码1234 ...
- 对VM挂载新加入的磁盘
在虚拟机配置中增加磁盘后,启动Linux,使用root登录. 首先查看未分区的磁盘,使用下面命令: ## 查看未使用的磁盘 fdisk -l 磁盘/dev/sdb后面没有任何分区,是新挂载的磁盘 输入 ...
- [stm32] MPU6050 HMC5883 Kalman 融合算法移植
一.卡尔曼滤波九轴融合算法stm32尝试 1.Kalman滤波文件[.h已经封装为结构体] /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronic ...
- [C++] 行程编码C++代码
#include<iostream> #include<string.h> #include<string> #include<cstring> #in ...