节点(pass,end,nexts)
pass:有多少个节点划过
end:有多少个字符串以该节点结尾
nexts数组:有多少条边,设为26长度的数组(表示从a-z),值为空表示不存在这条路,为node表示存在(即这条路的下一个节点)。
也可用hashmap表示:(key:a的ascii码,value:对应的node)
应用:
1、查询一个字符串(eg:hello)在数据集中出现过多少次:(哈希表可以也可以实现)
从h开始寻找,求hello尾节点的end值
2、查找多少词以某个单词(eg:hel)开头,求“l”的pass值。(哈希表无法实现)【复杂度于查询单词长度有关,与样本量无关】
注1:通过修改节点信息,可以实现很多功能
注2:改代码只能处理a-z的字符串,可用哈希表代替nexts数组实现更复杂功能。(key:a的ascii码,value:对应的node)
代码:
class TrieNode():
def __init__(self):
self.passs=0
self.end=0
self.nexts=[None for i in range(26)] #限制字符串中的字母“a-z”
class Trie():
def __init__(self):
self.root=None
def makeTrie(self):
self.root=TrieNode()
def insert(self,word): #插入一个字符串的方法
if word==None:
return
chs=list(word) #将字符串转化为一个个字母
node=self.root
index=0
for i in range(len(chs)):
index=ord(chs[i])-ord('a')#将字母转化成数字下标a-0,b-1,c-2....z-25
if node.nexts[index]==None: #如果没有,建立这个边
node.nexts[index]=TrieNode()
node=node.nexts[index] #node往下级跑
node.passs+=1 #沿途节点的pass值加一
node.end+=1 #尾部节点的end值加一
def search(self,word): #查字符串出现了几次
if word==None:
return 0
chs = list(word) # 将字符串转化为一个个字母
node = self.root
index = 0
for i in range(len(chs)):
index=ord(chs[i])-ord('a') #将字母转化成数字下标a-0,b-1,c-2....z-25
if node.nexts[index]==None: #如果走不下去,返回0
return 0
node=node.nexts[index] #继续往下走
return node.end #返回最后一个节点的end值
def dellete(self, word): #删除一个字符串的方法
if self.search(word) != 0: #判断是否存在
chs = list(word) # 将字符串转化为一个个字母
node = self.root
#node.passs-=1
index = 0
for i in range(len(chs)):
index = ord(chs[i]) - ord('a') # 将字母转化成数字下标a-0,b-1,c-2....z-25
node.nexts[index].passs-=1 #下一节点的pass值在减一之后是否等于0
if node.nexts[index].passs ==0 : # 如果等于0,整条链直接全舍去
node.nexts[index] = None
return
node = node.nexts[index] # node往下级跑
node.end-= 1 # 沿途节点的end值减一
def prefixnumber(self,word): #查找以word开头的字符串个数
if word==None:
return 0
chs = list(word) # 将字符串转化为一个个字母
node = self.root
index = 0
for i in range(len(chs)):
index = ord(chs[i]) - ord('a') # 将字母转化成数字下标a-0,b-1,c-2....z-25
if node.nexts[index]== None: # 进行不下去,说明没有字符串以该word开头
return 0
node = node.nexts[index]
return node.passs
trie=Trie()
trie.makeTrie()
print(trie.search("chen"))
trie.insert("chen")
print(trie.search("chen"))
trie.dellete("chen")
print(trie.search("chen"))
trie.insert("chen")
trie.insert("chen")
trie.insert("fei")
trie.insert("ting")
trie.insert("chena")
trie.insert("chenb")
print(trie.search("chen"))
print(trie.search("fei"))
print(trie.search("ting"))
print(trie.prefixnumber("chen"))
应用1:
子数组的最大异或和
方法1:预处理数组
def getmax1(arr):
eor=0
dp=[]
maxx=float("-inf")
for i in range(len(arr)):
eor^=arr[i] #0...i
maxx=max(maxx,eor)
for j in range(1,i+1):
cureor=eor^dp[j-1] #j..i=0...i^0...j-1
maxx=max(cureor,maxx)
dp[i]=eor
return maxx
方法2:前缀树
#0..i和0...?异或和最大
#首位相同,其他位相反
def getmax2(arr):
if not arr or len(arr)==0:
return 0
eor=0
maxx=float("-inf")
numtrie=NumTrie()
for i in range(len(arr)):
eor^=arr[i] #0...i
maxx=max(maxx,numtrie.maxeor(eor))
numtrie.addd(eor)
return maxx
class Node:
def __init__(self):
self.nexts=[None]*2 #0,1
class NumTrie:
def __init__(self):
self.head=Node()
def addd(self,num):
cur=self.head
for i in range(31,-1,-1):
path=(num>>i)&1 #提取出每一个位置上的数字
if cur.nexts[path]==None:
cur.nexts[path]=Node()
cur=cur.nexts[path]
#0...i
def maxeor(self,num):
cur=self.head
res=0
for i in range(31,-1,-1):
path=(num>>i)&1 #提取出每一个位置上的数字
if i==31: #符号位,相同,期待的位置
best=path
else: #数字位,取反
best=path^1
if cur.nexts[best]==None:
best^=1 #best路为空,被迫走另一条路
res|=(path^best)<<i
cur=cur.nexts[best] #继续往下走
return res
应用2:
题目:
给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。
找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。
你能在O(n)的时间解决这个问题吗?
示例:
输入: [3, 10, 5, 25, 2, 8]
输出: 28
解释: 最大的结果是 5 ^ 25 = 28.
class Node:
def __init__(self):
self.nexts=[None]*2 #0,1
class NumTrie:
def __init__(self):
self.head=Node()
def addd(self,num):
cur=self.head
for i in range(31,-1,-1):
path=(num>>i)&1 #提取出每一个位置上的数字
if cur.nexts[path]==None:
cur.nexts[path]=Node()
cur=cur.nexts[path]
def maxeor(self,num):
cur=self.head
res=0
for i in range(31,-1,-1):
path=(num>>i)&1 #提取出每一个位置上的数字
if i==31: #符号位,相同,期待的位置
best=path
else: #数字位,取反
best=path^1
if cur.nexts[best]==None:
best^=1 #best路为空,被迫走另一条路
res|=(path^best)<<i
cur=cur.nexts[best] #继续往下走
return res
class Solution:
def findMaximumXOR(self, nums) -> int:
tire=NumTrie()
maxx=float("-inf")
for i in range(len(nums)):
tire.addd(nums[i])
for i in range(len(nums)):
maxx=max(maxx,tire.maxeor(nums[i]))
return maxx