单词规律
· 5 min read
力扣面试经典——290题
💡 参考代码:
/**
* 判断字符串s是否遵循pattern的规律
* @param pattern: 规律字符串,由小写字母组成
* @param s: 待检测字符串,由空格分隔的单词组成
* @return: 如果s遵循pattern规律返回true,否则返回false
*/
bool wordPattern(char * pattern, char * s){
// 用于存储pattern中每个字符对应的单词
char* charToWord[26] = {NULL}; // 26个字母的映射表
// 用于存储已映射的单词,避免多个字符映射到同一个单词
char* usedWords[3000]; // 最多3000个单词
int wordCount = 0;
// 复制字符串s,因为strtok会修改原字符串
char* sCopy = malloc(strlen(s) + 1);
strcpy(sCopy, s);
// 使用空格分割字符串s
char* token = strtok(sCopy, " ");
// 遍历pattern中的每个字符
for(int i = 0; pattern[i] != '\0'; i++){
// 如果s中的单词已经用完,但pattern还有字符,返回false
if(token == NULL){
free(sCopy);
return false;
}
char currentChar = pattern[i]; // 当前pattern字符
char* currentWord = token; // 当前单词
// 计算字符在数组中的索引(相对于'a')
int charIndex = currentChar - 'a';
// 检查当前字符是否已经有映射
if(charToWord[charIndex] == NULL){
// 检查当前单词是否已经被其他字符映射
for(int j = 0; j < wordCount; j++){
if(strcmp(usedWords[j], currentWord) == 0){
free(sCopy);
return false;
}
}
// 建立新的映射关系
charToWord[charIndex] = malloc(strlen(currentWord) + 1);
strcpy(charToWord[charIndex], currentWord);
usedWords[wordCount] = malloc(strlen(currentWord) + 1);
strcpy(usedWords[wordCount], currentWord);
wordCount++;
} else {
// 检查现有映射是否与当前单词匹配
if(strcmp(charToWord[charIndex], currentWord) != 0){
free(sCopy);
return false;
}
}
// 获取下一个单词
token = strtok(NULL, " ");
}
// 检查是否还有多余的单词
if(token != NULL){
free(sCopy);
return false;
}
// 释放分配的内存
for(int i = 0; i < 26; i++){
if(charToWord[i] != NULL){
free(charToWord[i]);
}
}
for(int i = 0; i < wordCount; i++){
free(usedWords[i]);
}
free(sCopy);
return true;
}
📖 总结:
点击展开题目总结
🤔 单词规律
1️⃣ 题目核心信息
🎯 功能描述:判断字符串s中的单词是否按照pattern字符串的规律排列,需要建立字符与单词之间的双向唯一映射关系
📥 输入输出:
- 输入:
pattern:规律字符串,只包含小写英文字母s:待检测字符串,包含空格分隔的小写英文字母单词
- 输出:布尔值,表示s是否遵循pattern的规律
2️⃣ 实现原理
💡 核心思路:使用哈希表建立字符与单词的双向映射关系,并验证这种映射的一致性
📋 实现步骤:
- 使用数组作为哈希表存储每个字符对应的单词
- 使用另一个数组记录已映射的单词,确保双向唯一性
- 按空格分割字符串s,同时遍历pattern字符和单词
- 对每个字符-单词对验证映射关系的一致性
3️⃣ 关键点解析
🎯 代码技巧
- 使用字符减去'a'的ASCII值作为数组索引,实现简单的哈希映射
- 双向映射检查:既要检查字符是否已有映射,也要检查单词是否已被其他字符映射
- 使用strtok函数方便地按分隔符分割字符串
4️⃣ 使用场景
✅ 适用情况:
- 需要验证两个序列之间是否存在一一对应的映射关系
- 模式匹配问题,如模板验证
- 双射关系验证场景
⚠️ 前提条件:
- pattern只包含小写英文字母
- s中的单词由单个空格分隔且不含前导或尾随空格
5️⃣ 复杂度分析
- ⏱️ 时间复杂度:O(n×m),其中n是pattern长度,m是平均单词长度
- 💾 空间复杂度:O(n×m),用于存储映射关系和分割后的单词
🚩 边界情况:
- pattern长度与单词数量不相等
- 空字符串或单字符pattern
- 单个单词或无单词的字符串s
💥 易错点:
- 忘记检查双向映射关系,只检查了字符到单词的映射
- 没有正确处理内存分配和释放导致内存泄漏
- 忽略了pattern遍历完后还需要检查是否还有剩余单词的情况
7️⃣ 补充说明
以 pattern = "abba", s = "dog cat cat dog" 为例,逐步执行代码:
-
初始化数据结构:
charToWord[26]全部为 NULLusedWords[]为空- 使用
strtok分割字符串 s 得到单词序列:["dog", "cat", "cat", "dog"]
-
第一次循环 (i=0):
currentChar = 'a',currentWord = "dog"charIndex = 'a' - 'a' = 0charToWord[0]为 NULL,建立新映射:charToWord[0] = "dog"usedWords[0] = "dog"wordCount = 1
-
第二次循环 (i=1):
currentChar = 'b',currentWord = "cat"charIndex = 'b' - 'a' = 1charToWord[1]为 NULL,建立新映射:charToWord[1] = "cat"usedWords[1] = "cat"wordCount = 2
-
第三次循环 (i=2):
currentChar = 'b',currentWord = "cat"charIndex = 'b' - 'a' = 1charToWord[1]已存在且等于 "cat",映射一致,继续执行
-
第四次循环 (i=3):
currentChar = 'a',currentWord = "dog"charIndex = 'a' - 'a' = 0charToWord[0]已存在且等于 "dog",映射一致,继续执行
-
检查是否还有剩余单词:
token = strtok(NULL, " ")返回 NULL,没有剩余单词
-
返回 true,表示匹配成功
这个例子展示了正确的双向映射关系:'a' ↔ "dog",'b' ↔ "cat",且按照 "abba" 的模式排列。
加载评论中...
