1. 题目
题目描述
给定一种规律 pattern 和一个字符串 s ,判断字符串是否遵循相同的规律。
这里的遵循指完全匹配,例如,pattern 里的每个字母和字符串 s 中的每个非空单词之间存在双向一一映射的对应关系。
示例
输入:pattern = "abba", s = "dog cat cat dog"
输出:true
输入:pattern = "abba", s = "dog cat cat fish"
输出:false
输入:pattern = "aaaa", s = "dog cat cat dog"
输出:false
输入:pattern = "abba", s = "dog dog dog dog"
输出:false
约束
-
1≤pattern.length≤300
-
1≤s.length≤3000
-
s 只包含小写英文字母和单个空格,单词之间由单个空格分隔
-
pattern 只包含小写英文字母
2. 最佳解题思路描述(双向哈希映射 + stringstream 分割单词)
-
使用
stringstream按空格分割字符串s,提取所有单词存入数组; -
提前校验长度:
pattern字符数量必须等于单词总数,不等直接返回 false; -
建立两张哈希表实现双向唯一映射:
-
charToStr:pattern 字符 → 单词 -
strToChar:单词 → pattern 字符
-
-
同步遍历每个下标:
-
若字符已有映射,映射单词必须和当前单词一致,否则不匹配;
-
若字符无映射但当前单词已有反向映射,说明多对一冲突,返回 false;
-
无任何映射则双向存入哈希表;
-
-
全程无冲突则返回 true。
优势
完全复用 LC205 同构字符串的双向映射模板,逻辑统一,能拦截一对多、多对一两种非法映射;时间 O(n),n 为单词总数。
3. 可优化代码(逻辑完全正确,仅命名、格式优化)
#include <sstream>
#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:
bool wordPattern(string s, string t) {
vector<string> words;
stringstream ss(t);
string word;
while(ss >> word){
words.push_back(word);
}
unordered_map<char,string>hash;
unordered_map<string,char>hash2;
if (s.size() != words.size())
return false;
for(int i = 0;i<s.size();i++){
char c = s[i];
string c2 = words[i];
auto it = hash.find(c);
auto it2 = hash2.find(c2);
if(it != hash.end()){
if(it->second != c2) return false;
}
else if(it2 != hash2.end()){
if(it2->second != c) return false;
}
else{
hash[c] = c2;
hash2[c2] = c;
}
}
return true;
}
};
代码说明
-
正确性:无逻辑 bug,全部测试用例可通过,是标准解法;
-
可优化 / 规范点:
-
变量命名语义模糊:
hash→char2word,hash2→word2char; -
参数命名易混淆:形参
s存 pattern、t存句子,建议改为pattern、str提升可读性; -
可提前缓存
pattern.size(),避免循环重复取值; -
增加代码空格、换行,分支层次更清晰。
-
4. 规范优化版代码
#include <sstream>
#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:
bool wordPattern(string pattern, string str) {
vector<string> words;
stringstream ss(str);
string word;
while (ss >> word) {
words.push_back(word);
}
int n = pattern.size();
if (n != words.size()) return false;
unordered_map<char, string> char2word;
unordered_map<string, char> word2char;
for (int i = 0; i < n; ++i) {
char ch = pattern[i];
string wd = words[i];
auto it1 = char2word.find(ch);
auto it2 = word2char.find(wd);
if (it1 != char2word.end()) {
if (it1->second != wd) return false;
} else if (it2 != word2char.end()) {
if (it2->second != ch) return false;
} else {
char2word[ch] = wd;
word2char[wd] = ch;
}
}
return true;
}
};
5. 总结
-
本题和 LC205 同构字符串是同模板题型,区别仅为映射对象:字符↔单词;
-
核心必做两步:分割单词、双向哈希校验,缺一不可;
-
关键边界判断:pattern 长度和单词数组长度不一致直接 false;
-
只使用单向哈希会出现多对一误判(如
abba+dog dog dog dog),必须两张 map 双向校验。
6. 相关知识拓展
拓展 1:stringstream 分割特性
ss >> word 会自动以任意空白符分割,忽略首尾空格,完美适配本题单词分割需求;
若题目需要保留连续空格、多行文本,该方法不适用。
拓展 2:LC205 与 LC290 对比
| 题目 | 映射关系 | 处理步骤 |
|---|---|---|
| 205 同构字符串 | char ↔ char | 直接遍历双字符串,无需分割 |
| 290 单词规律 | char ↔ string | 先分割句子为单词数组,再双向映射 |
拓展 3:易错坑点
-
忘记判断 pattern 长度与单词数组长度,如
pattern="abc"、句子只有 2 个单词; -
仅使用一张单向哈希表,无法拦截多个字符映射同一个单词;
-
参数命名混淆 pattern 和句子,循环取值下标错位。
拓展 4:复杂度分析
-
时间复杂度 O(N):N 为句子总字符数,分割 + 遍历各一次;
-
空间复杂度 O(M):M 为不重复单词数量,哈希表存储映射关系。