0
点赞
收藏
分享

微信扫一扫

LeetCode 剑指 Offer II 前缀树(下) 专题总结

往期文章 :

  • LeetCode 剑指 Offer II 链表 专题总结
  • LeetCode 剑指 Offer II 哈希表 专题总结
  • LeetCode 剑指 Offer II 栈 专题总结
  • LeetCode 剑指 Offer II 队列 专题总结
  • LeetCode 剑指 Offer II 树(上) 专题总结
  • LeetCode 剑指 Offer II 树(下) 专题总结
  • LeetCode 剑指 Offer II 堆 专题总结
  • LeetCode 剑指 Offer II 前缀树(上) 专题总结

第一题:后缀,
第二题:前缀,用哈希更好
第三题:01 Trie树

目录

065. 最短的单词编码

题目:

示例:

提示:

  • 1 <= words.length <= 2000
  • 1 <= words[i].length <= 7
  • words[i] 仅由小写字母组成

思路:

class Trie {
public:
    vector<Trie*> next;
    bool isEnd;
    Trie():next(26, nullptr),isEnd(false){}
    void insert(string& word) {
        Trie* node = this;
        // 反向插入
        for(int i = word.length() - 1; i >= 0; i--) {
            int index = word[i] - 'a';
            if(node->next[index] == nullptr) {
                node->next[index] = new Trie();
            }
            node = node->next[index];
        }
        node->isEnd = true;
    }
    int searchLen(string& word) {
        Trie* node = this;
        for(int i = word.length() - 1; i >= 0; i--) {
            int index = word[i] - 'a';
            node = node->next[index];
            // 找到单词最后一个字符,并且该字符是单词结尾
            if(node->isEnd && i == 0) {
                // 判断这个字符是不是结尾,不是的话就是后缀,不用处理
                for(int i = 0; i < 26; i++) {
                    if(node->next[i]) {
                        return 0;
                    }
                }
                // 将这个单词删除,将相同元素 adn 后缀元素删除
                node->isEnd = false;
                // 这个字符是结尾,返回 单词 + #
                return word.length() + 1;
            }
        }
        return 0;
    }
};

class Solution {
public:
    // 思路:本题含义是如果 x 是 y 的后缀,就删除x,不用统计
    int minimumLengthEncoding(vector<string>& words) {
        Trie* node = new Trie();
        for(auto& word : words) {
            node->insert(word);
        }
        int ans = 0;
        for(auto& word : words) {
            ans += node->searchLen(word);
        }
        return ans;
    }
};

066. 单词之和

题目:

示例:

提示:

  • 1 <= key.length, prefix.length <= 50
  • keyprefix 仅由小写英文字母组成
  • 1 <= val <= 1000
  • 最多调用 50insertsum

思路:

这道题用哈希表反而比前缀树简单不止一点半点,而且还快
题意:难点是 sum()函数,要找到prefix前缀的单词的val

方法一:哈希表

class MapSum {
public:
    unordered_map<string, int> map;
    MapSum() {
    }
    
    void insert(string key, int val) {
        map[key] = val;
    }
    
    int sum(string prefix) {
        int ans = 0, n = prefix.length();
        for(auto& [key, val] : map) {
            if(key.length() >= n && key.substr(0, n) == prefix)
                ans += val;
        }
        return ans;
    }
};

方法二:前缀树

class Trie {
private:
    int wordVal;
    vector<Trie*> next;
public:
    Trie():next(26,nullptr),wordVal(0){};
    // 插入,将结尾的bool 换成 int 就行
    void insert(string& word, int val) {
        Trie* node = this;
        for(char ch : word) {
            int index = ch - 'a';
            if(node->next[index] == nullptr) {
                node->next[index] = new Trie();
            }
            node = node->next[index];
        }
        node->wordVal = val;
    }
    // 先顺着前缀搜索下去,后面转而遍历每一种可能
    void searchPrefix(string& word, int& ans) {
        Trie* node = this;
        // 找到前缀的最后一个字符
        for(auto& ch : word) {
            // 没有word这个前缀就直接返回
            if(node->next[ch - 'a'] == nullptr)
                return ;
            node = node->next[ch - 'a'];
        }
        // 从这个字符开始遍历
        dfs(node, ans);
    }
    void dfs(Trie* node, int& ans) {
        if(node == nullptr) return ;

        // 如果是单词就加上
        if(node->wordVal > 0) 
            ans += node->wordVal;
        // 遍历前缀剩余可能的部分
        for(int i = 0; i < 26; i++) {
            dfs(node->next[i], ans);
        }
    }
};

class MapSum {
public:
    Trie* node;
    MapSum() {
        node = new Trie();
    }
    
    void insert(string key, int val) {
        node->insert(key, val);
    }
    
    int sum(string prefix) {
        int ans = 0;
        node->searchPrefix(prefix, ans);
        return ans;
    }
};

067. 最大的异或

题目:

示例:

提示:

  • 1 <= nums.length <= 2 * 104
  • 0 <= nums[i] <= 231 - 1

思路:

class Trie {
public:
    vector<Trie*> next;
    Trie():next(2,nullptr){}
    void insert(int x) {
        Trie* node = this;
        for(int i = 30; i >= 0; i--) {
            // 取x的第i位
            int u = (x >> i) & 1;
            if(node->next[u] == nullptr) {
                node->next[u] = new Trie();
            }
            node = node->next[u];
        }
    }
    int search(int x) {
        Trie* node = this;
        // 存储 x 能够异或的最大值
        int res = 0;
        for(int i = 30; i >= 0; i--) {
            int u = (x >> i) & 1;
            // 优先选择取该位反方向为最大 因为 1 ^ 0 = 1
            if(node->next[!u]) {
                node = node->next[!u];
                res = (res << 1) ^ !u;
            }else {
                // 没有的话取本身
                node = node->next[u];
                res = (res << 1) ^ u;
            }
        }
        // ans = res ^ x
        res ^= x;
        return res;
    }
};

class Solution {
public:
    int findMaximumXOR(vector<int>& nums) {
        Trie* node = new Trie();
        for(int i : nums) {
            node->insert(i);
        }
        int res = 0;
        for(int i : nums) {
            res = max(res, node->search(i));
        }
        return res;
    }
};
举报

相关推荐

0 条评论