如何找出字典中的兄弟单词

据说是百度的一个面试题,是这样描述的:

image

其实总结下问题描述其实是差不多的:给定一个字典(即单词序列),用户输入一个单词,求出字典中单词的变换?

一:

看到这个题目后,直觉是可能是这样的:求出输入单词的全部变换(假如单词的长度是n,则其全部变换有n!个。如果有相同的字母就不是n!了吧?),求出单词的变换后,判断每个变换是否在字典中。

例如对于输入abc,则其变换有3!=6种:abc、acb、bca、bac、cab、cba。然后在依次判断这6个单词(当然这里不是单词了,而是字符串)是否在字典中,如果在字典中则记录下来。

很明显这种思想的复杂度是比较高的,因为对于n稍微大点的话,n!是一个很可怕的递增过程,因此这个方法是不太可取的。

二:

考虑使用hash的方法。构造一个hash函数,该函数使得单词的变换具有相同的hash值。

可以构造这样的函数,给定一个字符串,其hash值是字符串中字母的有序排列。例如字符串cda对应的hash值是acd;zhang的hash值是aghnz,即是字母从小到大的排列。这样对于一个单词的变换其hash值是相同的。

有上面的介绍后可以根据下面的步骤来进行了:

1、根据输入单词求出其hash值,即将单词按字母从小到大进行排列。

2、遍历给定的字典,对于字典里的每个单词,求出其hash值,然后和上一步中求出的hash值进行比较,如果相等,那么这个单词就是输入单词的一个变换,否则不是。

当然上面的方法是可行的。不过时间复杂度是比较高的:

word_hash = hash(word); //如果使用快排,复杂度是nlgn

for(i=0; i<n; i++)//n

{

temp = hash(dic[i]); //nlgn

if(strcmp(temp, word_hash) == 0)

{

output   dic[i];

}

}

总的时间复杂度是n*nlgn(不知道算的正确不),当然,如果hash的时间复杂度降低的话还是很不错的。

通过上面可以知道其实可以提前求出字典中单词的hash值,然后再进行匹配的。这样可以有一个变化的方法:

利用c++中的mutilmap或者其他容器,将hash值和字典中的单词昨为一个pair保存在mutilmap中。pair的情况是:<hash(word), word>,其中hash(word)作为map的key,word作为value。

这样就可以遍历map进行判断了。当然也可以先对map进行排序,这样会更快点。

 

这大概就是这个题目的思路。

编程珠玑上有一些简单的介绍和一个程序实现;这本 STL.Tutorial.and.Reference.Guide 的第12~15章节都是分析了这个问题,不断的改进,是一个很详细的介绍,值得学习。

