兄弟单词

 转载:http://www.ahathinking.com/archives/182.html(代码自己没编译运行过)

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

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

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

1
bool isStr, Node* next[26], vector<const char*> brothers

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

【测试用例】

1
2
3
4
5
6
7
8
9
10
11
input:
 
cba acb bc cb b
 
output:
 
cba acb
 
bc cb
 
b
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
 
#define MAXLEN 100  /* 单词最大长度 */
 
/* qsort比较函数 */
int charcmp(const void *p, const void *q)
{
    return *(char *)p - *(char *)q;
}
 
/* 打印输出 & 释放内存 */
void output(map<string,vector<char*>> dic)
{
    for(map<string,vector<char*>>::iterator it = dic.begin(); it != dic.end(); ++it)
    {
        for(vector<char *>::iterator itv = it->second.begin(); itv != it->second.end(); ++itv)
        {
            printf("%s ",*itv);
            free(*itv);
        }
        printf("\n");
    }
}
 
void main()
{
    map<string,vector<char*>> dic;  /* 存储<key,兄弟单词集> */
    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,定义存储兄弟单词的trie树结构;BroTrie.cpp,算法实现ey)

    
/******* BroTrie.h *******/
#include <vector>
 
#define BRANCHNUM 26
 
/* trie节点 */
struct TrieNode
{
    bool isStr;  // 标记是否构成串
    TrieNode * next[BRANCHNUM];
    vector<const char*> 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<const char*>::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 <iostream>
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、付费专栏及课程。

余额充值