java中判断是否为兄弟单词的算法_兄弟单词 — 两种算法实现 | 学步园

兄弟单词这个题目最初见于《编程珠玑》,但是里面给出的方法是最笨的,一般不提倡采用吧;这个题目在之前的百度面试中也遇到过,本文实现两种方法的代码,方法如下:

方案一:使用数据结构 map。兄弟单词共用一个签名key,key为单词内部排序后的词条,list存储同一key的单词集合;相对于编程珠玑中的方法,该方法在空间上节省了每个单词一个key的空间;在时间上,不再需要二分查找,O(1)的查找;但是这种方法还可以优化,见方案二

方案二:使用trie树。trie树又称字典树,在面试题中关于“字符串”与“数字串”类型的问题中高频出现,非常实用。对于兄弟单词,兄弟单词公用一个key自不必说,只是trie的节点结构应该多出一个域list,用来存储key对应的兄弟单词;具体节点结构应该为

bool isStr, Node* next[26], vector brothers

该方案查询的复杂度为O(L),L为key的平均长度;空间上则有很大的优化,例如单词的key有“abc”、“abcd”、“abcde”之类的形式,则这些key也能达到空间公用,不过数据量大还好,数据量小,trie树开辟的空间还是有些浪费的,不多言,上代码:

【测试用例】

input:

cba acb bc cb b

output:

cba acb

bc cb

b

【方案一:使用哈希map实现兄弟单词】

#include

#include

#include

#include

using namespace std;

#define MAXLEN 100 /* 单词最大长度 */

/* qsort比较函数 */

int charcmp(const void *p, const void *q)

{

return *(char *)p - *(char *)q;

}

/* 打印输出 & 释放内存 */

void output(map> dic)

{

for(map>::iterator it = dic.begin(); it != dic.end(); ++it)

{

for(vector::iterator itv = it->second.begin(); itv != it->second.end(); ++itv)

{

printf("%s ",*itv);

free(*itv);

}

printf("\n");

}

}

void main()

{

map> dic; /* 存储 */

char word[MAXLEN];

int len = 0;

while(scanf("%s",word) != EOF) /* ctrl+z结束输入 */

{

len = strlen(word);

if(len > 0)

{

char * ptr = (char *) malloc(len+1);

strcpy(ptr,word);

qsort(word,len,sizeof(char),charcmp);

string key(word);

dic[key].push_back(ptr);

}

}

output(dic);

}

【方案二:使用trie树实现兄弟单词】

/******* BroTrie.h *******/

#include

#define BRANCHNUM 26

/* trie节点 */

struct TrieNode

{

bool isStr; // 标记是否构成串

TrieNode * next[BRANCHNUM];

vector bros; // 存储兄弟单词集

TrieNode():isStr(false)

{

memset(next,NULL,sizeof(next));

}

};

/* trie类 */

class BroTrie

{

public:

TrieNode * root;

BroTrie(){ root = new TrieNode(); }

/* 插入key对应的单词 */

void insert(const char *key, const char *word)

{ //check NULL....

TrieNode * location = root;

while(*key)

{

if(location->next[*key-'a'] == NULL)

{

TrieNode * tmp = new TrieNode();

location->next[*key-'a'] = tmp;

}

location = location->next[*key-'a'];

++key;

}

location->isStr = true;

location->bros.push_back(word);

}

/* 输出兄弟单词 & 释放内存 */

void outputBros(TrieNode * location)

{ // check NULL

if(location->isStr == true) // 是key串,则输出该key对应的兄弟单词集

{

for(vector::iterator iter = location->bros.begin();

iter != location->bros.end(); ++iter)

{

printf("%s ", *iter);

}

printf("\n");

}

for(int i = 0; i < BRANCHNUM; ++i) // 释放内存

{

if(location->next[i] != NULL)

{

outputBros(location->next[i]);

}

}

delete location;

}

};

/******* BroTrie.cpp *******/

#include

using namespace std;

#include "BroTrie.h"

#define MAXLEN 100 /* 单词最大长度 */

/* qsort比较函数 */

int charcmp(const void *p, const void *q)

{

return *(char *)p - *(char *)q;

}

void main()

{

BroTrie broWords;

char word[MAXLEN];

int len = 0;

while(scanf("%s",word) != EOF) /* ctrl+z结束输入 */

{

len = strlen(word);

if(len > 0)

{

char * ptr = (char *) malloc(len+1);

strcpy(ptr,word);

qsort(word,len,sizeof(char),charcmp);

broWords.insert(word,ptr);

}

}

broWords.outputBros(broWords.root);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值