poj-2001

#include <stdio.h>
#include <string.h>
#include <vector>
#include <string>
#include <cstdlib>
#include <iostream>

using namespace std;

const int CHAR_NUM = 26;

struct tireNode{
    char val[22];
    struct tireNode * tireChildNode[CHAR_NUM];
    int appearTime;
    int byTime;
    int childNum;
    int index;
};

class stringInfo {
public:
    string orginal;
    string abbv;
    stringInfo(const string & str): orginal(str), abbv("") {
    }
};
typedef struct stringInfo stringInfo;
typedef struct tireNode tireNode;

vector<stringInfo> V1;

tireNode * tireTreeHead;

void buildTireTree(char * word, int index) {
    if (!tireTreeHead) {
        tireTreeHead = (tireNode *)malloc(sizeof(tireNode));
        memset(tireTreeHead, 0, sizeof(tireNode));
    }
    int wordLength = strlen(word);

    tireNode * currentNode = tireTreeHead;

    for (int i = 0; i < wordLength; i++) {
        if (!currentNode->tireChildNode[word[i]-'a']) {
            currentNode->tireChildNode[word[i]-'a'] = (tireNode *)malloc(sizeof(tireNode));
            memset(currentNode->tireChildNode[word[i]-'a'], 0, sizeof(tireNode));
            strcpy(currentNode->tireChildNode[word[i]-'a']->val, currentNode->val);
            currentNode->childNum++;
            currentNode->tireChildNode[word[i]-'a']->val[strlen(currentNode->val)] = word[i];
            currentNode->tireChildNode[word[i]-'a']->index = index;
        }
        currentNode = currentNode->tireChildNode[word[i]-'a'];
        (currentNode->byTime)++;
    }
    (currentNode->appearTime)++;
    // printf("build %s %d\n", currentNode->val, currentNode->appearTime);
}

void getShortsetPrefix(tireNode * currentNode) {
    if (!currentNode) {
        return;
    }
    if (currentNode->byTime == 1) {
        // printf("1 %d %s %s\n", currentNode->index, V1.at(currentNode->index).orginal.c_str(), currentNode->val);
        V1.at(currentNode->index).abbv = currentNode->val;
        return;
    }
    // if (currentNode->appearTime) {
    //     // printf("%s %s\n", currentNode->val, possiblePrefix.c_str());
    //     // printf("2 %s %s\n", V1.at(currentNode->index).c_str(), currentNode->val);
    // }

    for (int i = 0; i < CHAR_NUM; i++) {
        if (currentNode->tireChildNode[i]) {
            getShortsetPrefix(currentNode->tireChildNode[i]);
        }
    }
}

void printRes(vector<stringInfo> V) {
    if (!V.size()) {
        cout<<endl;
        // printf("\n");
    }
    vector<stringInfo>::iterator it = V.begin();

    for (;it != V.end(); it++) {
        if (it->abbv.empty()) {
            cout<<it->orginal<<" "<<it->orginal<<endl;
        } else {
            cout<<it->orginal<<" "<<it->abbv<<endl;
            // printf("%s %s\n", it->orginal.c_str(), it->abbv.c_str());
        }
    }

}

int main() {
        char word[22] = {0};
        tireTreeHead = NULL;
        V1.clear();
        while(scanf("%s", word) != EOF) {
            // if (!strcmp(word, "end")) {
            //     break;
            // }
            V1.push_back(stringInfo(word));
            buildTireTree(word, V1.size()-1);
        }
        getShortsetPrefix(tireTreeHead);
        printRes(V1);
        return 0;
}

G++ 1224K 47MS

tire树系列题, 这次用的是动态tire树,静态应该更快,这次也让我意识到,tire树建树本身不是题考察的重点,而是在建立好tire树以后,

如何用这棵树得到最后想要的结果。

题意是得到能无疑义表示该单词的缩写, 想了好久,不知道该如何表示这种abbv,

后来才想明白:

tire树其实是一条条字符串 顺序字符分解 所经过的路径的组合, 那么如何唯一的标示一个字符串? 2种case:

case1: 单词的整个路径都被其他的单词路过,及该单词必是其他单词的前缀,那么唯一表示办法abbv就是单词本身。

case2:  单词在某个字符以后所经过的路径没有被其他单词所经过过,那么唯一标示此单词的abbv就是前面的共享的前缀将上自己独有路径的第一个字符即可.

自己对tire树还是理解不够深入,从路径角度思考,就好理解很多。

