N叉树
LeetCode中N叉树的子节点用一个列表 node.children 来储存
遍历-3
N叉树的前序遍历,简单
递归:
class Solution:
def preorder(self, root: 'Node') -> List[int]:
ans = []
def order(root,ans):
if not root:
return
ans.append(root.val)
if root.children:
for node in root.children:
order(node,ans)
order(root,ans)
return ans
迭代:
class Solution:
def preorder(self, root: 'Node') -> List[int]:
if not root:
return []
stack,ans = [root],[]
while stack:
node = stack.pop()
ans.append(node.val)
if node.children:
stack.extend(reversed(node.children))
#也可以写成 stack.extend(node.children[::-1])
return ans
N叉树的后序遍历,简单
递归:
class Solution:
def postorder(self, root: 'Node') -> List[int]:
ans = []
def order(root,ans):
if not root:
return
if root.children:
for node in root.children:
order(node,ans)
ans.append(root.val)
order(root,ans)
return ans
迭代,假遍历,输出反向数组:
class Solution:
def postorder(self, root: 'Node') -> List[int]:
if not root:
return []
stack,ans = [root],[]
while stack:
node = stack.pop()
ans.append(node.val)
if node.children:
stack.extend(node.children)
return ans[::-1]
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
if not root:
return []
queue,ans,tempans = [root],[],[]
while queue:
nextqueue,tempans = [],[]
while queue:
node = queue.pop(0)
tempans.append(node.val)
if node.children:
nextqueue.extend(node.children)
ans.append(tempans)
queue = nextqueue
return ans
递归-1
N 叉树的最大深度,简单
自己写代码求最大值:
class Solution:
def maxDepth(self, root: 'Node') -> int:
if not root:
return 0
depth = 0
for item in root.children:
temp = self.maxDepth(item)
if temp > depth:
depth = temp
return depth + 1
用max求列表最大值:
class Solution:
def maxDepth(self, root: 'Node') -> int:
if not root:
return 0
if root.children == []: #这个判断必须要加,否则root.children为空时不存在 i ,求不出max
return 1
return max(self.maxDepth(i) for i in root.children) + 1
前缀树
基本操作
实现 Trie (前缀树),中等
用字典来存节点的信息,键位字符,值为子节点的字典
为了区分开 search方法和 startwith方法,插入单词的时候需要在末尾添加一个‘#’终结符
class Trie:
def __init__(self):
self.dic = {}
def insert(self, word: str) -> None:
tree = self.dic
for i in word:
if i not in tree:
tree[i] = {}
tree = tree[i]
#单词结束的标志,表示到此为止了
tree['#'] = '#'
def search(self, word: str) -> bool:
tree = self.dic
for i in word:
if i not in tree:
return False
tree = tree[i]
if '#' in tree:
return True
return False
def startsWith(self, prefix: str) -> bool:
tree = self.dic
for i in prefix:
if i not in tree:
return False
tree = tree[i]
return True
实际应用-3
键值映射,中等
trie树,dfs求和
class MapSum:
def __init__(self):
self.dic = {}
self.sumval = 0
def insert(self, key: str, val: int) -> None:
tree = self.dic
for i in key:
if i not in tree:
tree[i] = {}
tree = tree[i]
tree['#'] = val
def dfs(self,tree):
if '#' in tree:
self.sumval += tree['#']
for item in tree.keys():
if item != '#':
self.dfs(tree[item])
def sum(self, prefix: str) -> int:
self.sumval = 0
tree = self.dic
for i in prefix:
if i not in tree:
return 0
tree = tree[i]
self.dfs(tree)
return self.sumval
另外的实现,为每一个节点维护一个前缀和的值,insert 的时候每个节点都加上当前的 val,sum 方法调用的时候就不用 dfs 了,减少 sum 的复杂度
但是更新 key的值需要重复遍历一遍 key,把原来的值减掉,增加了 insert 的复杂度
最后提交发现运行反而没有上面的方法快
求 sum 的操作多的话可以用下面这个
class MapSum:
def __init__(self):
self.dic = {}
def insert(self, key: str, val: int) -> None:
tree = self.dic
for i in key:
if i not in tree:
tree[i] = {}
tree[i]['S'] = 0
tree = tree[i]
tree['S'] += val
if '#' not in tree:
tree['#'] = val
return
repeated = tree['#']
tree['#'] = val #漏了这一句
tree = self.dic
for i in key:
tree = tree[i]
tree['S'] -= repeated
def sum(self, prefix: str) -> int:
tree = self.dic
for i in prefix:
if i not in tree:
return 0
tree = tree[i]
return tree['S']
添加与搜索单词 - 数据结构设计,中等
Trie树,识别到万能符 ‘.’ 之后深搜
class WordDictionary:
def __init__(self):
self.dic = {}
def addWord(self, word: str) -> None:
tree = self.dic
for i in word:
if i not in tree:
tree[i] = {}
tree = tree[i]
tree['#'] = '#'
def search(self, word: str) -> bool:
return self.dfs_search(self.dic,word)
def dfs_search(self,begin,word):
tree = begin
for i,item in enumerate(word):
if item == '.':
for k in tree.keys():
# k!='#'保证了word比dictionary里的条目恰好多一个'.'的情况不被识别成True
if self.dfs_search(tree[k],word[i+1::]):
return True
return False
elif item not in tree:
return False
tree = tree[item]
if '#' in tree:
return True
else: #长度不够word的不会被匹配
return False
数组中两个数的最大异或值,中等
转为二进制: bin()函数,返回前缀为 0b 的二进制字符串
将 nums 内的元素转化为二进制列表:nums = [[(x >> i) & 1 for i in range(n)][::-1] for x in nums]
用 tire树存储数组信息,用递归函数计算最大异或值:
递归函数嗯是讨论了两个节点 01 分布的所有情况
class Solution:
def findMaximumXOR(self, nums: List[int]) -> int:
n = len(bin(max(nums))) - 2
# x & 0b000001 = 最低位
nums = [[(x >> i) & 1 for i in range(n)][::-1] for x in nums]
maxXOR = 0
trie_dic = {}
for x in nums:
tree = trie_dic
for i in x:
if i not in tree:
tree[i] = {}
tree = tree[i]
xor_num1 = trie_dic
xor_num2 = trie_dic
def dfsfind(node1,node2,exp):
if exp < 0:
return 0
if 1 in node1:
if 0 in node2:
ans = 2 ** exp
if 0 in node1 and 1 in node2:
return ans + max(dfsfind(node1[1],node2[0],exp-1),dfsfind(node1[0],node2[1],exp-1))
else:
return ans + dfsfind(node1[1],node2[0],exp-1)
elif 0 in node1:
ans = 2 ** exp
return ans + dfsfind(node1[0],node2[1],exp-1)
else:
return dfsfind(node1[1],node2[1],exp-1)
elif 1 in node2:
ans = 2 ** exp
return ans + dfsfind(node1[0],node2[1],exp-1)
else:
return dfsfind(node1[0],node2[0],exp-1)
return dfsfind(xor_num1,xor_num2,n-1)
单词搜索 II,困难
用 Trie树 存words列表里的单词,然后遍历网格
如果网格上的字母在trie里,则dfs看其四周的字母在不在trie的节点里
找到‘#’了就把单词添加到答案列表,然后删掉‘#’避免重复
class Solution:
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
trie = {}
for word in words:
tree = trie
for alpha in word:
if alpha not in tree:
tree[alpha] = {}
tree = tree[alpha]
tree['#'] = '#'
m,n = len(board),len(board[0])
visited = [[False for _ in range(n)] for _ in range(m)]
ans = []
def dfs(x,y,now,tree):
if '#' in tree:
ans.append(now)
del tree['#']
visited[x][y] = True
if x > 0 and not visited[x-1][y] and board[x-1][y] in tree:
dfs(x-1,y,now+board[x-1][y],tree[board[x-1][y]])
if x < m-1 and not visited[x+1][y] and board[x+1][y] in tree:
dfs(x+1,y,now+board[x+1][y],tree[board[x+1][y]])
if y > 0 and not visited[x][y-1] and board[x][y-1] in tree:
dfs(x,y-1,now+board[x][y-1],tree[board[x][y-1]])
if y < n-1 and not visited[x][y+1] and board[x][y+1] in tree:
dfs(x,y+1,now+board[x][y+1],tree[board[x][y+1]])
visited[x][y] = False
for i in range(m):
for j in range(n):
if board[i][j] in trie:
dfs(i,j,board[i][j],trie[board[i][j]])
return ans
剪枝:删掉无子节点的节点,即在每一个dfs(x,y,now,tree)
后面加上if not tree: del tree
,其中的 tree 需要写得跟调用时的 tree 一模一样
#剪枝例
if x > 0 and not visited[x-1][y] and board[x-1][y] in tree:
dfs(x-1,y,now+board[x-1][y],tree[board[x-1][y]])
if not tree[board[x-1][y]]: del tree[board[x-1][y]]
#剪枝例
for i in range(m):
for j in range(n):
if board[i][j] in trie:
dfs(i,j,board[i][j],trie[board[i][j]])
if not trie[board[i][j]]: del trie[board[i][j]]