LeetCode刷题之路 --- 字典树

 

目录

1 字典树的概念

2字典树的套路

2 .1 字典树的特点

2.2实现方法【通用模板】

3. Leetcode 648 单词替换


1 字典树的概念

       在算法导论中,Trie并不是叫字典树,而是叫基数树,也就是说实际上并不是只有和字符串有关。字典树实际上是一个N叉树 。 在这个N 二叉树中,如果是共父节点的N个子节点是有序的,这样构造出来的树就和字典很像了,故叫字典树。

      字典树的功能实际上市对于很多的串进行压缩,压缩的方法是根据这个字符串的前缀。具体的说,就是每个字典树的接管将表示一个字符,用从根节点到叶子节点来表示一个字符串。【好绕啊,看下面的图 ==】

               LeetCode刷题之路 --- 字典树_第1张图片

2字典树的套路

2 .1 字典树的特点

Trie Tree特点:
 1. 根节点不包含字符, 除根节点外每一个节点都只包含一个字符。

  2. 从根节点到某一节点, 路径上经过的字符连接起来, 为该节点对应的字符串。

  3. 在trie树中查找一个关键字的时间和树中包含的结点数无关, 而取决于组成关键字的字符数。 也就是查找字符串s的时间为O(strlen(s))

  4. 如果要查找的关键字可以分解成字符序列且不是很长, 利用Trie树查找速度优于二叉查找树。

  如:若关键字长度最大是5, 则利用Trie树, 利用5次比较可以从265=11881376个可能的关键字中检索出指定的关键字。 而利用二叉查找树至少要进行log2265=23.5次比较。

2.2实现方法【通用模板】

定义:

/* 定义Trie */
typedef struct _info_trie
{
    int flag;    /* 标记位,对应单词的编号 */
    struct _info_trie *nxt[26];
}info_trie;

查找:

int Find(char *s) {
    int t, 
    int p = 1;
    int len = strlen;
    for (int i = 0; i < len; i ++) {
        t = s[i] - 'a';
        if (trie[p]->nxt[t] == NULL) {
            return 0;         /* 当前要匹配值为t的字母,若没有则结束 */
        }
        p = trie[p]->nxt[t]; /* 若存在值为t的字母,则继续匹配 */
    } 
    return trie[p]->flag;    /* 若for循环执行完毕,说明找到了需要的单词,返回其编号 */
}

插入:

void Insert(int *s, int k) {
    int t; 
    int p = 1;
    int len = strlen(s);
    for (int i = 0; i < len; i ++) {
        /* 将字符c[i]转换成值为0到25的数字,比如'a'转换为0,'b'转换为1,‘c’转换为2… */
        t = c[i] - 'a';    
        if (trie[p]->nxt[t] == NULL) { /* 若p没有值为t的儿子 */
            tot++;                     / * 新增一个编号为tot的节点 */
            trie[p]->nxt[t] = tot;     /* 记下p的值为t的孩子节点的编号 */
            p = trie[p]->nxt[t];       /* p指向新添加的节点 */
            trie[p]->flag = 0;         /* 初始化新添加的节点,将其标记为不是单词的结尾
        } else {
            p = trie[p]->nxt[t];       /* 若p存在值为t的儿子,p指向该儿子,继续讨论 */
        }
    } 
    trie[p]->flag = k; //for循环已执行完,说明第k个单词已加入,在单词结尾做上标记
}

 

3. Leetcode 648 单词替换

LeetCode 648 : 单词替换 的完整答案如下

考试需要,最近一律《C语言版本》。

#define maxSize 100000
/* 定义Trie */
typedef struct _info_st
{
    int flag;    /* 标记位,对应单词的编号 */
    struct _info_st *nxt[26];
}info_st;

char * replaceWords(char ** dict, int dictSize, char * sentence)
{
    /* 构造字典树 len = maxSize * sizeof(info_st) */
    info_st * pool = (info_st *)calloc(maxSize, sizeof(info_st));  /* info_st * pool = (info_st *)malloc(sizeof(info_st) * maxSize);会报错 */
    int psize = 0;

    info_st *root = &pool[psize++];
    for(int i = 0; i < dictSize; i++)
    {
        int wordslen = strlen(dict[i]);  /* 字典里每个单词的长度 */
        info_st *cur = root;             /* 定义cur指向root */
        for(int j = 0; j < wordslen; j++) {
            int nid = dict[i][j] - 'a';  /* 都是小写字母 */
            if(cur->nxt[nid] == NULL)    /* 如果没有子节点,咱们就生成一个 */
            {
                cur->nxt[nid] = &pool[psize++];
            }
            cur = cur->nxt[nid];
        }
        cur->flag++;    /* flag = 1, 表示该单词结束 */
    }

    int slen = strlen(sentence);

    char * res = (char *)calloc(slen + 1, sizeof(char)); /* 改成char *res = (char *)malloc(sizeof(char) * (slen + 1))报错; */
    int rsize = 0;
    /* 双指针遍历并处理句子中的单词 */
    int wordsStart = 0;
    int wordsEnd = 0;
    while(wordsEnd < slen) {
        /* 遍历句子中的每个词 */
        if(sentence[wordsEnd] != ' ') {
            wordsEnd++;
            continue;
        }
        info_st *cur = root; /* 定义cur指向root */
        for(int i = wordsStart; i < wordsEnd; i++) {
            if(cur != NULL) {
                if(cur->flag > 0) { /* flag > 0 找到了能扩展的子串 */
                    break;
                }
                int nid = sentence[i] - 'a';
                cur = cur->nxt[nid];
            }
            res[rsize++] = sentence[i];
        }
        res[rsize++] = sentence[wordsEnd++]; /* 空格赋值 */
        wordsStart = wordsEnd;               /* 继续遍历句子中的下一个词 */
    }
    /* 处理最后一个单词 */
    info_st *cur = root;
    for(int i = wordsStart; i < wordsEnd; i++) {
        if(cur != NULL) {
            if(cur->flag > 0) {
                break;
            }
            int nid = sentence[i] - 'a';
            cur = cur->nxt[nid];
        }
        res[rsize++] = sentence[i];
    }
    res[rsize++] = '\0';
    return res;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

--@shanghai, 20200206

你可能感兴趣的:(LeetCode)