字符串算法
目录
字符串处理
KMP
讲解视频:最浅显易懂的 KMP 算法讲解
|
|
字典树Trie
字典树Trie是一种高效地存储和查找字符串集合的数据结构,由“结点”和“带有字符的边〞构成。
典型应用是用于统计和排序大量的字符串(但不仅限于字符串),经常被搜索引擎系统用于文本词频统计。
它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
基本性质
- 结点本身不保存完整单词
- 从根结点到某一结点,路径上经过的字符连接起来即为该结点对应的单词
- 每个结点出发的所有边代表的字符都不相同
- 结点用于存储单词的额外信息(例如频次)
内部实现
-
字符集数组法(简单)
每个结点保存一个长度固定为字符集大小(例如26)的数组,以字符为下标,保存指向的结点空间复杂度为
O(结点数*字符集大小)
,查询的时间复杂度为O(单词长度)
适用于较小字符集,或者单词短、分布稠密的字典 -
字符集映射法(优化)
把每个结点上的字符集数组改为一个映射(词频统计:hashmap,排序:ordered map) 空间复杂度为
O(文本字符总数)
,查询的时间复杂度为O(单词长度)
,但常数稍大一些适用性更广
核心思想——空间换时间
-
无论是保存树的结构、字符集数组还是字符集映射,都需要额外的空间
-
利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的
-
分组思想:前缀相同的字符串在同一子树中
模版
-
一般实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
class Trie { public: Trie() { root = new Node(); } void insert(string word) { Node* cur = root; for (char ch : word) { if (cur->mp.find(ch) == cur->mp.end()) { cur->mp[ch] = new Node(); } cur = cur->mp[ch]; } ++cur->count; } bool search(string word) { Node* cur = root; for (char ch : word) { if (cur->mp.find(ch) == cur->mp.end()) return false; cur = cur->mp[ch]; } return cur->count > 0; } bool startsWith(string prefix) { Node* cur = root; for (char ch : prefix) { if (cur->mp.find(ch) == cur->mp.end()) return false; cur = cur->mp[ch]; } return true; } private: struct Node { int count; unordered_map<char, Node*> mp; Node() { count = 0; } }; Node* root; };
-
重构实现(更精简)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
struct Trie { public: /** Initialize your data structure here. */ Trie() { root = new Node(); } /** Inserts a word into the trie. */ void insert(string word) { find(word, true, true); } /** Returns if the word is in the trie. */ bool search(string word) { return find(word, true, false); } /** Returns if there is any word in the trie that starts with the given prefix. */ bool startsWith(string prefix) { return find(prefix, false, false); } private: struct Node { int count; unordered_map<char, Node*> child; Node() : count(0) {} }; Node* root; bool find(const string& s, bool exact_match, bool insert_if_not_exist) { Node* curr = root; for (char c : s) { if (curr->child.find(c) == curr->child.end()) { if (!insert_if_not_exist) return false; curr->child[c] = new Node(); } curr = curr->child[c]; } if (insert_if_not_exist) curr->count++; return exact_match ? curr->count > 0 : true; } };
一道有意思的Trie应用题
最大异或对
在给定的N个整数 A1,A2……An中选出两个进行 xor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数 N。
第二行输入N个整数 A1A1~An。
输出格式
输出一个整数表示答案。
数据范围
32位整数,N <= 1e5
|
|