题目链接:
30. Substring with Concatenation of All Words
给定字符串 s 和单词列表 words (其中所有 word 为等长字符串, 可以重复), 找出字符串 s 的 所有满足条件的子串的首字符的索引(index) ; 其中, 所有子串的内容均为 words 中所有 word 首尾连结而成的(顺序随意), 且所有单词均出现且仅完整出现一次 ;
解题过程:
(1) 考虑所有单词(word) 等长且必须在目标子串中互相首尾相连(故而 目标子串长度恒定), 故可以在遍历字符串 s 时不断进行逐词的检查(分别从每个下标), 一旦发现不符合要求立即转而开始从下一个字符开始进行检查 ;
(2) 一开始没有想到 words 中允许重复, 所以直接用 unordered_set 作处理, 后来发现重复的存在后就改用 unordered_multiset, 但这样便导致了超时, 所以还是要老老实实用 unordered_map (直接记录每个词的重复个数) ;
(*) 其实, 既然已经确定 "所有单词(word) 等长且必须在目标子串中互相首尾相连", 那么应该可以直接对 输入字符串 s 做逐词的检查, 也即 以词长为步进, (我这里就只是先逐个索引地遍历再(针对)每一次作处理, 显然有很多冗余检查), 因为目标子串所在的 "轨迹" 在 s 中是固定且有限的 ;
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ret;
auto wordLength = words.front().size();
if (s.size() < wordLength*words.size()) { return ret; }
unordered_map<string, int> existedWords;
for (auto w : words) {
existedWords[w]++;
}
for (size_t i = 0; i <= s.size() - wordLength; i++) {
bool match = true;
unordered_map<string, int> matchedWords;
for (auto j = i; j < i + wordLength * words.size(); j += wordLength) {
auto word = s.substr(j, wordLength);
if (existedWords[word] < 1 ||
matchedWords[word] >= existedWords[word]) {
match = false;
break;
}
matchedWords[word]++;
}
if (match) {
ret.push_back(i);
}
}
return ret;
}
};
Runtime: 256 ms