Leetcode学习笔记 N叉树&前缀树

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]

N 叉树的层序遍历,中等

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]]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值