那么在有了上面这个条件以后,就好办了, 只需为每个tire node加上一个byTime 来记录有多少个字符串经过此处,

然后在后面遍历此tire数时,察看当前node的byTime是否为1即可,如果是1,那么必定是某个字符串的独有路径,此node所记录的累加字符串即为该字符串的最短abbv,

并且直接return(这条路已经不需要再check了,可以理解为剪枝),遍历其他的tirenode。

本题比较烦人的是最后的输出,

还要按照原来的顺序输出原字符串与abbv, 及不但要得到abbv,还要能记录该abbv是对应于哪个原字符串。

我搞了一个很麻烦的法子,在原字符串输入时,就俺顺序为其分配相应的index,同时在建立tire树的时候,当有新路径被开辟时,tirenode中的index值会设置为此原字符串的index,这样就建立了起来映射关系,

而为了那些整个路径都被共享的原字符串(不能依靠byTime来区分),index在这种情况下也不能用,因为此公共路径的index在输入的时候会被改写多次。

因此就搞了一个复杂的class,存储orginal和addv, addv默认为空, 而original只有在上面遇到独有路径时才会根据node的index来设置vector中的相应的addv。

这样,最后遍历的时候,如果遇到abbv为空的情况,直接输出orginal orginal即可。

一开始WA了几次,原因是设置node的index的时候给了当前node,其实应该设给新建出来的node。

还要找找更好的办法,这个法子太ugly了.


#include <stdio.h>
#include <string.h>
#include <vector>
#include <string>
#include <cstdlib>
#include <iostream>

using namespace std;

const int CHAR_NUM = 26;

struct tireNode{
    char val[22];
    struct tireNode * tireChildNode[CHAR_NUM];
    int appearTime;
    int byTime;
    int childNum;
};

typedef struct stringInfo stringInfo;
typedef struct tireNode tireNode;

vector<string> V1;

tireNode * tireTreeHead;

void buildTireTree(char * word) {
    if (!tireTreeHead) {
        tireTreeHead = (tireNode *)malloc(sizeof(tireNode));
        memset(tireTreeHead, 0, sizeof(tireNode));
    }
    int wordLength = strlen(word);

    tireNode * currentNode = tireTreeHead;

    for (int i = 0; i < wordLength; i++) {
        if (!currentNode->tireChildNode[word[i]-'a']) {
            currentNode->tireChildNode[word[i]-'a'] = (tireNode *)malloc(sizeof(tireNode));
            memset(currentNode->tireChildNode[word[i]-'a'], 0, sizeof(tireNode));
            strcpy(currentNode->tireChildNode[word[i]-'a']->val, currentNode->val);
            currentNode->childNum++;
            currentNode->tireChildNode[word[i]-'a']->val[strlen(currentNode->val)] = word[i];
        }
        currentNode = currentNode->tireChildNode[word[i]-'a'];
        (currentNode->byTime)++;
    }
    (currentNode->appearTime)++;
}

void getShortsetPrefix(string word) {
    tireNode * currentNode = tireTreeHead;
    int wordLength = word.size();
    for (int i = 0; i < wordLength; i++) {
        if (currentNode->byTime == 1) {
            cout<<word<<" "<<currentNode->val<<endl;
            return;
        } else {
            if (currentNode->tireChildNode[word[i]-'a']) {
                currentNode = currentNode->tireChildNode[word[i]-'a'];
            }
        }
    }
    cout<<word<<" "<<word<<endl;
}

void printRes(vector<string> V) {
    if (!V.size()) {
        cout<<endl;
    }
    vector<string>::iterator it = V.begin();

    for (;it != V.end(); it++) {
        getShortsetPrefix(*it);
    }

}

int main() {
        char word[22] = {0};
        tireTreeHead = NULL;
        V1.clear();
        while(scanf("%s", word) != EOF) {
            // if (!strcmp(word, "end")) {
            //     break;
            // }
            V1.push_back(word);
            buildTireTree(word);
        }
        printRes(V1);
        return 0;
}

G++ 47ms

果然是我SB了,把问题复杂化了。。。

在用vector记录了输入的字符串以后,在输出的时候,只需遍历此vector,

用vector中保存的orginal 字符串对tire数组进行处理即可:

顺序遍历original的字符, 根据字符值沿着tire树中保存的路径一直向下走,沿路检查每个经过node的byTime,如果遇到=1的就输出此orginal abbv return。

否则,如果遍历完都找不到byTime == 1的node,那么可以就直接输出orginal original。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值