LeetCode刷題之路 --- 字典樹

 

目錄

1 字典樹的概念

2字典樹的套路

2 .1 字典樹的特點

2.2實現方法【通用模板】

3. Leetcode 648 單詞替換


1 字典樹的概念

       在算法導論中,Trie並不是叫字典樹,而是叫基數樹,也就是說實際上並不是只有和字符串有關。字典樹實際上是一個N叉樹 。 在這個N 二叉樹中,如果是共父節點的N個子節點是有序的,這樣構造出來的樹就和字典很像了,故叫字典樹。

      字典樹的功能實際上市對於很多的串進行壓縮,壓縮的方法是根據這個字符串的前綴。具體的說,就是每個字典樹的接管將表示一個字符,用從根節點到葉子節點來表示一個字符串。【好繞啊,看下面的圖 ==】

               

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章