1
0
mirror of https://github.com/SunnyQjm/algorithm-review.git synced 2026-06-03 08:16:43 +08:00

add: chapter11

This commit is contained in:
2020-06-22 15:13:28 +08:00
parent ecca4239b9
commit 6bb6556d34
7 changed files with 527 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 208 实现 Trie (前缀树)
#
# 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。
#
# 示例:
# Trie trie = new Trie();
#
# trie.insert("apple");
# trie.search("apple"); // 返回 true
# trie.search("app"); // 返回 false
# trie.startsWith("app"); // 返回 true
# trie.insert("app");
# trie.search("app"); // 返回# true
#
# 说明:
# - 你可以假设所有的输入都是由小写字母 a-z 构成的。
# - 保证所有输入均为非空字符串。
#######################################################################################
class TreeNode:
def __init__(self):
self.word = False # 表示当前节点是否是一个曾经插入的单词
self.children = {} # 子节点列表
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = TreeNode()
def insert(self, word: str) -> None:
"""
Inserts a word into the trie.
"""
# 从根节点出发
node = self.root
for char in word:
if char not in node.children: # 判断当前字符是否在当前节点的子节点里面,不在,则创建一个子节点
node.children[char] = TreeNode()
node = node.children[char] # 跳到对应的子节点
node.word = True
def search(self, word: str) -> bool:
"""
Returns if the word is in the trie.
"""
node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.word
def startsWith(self, prefix: str) -> bool:
"""
Returns if there is any word in the trie that starts with the given prefix.
"""
node = self.root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True
# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)
if __name__ == '__main__':
obj = Trie()
obj.insert("apple")
print(obj.search("apple"), "= True")
print(obj.search("app"), "= False")
print(obj.startsWith("app"), "= True")
obj.insert("app")
print(obj.search("app"), "= True")
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 720 词典中最长的单词
#
# 给出一个字符串数组words组成的一本英语词典。从中找出最长的一个单词,该单词是由words词典中其他单词逐步添加一个字母组成。若其中有多个可行的答案,则返回答案中字典序最小的单词。
# 若无答案,则返回空字符串。
#
# 示例 1:
# 输入:
# words = ["w","wo","wor","worl", "world"]
# 输出: "world"
# 解释:
# 单词"world"可由"w", "wo", "wor", 和 "worl"添加一个字母组成。
#
# 示例 2:
# 输入:
# words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
# 输出: "apple"
# 解释:
# "apply"和"apple"都能由词典中的单词组成。但是"apple"得字典序小于"apply"。
#
# 注意:
# - 所有输入的字符串都只包含小写字母。
# - words数组长度范围为[1,1000]。
# - words[i]的长度范围为[1,30]。
#######################################################################################
from typing import List
class Solution:
def longestWord(self, words: List[str]) -> str:
"""
:type words: List[str]
:rtype str
(knowledge)
思路:
1. 用一个集合valid存储满足题目中限定的若干字符串;
2. 根据长度对原字符串列表排序,然后对排序后的字符串列表进行遍历;
3. 对每个字符串word,判断word[:-1]是否在valid当中,在则将其也放入到valid当中
4. 最后对valid进行按字典序排序,然后返回长度最大的元素即可
"""
valid = set([""])
for word in sorted(words, key=len):
if word[:-1] in valid:
valid.add(word)
return max(sorted(valid), key=len)
if __name__ == '__main__':
solution = Solution()
words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
print(solution.longestWord(words), "= apple")
@@ -0,0 +1,76 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 105 从前序与中序遍历序列构造二叉树
#
# 根据一棵树的前序遍历与中序遍历构造二叉树。
#
# 注意:
# 你可以假设树中没有重复的元素。
#
# 例如,给出
# 前序遍历 preorder = [3,9,20,15,7]
# 中序遍历 inorder = [9,3,15,20,7]
#
# 返回如下的二叉树:
# 3
# / \
# 9 20
# / \
# 15 7
#######################################################################################
from typing import List
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def __repr__(self):
if self:
return "{}->{}->{}".format(self.val, repr(self.left), repr(self.right))
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype TreeNode
(knowledge)
思路:
1. 首先根据中序定位根节点;
3 9 20 15 7
_
2. 然后根据先序,划分左右子树;
9 3 15 20 7
_
3. 然后将左右子树部分各自递归的进行构建即可
"""
if not preorder:
return None
root = TreeNode(preorder[0])
# 用于记录左右子树的元素个数
leftNum, rightNum = 0, 0
for num in inorder:
if num == preorder[0]:
break
leftNum += 1
root.left = self.buildTree(preorder[1:1+leftNum], inorder[0:leftNum])
root.right = self.buildTree(preorder[1+leftNum:], inorder[leftNum + 1:])
return root
if __name__ == '__main__':
solution = Solution()
solution.buildTree([3, 9, 20, 15, 7], [9, 3, 15, 20, 7])
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 997 找到小镇的法官
#
# 在一个小镇里,按从 1 到 N 标记了 N 个人。传言称,这些人中有一个是小镇上的秘密法官。
# 如果小镇的法官真的存在,那么:
# 1. 小镇的法官不相信任何人。
# 2. 每个人(除了小镇法官外)都信任小镇的法官。
# 3. 只有一个人同时满足属性 1 和属性 2 。
# 给定数组 trust,该数组由信任对 trust[i] = [a, b] 组成,表示标记为 a 的人信任标记为 b 的人。
# 如果小镇存在秘密法官并且可以确定他的身份,请返回该法官的标记。否则,返回 -1。
#
# 示例 1
# 输入:N = 2, trust = [[1,2]]
# 输出:2
#
# 示例 2
# 输入:N = 3, trust = [[1,3],[2,3]]
# 输出:3
#
# 示例 3
# 输入:N = 3, trust = [[1,3],[2,3],[3,1]]
# 输出:-1
#
# 示例 4
# 输入:N = 3, trust = [[1,2],[2,3]]
# 输出:-1
#
# 示例 5
# 输入:N = 4, trust = [[1,3],[1,4],[2,3],[2,4],[4,3]]
# 输出:3
#
# 提示:
# 1. 1 <= N <= 1000
# 2. trust.length <= 10000
# 3. trust[i] 是完全不同的
# 4. trust[i][0] != trust[i][1]
# 5. 1 <= trust[i][0], trust[i][1] <= N
#######################################################################################
from typing import List
class Solution:
def findJudge(self, N: int, trust: List[List[int]]) -> int:
"""
:type N: int
:type trust: List[List[int]]
:rtype int
(knowledge)
思路:
1. 将整个信任关系构建成一个图,a信任b表示a到b之间有条a->b的有向边;
2. 很容易直到,符合条件的法官要求入度为N-1,出度为0;
3. 所以只要找到入度为N-1的点,并判断其出度是否为0即可。
"""
# 特判只有一个人的情况,不构成图
if N == 1:
return 1
# 用两个字典分别记录入度和出度
inDegree, outDegree = {}, {}
# 遍历所有的边,记录所有的出度入度
for trust_element in trust:
if trust_element[0] in outDegree:
outDegree[trust_element[0]] += 1
else:
outDegree[trust_element[0]] = 1
if trust_element[1] in inDegree:
inDegree[trust_element[1]] += 1
else:
inDegree[trust_element[1]] = 1
# 遍历入度记录表,找到入度为N-1的人,并判断其出度是否为0
for key, value in inDegree.items():
if value == N - 1 and key not in outDegree:
return key
return -1
if __name__ == '__main__':
solution = Solution()
print(solution.findJudge(2, [[1, 2]]), "= 2")
print(solution.findJudge(3, [[1, 3], [2, 3]]), "= 3")
print(solution.findJudge(3, [[1, 3], [2, 3], [3, 1]]), "= -1")
print(solution.findJudge(3, [[1, 2], [2, 3]]), "= -1")
print(solution.findJudge(4, [[1, 3], [1, 4], [2, 3], [2, 4], [4, 3]]), "= 3")
@@ -0,0 +1,94 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 102 二叉树的层序遍历
#
# 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
#
# 示例:
# 二叉树:[3,9,20,null,null,15,7],
#
# 3
# / \
# 9 20
# / \
# 15 7
# 返回其层次遍历结果:
#
# [
# [3],
# [9,20],
# [15,7]
# ]
#######################################################################################
from typing import List
import collections
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def __repr__(self):
if self:
return "{}->{}->{}".format(self.val, repr(self.left), repr(self.right))
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
"""
:type root: TreeNode
:rtype List[List[int]]
(knowledge)
思路:
1. 采用图的BFS遍历的思想对树进行逐层遍历;
2. 用queue来实现BFS;(由于这边是树型结构,所以不会有环路,故不需要用visited来记录哪些节点已经访问过)
3. 为了记录当前遍历的节点在哪一层,我们用两个变量curLevelNum和nextLevelNum来分别记录当前层次还有多少没有遍历,以及下一层次还有多少没有遍历
tip: ppt中用的是DFS的方法,那种方法可以更容易的记录当前节点所属层级
"""
# 特判树为空的情况
if not root:
return []
# 初始时curLevelNum = 1表示要遍历的第一层为根节点只有一个
# 初始时nextLevelNum = 0,当遍历节点时,会增加下一层的可遍历节点数量
curLevelNum, nextLevelNum = 1, 0
result = [[]]
queue = collections.deque([root])
while queue:
curNode = queue.popleft()
result[-1].append(curNode.val)
curLevelNum -= 1
# 判断当前节点的左右节点是否存在,存在则入队
if curNode.left:
queue.append(curNode.left)
nextLevelNum += 1
if curNode.right:
queue.append(curNode.right)
nextLevelNum += 1
if curLevelNum == 0: # 判断是否换层
curLevelNum, nextLevelNum = nextLevelNum, 0
# 如果下一层还有可遍历的节点,则往结果集里面新加一个空列表用来存储下一层的遍历结果
if curLevelNum != 0:
result.append([])
return result
if __name__ == '__main__':
solution = Solution()
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)
print(solution.levelOrder(root), "= [[3], [9, 20], [15, 7]]")
@@ -0,0 +1,57 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 104 二叉树的最大深度
#
# 给定一个二叉树,找出其最大深度。
# 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
# 说明: 叶子节点是指没有子节点的节点。
#
# 示例:
# 给定二叉树 [3,9,20,null,null,15,7]
#
# 3
# / \
# 9 20
# / \
# 15 7
# 返回它的最大深度 3 。
#######################################################################################
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def __repr__(self):
if self:
return "{}->{}->{}".format(self.val, repr(self.left), repr(self.right))
class Solution:
def maxDepth(self, root: TreeNode) -> int:
"""
:type root: TreeNode
:rtype int
(knowledge)
思路:
1. 使用先序方法遍历,在遍历过程中传递当前层级深度;
2. 使用递归方式实现
"""
if not root:
return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1
if __name__ == '__main__':
solution = Solution()
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)
print(solution.maxDepth(root), "= 3")
@@ -0,0 +1,59 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 111 二叉树的最小深度
#
# 给定一个二叉树,找出其最小深度。
# 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
# 说明: 叶子节点是指没有子节点的节点。
#
# 示例:
# 给定二叉树 [3,9,20,null,null,15,7],
#
# 3
# / \
# 9 20
# / \
# 15 7
# 返回它的最小深度 2.
#######################################################################################
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def __repr__(self):
if self:
return "{}->{}->{}".format(self.val, repr(self.left), repr(self.right))
class Solution:
def minDepth(self, root: TreeNode) -> int:
"""
:type root: TreeNode
:rtype int
(knowledge)
思路:
1. 通过DFS递归遍历目标树,一旦遍历到叶子节点,马上返回
"""
if root is None:
return 0
if root.left and root.right:
return min(self.minDepth(root.left), self.minDepth(root.right)) + 1
return max(self.minDepth(root.left), self.minDepth(root.right)) + 1
if __name__ == '__main__':
solution = Solution()
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)
print(solution.minDepth(root), "= 2")