前缀树

用途:自动补全,拼音检查,ip路由(最长前缀匹配),九宫格打字预测

还有其他的数据结构,如平衡树和哈希表,使我们能够在字符串数据集中搜索单词。为什么我们还需要 Trie 树呢?尽管哈希表可以在 O(1)O(1) 时间内寻找键值,却无法高效的完成以下操作:

  1. 找到具有同一前缀的全部键值。
  2. 按词典序枚举字符串的数据集。

  Trie 树优于哈希表的另一个理由是,随着哈希表大小增加,会出现大量的冲突,时间复杂度可能增加到 O(n)O(n),其中 nn 是插入的键的数量。与哈希表相比,Trie 树在存储多个具有相同前缀的键时可以使用较少的空间。此时 Trie 树只需要 O(m)O(m) 的时间复杂度,其中 mm 为键长。而在平衡树中查找键值需要 O(m \log n)O(mlogn) 时间复杂度。

Trie 树是一个有根的树,其结点具有以下字段:。

  1. 最多 RR 个指向子结点的链接,其中每个链接对应字母表数据集中的一个字母。
  2. 本文中假定 RR 为 26,小写拉丁字母的数量。
  3. 布尔字段,以指定节点是对应键的结尾还是只是键前缀。
const int MAXN=;//英文字符个数
class Trie
{
private:
Trie *next[MAXN];
bool isEnd=false;
public:
/** Initialize your data structure here. */
Trie()
{
isEnd=false;
memset(next,,sizeof(next));
}
/** Inserts a word into the trie. */
void insert(string word)
{
if(word.empty())
return ; Trie *cur=this;//cur初始化根节点
for(auto c:word)
{
if(cur->next[c-'a']==nullptr)//看当前结点在前缀树中是否存在
{
Trie *node=new Trie();
cur->next[c-'a']=node;
}
cur=cur->next[c-'a'];//每个结点有个next和isEnd
}
cur->isEnd=true;//当前节点已经是一个完整的字符串
return ;
}
/** Returns if the word is in the trie. */
bool search(string word)
{
if(word.empty())
return false; Trie *cur=this;
for(auto c:word)
{
if(cur)
cur=cur->next[c-'a'];//若c在Trie中不存在,则cur->next[c-'a']为nullptr
}
return cur&&cur->isEnd?true:false;//cur不为空且cur指向的结点为一个完整的字符串,则为成功找到
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix)
{
if(prefix.empty())
return false; auto cur=this;
for(auto c:prefix)
{
if(cur)
cur=cur->next[c-'a'];
}
return cur?true:false;
}
};

  异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法。

