290.单词规律
给定一种规律pattern
和一个字符串str
,判断str
是否遵循相同的规律。
这里的遵循指完全匹配,例如,pattern
里的每个字母和字符串str
中的每个非空单词之间存在着双向连接的对应规律。
示例1
输入: pattern = "abba", str = "dog cat cat dog"
输出: true
示例2
输入:pattern = "abba", str = "dog cat cat fish"
输出: false
示例3
输入: pattern = "aaaa", str = "dog cat cat dog"
输出: false
提示
1 <= pattern.length <= 300
pattern
只包含小写英文字母1 <= str.length <= 3000
str
只包含小写英文字母和' '
str
不包含 任何前导或尾随对空格str
中每个单词都被单个空格分隔
思路
这道题的关键在于如何构建pattern
中字符和str
中单词的双向映射,这个双向映射能够保证一个字符对应一个单词,一个单词也只对应一个字符。可以用双哈希表来表示这种关系,即hashmap1[i] = j
和hashmap2[j] = i
。
代码
bool wordPattern(string pattern, string str) {
unordered_map<string, char> str2ch;
unordered_map<char, string> ch2str;
int m = str.length();
int i = 0;
// 逐个遍历模式串
for (auto ch : pattern) {
if (i > m) {
return false;
}
// 划分单词
int j = i;
while (j < m && str[j] != ' ') j++;
const string &tmp = str.substr(i, j - i);
// 如果以单词为键值的哈希表中存在tmp对应的值且这个值不等于当前字符,返回false
if (str2ch.count(tmp) && str2ch[tmp] != ch) {
return false;
}
// 如果以字符为键值的哈希表中存在ch对应的值且这个值不等于当前单词,返回false
if (ch2str.count(ch) && ch2str[ch] != tmp) {
return false;
}
// 这两句指令是为了初始化哈希表
str2ch[tmp] = ch;
ch2str[ch] = tmp;
i = j + 1;
}
return i > m;
}
763.划分字母区间
字符串s
由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
示例
输入:S = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少
提示
s
的长度在[1, 500]
之间。s
只包含小写字母'a'
到'z'
。
思路
由于同一个字母只能出现在同一个字段,因此同一个字母的第一次出现的下标位置和最后一次出现的下标位置必须出现在同一个片段。因此需要遍历字符串,得到每一个字母最后一次出现的下标位置。
- 从左到右遍历字符串,遍历的同时维护当前片段的开始下标 s t a r t start start和结束下标 e n d end end,初始条件 s t a r t = e n d = 0 start=end=0 start=end=0;
- 对于每个遍历到的字母 c c c,得到当前字母的最后一次出现的下标位置 e n d c end_c endc,则当前片段的结束下标一定不小于 e n d c end_c endc,因此令 e n d = m a x ( e n d , e n d c ) end=max(end, end_c) end=max(end,endc);
- 当访问到下标 e n d end end时,本片段访问结束,当前片段的下标范围是 [ s t a r t , e n d ] [start,end] [start,end],长度为 e n d − s t a r t + 1 end-start+1 end−start+1,将当前片段的长度加入返回值中,然后令 s t a r t = e n d + 1 start=end + 1 start=end+1
代码
vector<int> partitionLabels(string s) {
vector<int> result;
unordered_map<char, int> map; //记录char c 和其最后出现位置的 map
int start = 0, end = 0;
for (int i = 0; i < s.size(); i ++) {
map[s[i]] = i;
}
for (int i = 0; i < s.size(); i ++) {
end = max(end, map[s[i]]);
if (i == end) {
result.push_back(end - start + 1);
start = i + 1;
}
}
return result;
}
本文题目及部分解答来自力扣:290.单词规律和763.划分字母区间。