<think>好的,用户想用C语言实现查找兄弟单词的算法。首先,我需要明确什么是兄弟单词兄弟单词的定义通常是两个单词字母相同但顺序不同,比如“listen”和“silent”就是兄弟单词。所以,我需要一个方法来判断两个单词是否符合这个条件。 首先,用户的问题涉及到字符串处理,可能需要对单词进行排序或者统计字符频率。比如,可以将每个单词的字符按字母顺序排序,如果排序后的字符串相同,那么它们就是兄弟单词。例如,将“listen”和“silent”都排序为“eilnst”,这样就能判断它们是兄弟。 接下来,我需要考虑如何实现这个算法。可能的步骤包括:读取输入的单词列表,处理每个单词生成其排序后的形式,然后比较这些排序后的字符串是否相同。同时,用户可能需要输出所有符合条件的兄弟单词,并按字典序排列,最后输出指定的第k个兄弟单词。 然后,我需要参考用户提供的引用内容。比如引用[5]提到使用strcmp进行字符串比较,这可能用于排序后的字典序排列。另外,引用[2]和[4]中的查找算法可能对遍历和比较单词有帮助。例如,BF算法中的字符串比较逻辑可以借鉴,但这里更可能需要的是对字符的统计或排序。 接下来,我需要考虑具体实现。例如,定义一个结构体来存储原始单词及其排序后的版本。然后,遍历所有单词,生成排序后的键。当用户输入一个目标单词时,同样生成其排序后的键,并在结构体数组中查找所有具有相同键的单词,排除自身,收集这些兄弟单词。 此外,还需要处理输入输出。比如,用户输入可能包含多个单词一个整数k,程序需要解析这些输入,处理每个单词,最后输出兄弟单词的数量和按字典序排列后的第k个单词。 还需要注意边界情况,例如当k超出兄弟单词数量时的处理,或者输入中有重复单词时的处理。例如,如果用户输入的单词本身在列表中重复出现,是否需要排除这些情况。 可能遇到的难点是如何高效地比较和排序。对于每个单词进行排序的时间复杂度是O(m log m),其中m是单词长度。如果单词数量很大,这可能会影响性能。不过,根据用户的需求,可能这是一个合理的实现方式,尤其是对于练习项目来说。 最后,测试代码的正确性。例如,测试用例应该包括多个兄弟单词的情况,以及没有兄弟单词的情况。例如,输入“listen silent enlist tinsel”,目标单词是“listen”,k为2,应该输出正确的兄弟单词数量和第二个兄弟单词。 总结步骤: 1. 输入处理:读取单词列表和目标单词及k值。 2. 预处理每个单词,生成排序后的键。 3. 查找与目标单词具有相同键的单词,排除自身。 4. 收集兄弟单词,按字典序排序。 5. 输出数量和指定位置的单词。</think>### 如何用C语言实现查找兄弟单词的算法 #### 一、兄弟单词的定义 兄弟单词指两个单词包含**完全相同的字母**但排列顺序不同,例如: - 单词"listen"和"silent" - 单词"fried"和"fired" #### 二、算法实现步骤 1. **数据预处理** ```c typedef struct { char original[50]; // 原始单词 char sorted[50]; // 排序后的字母序列 } WordEntry; ``` 2. **生成字母特征码** 对每个单词的字母进行排序生成特征码,例如: ```c void generateKey(char *word, char *key) { strcpy(key, word); qsort(key, strlen(key), sizeof(char), compareChar); } ``` 3. **兄弟单词匹配逻辑** 遍历单词列表,比较目标单词的特征码与其他单词的特征码: ```c for (int i = 0; i < wordCount; i++) { if (strcmp(targetKey, wordList[i].sorted) == 0 && strcmp(targetWord, wordList[i].original) != 0) { // 找到兄弟单词 } } ``` 4. **字典序排序** 使用`qsort`配合自定义比较函数: ```c int compareWords(const void *a, const void *b) { return strcmp(*(const char**)a, *(const char**)b); } ``` #### 三、完整代码实现 ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_WORDS 100 // 字符比较函数 int compareChar(const void *a, const void *b) { return (*(char*)a - *(char*)b); } // 单词比较函数 int compareWords(const void *a, const void *b) { return strcmp(*(const char**)a, *(const char**)b); } typedef struct { char original[50]; char sorted[50]; } WordEntry; int main() { WordEntry wordList[MAX_WORDS]; int wordCount = 0; char input[500], target[50]; int k; // 读取输入数据 fgets(input, 500, stdin); scanf("%s %d", target, &k); // 分割单词并预处理 char *token = strtok(input, " "); while (token != NULL && wordCount < MAX_WORDS) { strcpy(wordList[wordCount].original, token); strcpy(wordList[wordCount].sorted, token); qsort(wordList[wordCount].sorted, strlen(token), sizeof(char), compareChar); wordCount++; token = strtok(NULL, " "); } // 生成目标特征码 char targetKey[50]; generateKey(target, targetKey); // 查找兄弟单词 char *brothers[MAX_WORDS]; int brotherCount = 0; for (int i = 0; i < wordCount; i++) { if (strcmp(targetKey, wordList[i].sorted) == 0 && strcmp(target, wordList[i].original) != 0) { brothers[brotherCount++] = wordList[i].original; } } // 排序并输出结果 qsort(brothers, brotherCount, sizeof(char*), compareWords); printf("%d\n", brotherCount); if (k > 0 && k <= brotherCount) { printf("%s\n", brothers[k-1]); } return 0; } ``` #### 四、算法特性分析 1. **时间复杂度** - 预处理阶段:$O(n \cdot m \log m)$(n为单词数量,m为单词长度) - 匹配阶段:$O(n)$ - 总时间复杂度:$O(n \cdot m \log m)$ 2. **空间复杂度** $O(n \cdot m)$,主要用于存储预处理后的单词数据 3. **关键点** - 通过字母排序生成特征码实现高效比对[^5] - 使用字典序排序保证输出顺序正确性[^2] 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值