#include <iostream>
#include <vector>
#include <cmath>
using namespace std; //1.暴力解O(n^3)
int get_max_eor(const vector<int>& arr)
{
if(arr.empty()||arr.size()<)
return -; int Max=-0x3f3f;
for(unsigned int i=;i<arr.size();++i)//以i结尾的每个子数组
{
for(unsigned int start=;start<=i;++start)//0..i/1..i/2..i等等,前两个for找所有的子数组
{
int Eor=;
for(unsigned int k=start;k<=i;++k)//遍历每个区间:k=[start..i],求每个区间的最大异或和,arr.at(k)
Eor^=(arr.at(k));
Max=max(Max,Eor);
}
}
return Max;
} //2.记忆化优化解O(n^2)
//0...i异或结果为Sum
//0...start-1异或结果为A
//start...i的异或结果为Sum^A
int get_max_eor1(const vector<int>& arr)
{
if(arr.size()<||arr.empty())
return -; int Eor=;
int Max=-0x3f3f;
for(unsigned int i=;i<arr.size();++i)
{
Eor^=arr.at(i);//遍历0...i,Xor保存每个以i结尾的最长数组的异或和
Max=max(Max,Eor);//一:可能是整个以i结尾的数组的异或和最大
int res=;
for(unsigned int start=;start<=i;++start)
{
res^=arr.at(start);//每个以i结尾的数组的前半部分
Max=max(Max,res^Eor);//二:可能是某个子数组的异或和最大
}
}
return Max;
}
//2 O(n^2)
int get_max_eor2(const vector<int>& arr)
{
if(arr.size()<||arr.empty())
return -; vector<int> dp(arr.size(),);
int Eor=;
int Max=-0x3f3f;
for(unsigned int i=;i<arr.size();++i)
{
Eor^=arr.at(i);
Max=max(Max,Eor);
for(unsigned int start=;start<=i;++start)
{
int res=Eor^dp[start-];
Max=max(Max,res);
}
dp.at(i)=Eor;
}
return Max;
}
//3
//0...i的异或结果Eor存
//0...0异或结果 0...1的异或结果 0...2的异或结果 直到0...i-1的异或结果(装入黑盒---前缀树)
typedef struct Node
{
Node *next[];
Node()
{
next[]=nullptr;
next[]=nullptr;
}
}Node;
class Trie
{
public:
int get_max_eor3(const vector<int>& arr);
~Trie()
{
delete head;
}
private:
int max_eor(const int &num);
void add(const int &num);
static Node *head;
};
Node* Trie::head=new Node(); int Trie::get_max_eor3(const vector<int>& arr)
{
if(arr.size()<||arr.empty())
return -; int Max=-0x3f3f;
int Eor=;
Trie trie;
trie.add(); for(unsigned int i=;i<arr.size();++i)
{
Eor^=arr.at(i);
Max=max(max_eor(Eor),Max);
add(Eor);
}
return Max;
} void Trie::add(const int& num)//把num添加到前缀树中
{
Node *cur=head;
int res=;
for(int move=;move>=;--move)
{
int path=((num>>move)&);//取每一位
cur->next[path]=(cur->next[path]==nullptr?new Node():cur->next[path]);
cur=cur->next[path];
}
}
//符号位尽量为0,后面的位是0走1,1走0,没得选就将就着走,尽量保持最大化值
//每次选最优,可以找到最大值
int Trie::max_eor(const int& num)//num和前缀树中的哪个值异或和最大
{
int res=;
Node *cur=head; for(int move=;move>=;--move)
{
int path=((num>>move)&);
int best=(move==?path:(path^));
best=(cur->next[best]!=nullptr?best:(best^));
res|=((path^best)<<move);
cur=cur->next[best];
}
return res;
} int main()
{
vector<int> arr{,,,,,,};
cout<<get_max_eor(arr)<<endl;
cout<<get_max_eor1(arr)<<endl;
cout<<get_max_eor2(arr)<<endl; Trie t;
cout<<t.get_max_eor3(arr)<<endl;
return ;
}

https://blog.csdn.net/v_july_v/article/details/6685962

子数组的最大异或和---Trie的更多相关文章

  1. 算法进阶面试题07——求子数组的最大异或和(前缀树)、换钱的方法数(递归改dp最全套路解说)、纸牌博弈、机器人行走问题

    主要讲第五课的内容前缀树应用和第六课内容暴力递归改动态规划的最全步骤 第一题 给定一个数组,求子数组的最大异或和. 一个数组的异或和为,数组中所有的数异或起来的结果. 简单的前缀树应用 暴力方法: 先 ...

  2. 【js】Leetcode每日一题-子数组异或查询

    [js]Leetcode每日一题-子数组异或查询 [题目描述] 有一个正整数数组 arr,现给你一个对应的查询数组 queries,其中 queries[i] = [Li, Ri]. 对于每个查询 i ...

  3. [LeetCode] 898. Bitwise ORs of Subarrays 子数组按位或操作

    We have an array A of non-negative integers. For every (contiguous) subarray B = [A[i], A[i+1], ..., ...

  4. [LeetCode] Minimum Size Subarray Sum 最短子数组之和

    Given an array of n positive integers and a positive integer s, find the minimal length of a subarra ...

  5. 剑指Offer面试题:28.连续子数组的最大和

    一.题目:连续子数组的最大和 题目:输入一个整型数组,数组里有正数也有负数.数组中一个或连续的多个整数组成一个子数组.求所有子数组的和的最大值.要求时间复杂度为O(n).例如输入的数组为{1,-2,3 ...

  6. lintcode循环数组之连续子数组求和

    v 题目:连续子数组求和 II 给定一个整数循环数组(头尾相接),请找出一个连续的子数组,使得该子数组的和最大.输出答案时,请分别返回第一个数字和最后一个数字的值.如果多个答案,请返回其中任意一个. ...

  7. 给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积。例如arr=[-2.5,4,0,3,0.5,8,-1],子数组[3,0.5,8]累乘可以获得最大的乘积12,所以返回12。

    分析,是一个dp的题目, 设f[i]表示以i为结尾的最大值,g[i]表示以i结尾的最小值,那么 f[i+1] = max{f[i]*arr[i+1], g[i]*arr[i+1],arr[i+1]} ...

  8. 查找二维数组list[][]中的最大的子数组的和

    之前做过最大一维数组子数组的和的题目,现在将数组扩展成二维: 代码如下: #include<iostream> #define null -858993460 using namespac ...

  9. 剑指Offer:面试题31——连续子数组的最大和(java实现)

    问题描述 : 输入一个整数数组,数组里面有正数也有负数.数组中一个或连续几个整数组成一个子数组.求所有子数组的和的最大值.要求时间复杂度为O(n) 思路1:常规解法,不知道怎么描述了.. 代码: bo ...

随机推荐

  1. R语言-默认镜像设置

    问题1:如何设置默认镜像 你希望下载某些R包,因此希望设定默认的CRAN网站镜像,这样R每次下载时不需要你选择镜像. 解决方案 该方案要求用户R系统中包含一个.Rprofile文件,如方法3.16描述 ...

  2. FLEX外包团队:Flex例子DEMO源码

    代码如下: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx=& ...

  3. 使用 R 语言挖掘 QQ 群聊天记录

    1.获取数据 从 QQ 消息管理器中导出消息记录,保存的文本类型选择 txt 文件.这里获取的是某群从 2016-04-18 到 2016-05-07 期间的聊天记录,记录样本如下所示. 消息记录(此 ...

  4. angular --- s3core移动端项目(三)

    angular.module('myApp') .directive('listActive',functon(){ return { restrict:'A', scope:{ listActive ...

  5. ubuntun 18.04 安装google浏览器

    ---恢复内容开始--- 一:下载谷歌浏览器镜像源 sudo wget http://www.linuxidc.com/files/repo/google-chrome.list -P /etc/ap ...

  6. bootStrap table 和 JS 开发过程中遇到问题汇总

    1..bootStrap-table表头固定 在table定义的时候给高度属性就可以自动生成滚动条,并且固定表头[height: 220,] 2.为动态生成的DOM元素绑定事件 on("cl ...

  7. 想做AI测试,需要学习哪些数学知识?

    摘自知乎的回答 作者:者也 以上是个人读研以来感受用得最多的数学基础课,挂一漏万,大侠请补充指正 高等数学是基础中的基础,研究生以上级别的一切理工科都需要这个打底,数据挖掘.人工智能.模式识别此类跟数 ...

  8. 【转】 pthread设置线程的调度策略和优先级

    转自:https://www.cnblogs.com/tianzeng/p/9192706.html 线程的调度有三种策略:SCHED_OTHER.SCHED_RR和SCHED_FIFO.Policy ...

  9. 20190315xlVBA_删除无用的区域

    '经常遇见天眼查表格文件特别大,原因是使用了整个表格,虽然无法解释为什么,但是经过验证以下代码是凑效的 Private Sub DeleteUselessRegion(ByVal sht As Wor ...

  10. 深入理解Plasma(三)Plasma MVP

    这一系列文章将围绕以太坊的二层扩容框架 Plasma,介绍其基本运行原理,具体操作细节,安全性讨论以及未来研究方向等.本篇文章主要介绍 Plasma 的一个最小实现 Plasma MVP(Minima ...