mirror of
https://github.com/SunnyQjm/algorithm-review.git
synced 2026-06-03 08:16:43 +08:00
add: chapter10
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#######################################################################################
|
||||
# Leetcode 235 二叉搜索树的最近公共祖先
|
||||
#
|
||||
# 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
|
||||
# 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
|
||||
#
|
||||
# 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
|
||||
# 6
|
||||
# / \
|
||||
# 2 8
|
||||
# / \ / \
|
||||
# 0 4 7 9
|
||||
# / \
|
||||
# 3 5
|
||||
#
|
||||
# 示例 1:
|
||||
# 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
|
||||
# 输出: 6
|
||||
# 解释: 节点 2 和节点 8 的最近公共祖先是 6。
|
||||
#
|
||||
# 示例 2:
|
||||
# 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
|
||||
# 输出: 2
|
||||
# 解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
|
||||
#
|
||||
# 说明:
|
||||
# - 所有节点的值都是唯一的。
|
||||
# - p、q 为不同节点且均存在于给定的二叉搜索树中。
|
||||
#######################################################################################
|
||||
|
||||
|
||||
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 lowestCommonAncestor(self, root, p, q):
|
||||
"""
|
||||
:type root: TreeNode
|
||||
:type p: TreeNode
|
||||
:type q: TreeNode
|
||||
:rtype TreeNode
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 直接根据二叉搜索树的性质,对树进行先序遍历;
|
||||
2. 将两个目标节点根据节点值得大小,小的指定为left, 大的指定为right
|
||||
2. 如果找到一个节点,其值大于等于left.val,且小于等于right.val,则该节点即为要求的结果
|
||||
3. 如果当前节点不是目标节点,则对左右子树进行递归遍历
|
||||
"""
|
||||
def preOrderTraversal(root, left, right):
|
||||
if not root or (left.val <= root.val <= right.val):
|
||||
return root
|
||||
|
||||
leftResult = preOrderTraversal(root.left, left, right)
|
||||
rightResult = preOrderTraversal(root.right, left, right)
|
||||
return leftResult if not rightResult else rightResult
|
||||
|
||||
left = p if p.val < q.val else q
|
||||
right = p if p.val >= q.val else q
|
||||
return preOrderTraversal(root, left, right)
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#######################################################################################
|
||||
# Leetcode 110 平衡二叉树
|
||||
#
|
||||
# 给定一个二叉树,判断它是否是高度平衡的二叉树。
|
||||
# 本题中,一棵高度平衡二叉树定义为:
|
||||
# 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
|
||||
#
|
||||
# 示例 1:
|
||||
# 给定二叉树 [3,9,20,null,null,15,7]
|
||||
#
|
||||
# 3
|
||||
# / \
|
||||
# 9 20
|
||||
# / \
|
||||
# 15 7
|
||||
# 返回 true 。
|
||||
#
|
||||
# 示例 2:
|
||||
# 给定二叉树 [1,2,2,3,3,null,null,4,4]
|
||||
#
|
||||
# 1
|
||||
# / \
|
||||
# 2 2
|
||||
# / \
|
||||
# 3 3
|
||||
# / \
|
||||
# 4 4
|
||||
# 返回 false 。
|
||||
#######################################################################################
|
||||
|
||||
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 isBalanced(self, root):
|
||||
"""
|
||||
:type root: TreeNode
|
||||
:rtype bool
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 直接递归计算每个节点左右子树的高度;
|
||||
2. 根据AVL树的特性,如果任意一个节点的左右子树的高度差大于一,则该树不是AVL树,标记器高度为-1;
|
||||
3. 如果某个子树的高度计算为-1,则表示该子树不是AVL树,-1会一直传递到顶层。
|
||||
"""
|
||||
def preOrderTraversal(root):
|
||||
if not root:
|
||||
return 0
|
||||
leftNum = preOrderTraversal(root.left)
|
||||
rightNum = preOrderTraversal(root.right)
|
||||
if leftNum == -1 or rightNum == -1 or abs(leftNum - rightNum) > 1:
|
||||
return -1
|
||||
return 1 + max(leftNum, rightNum)
|
||||
return preOrderTraversal(root) != -1
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#######################################################################################
|
||||
# Leetcode 257 二叉树的所有路径
|
||||
#
|
||||
# 给定一个二叉树,返回所有从根节点到叶子节点的路径。
|
||||
# 说明: 叶子节点是指没有子节点的节点。
|
||||
#
|
||||
# 示例:
|
||||
# 输入:
|
||||
#
|
||||
# 1
|
||||
# / \
|
||||
# 2 3
|
||||
# \
|
||||
# 5
|
||||
#
|
||||
# 输出: ["1->2->5", "1->3"]
|
||||
#
|
||||
# 解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->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 binaryTreePaths(self, root):
|
||||
"""
|
||||
:type root: TreeNode
|
||||
:rtype List[str]
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 递归的进行先序遍历,过程中记录走过的路径;
|
||||
2. 当遍历到一个叶子节点时,将当前路径添加到结果集当中;
|
||||
"""
|
||||
def preorderTraversal(root, s, result):
|
||||
if not root:
|
||||
return
|
||||
if not root.left and not root.right:
|
||||
result.append(s + "->" + str(root.val))
|
||||
preOrderTraversal(root.left, s + "->" + str(root.val), result)
|
||||
preOrderTraversal(root.right, s + "->" + str(root.val), result)
|
||||
|
||||
if not root:
|
||||
return []
|
||||
if not root.left and not root.right:
|
||||
return [str(root.val)]
|
||||
s = str(root.val)
|
||||
result = []
|
||||
preOrderTraversal(root, s, result)
|
||||
return result
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
#######################################################################################
|
||||
# Leetcode 703 数据流中的第K大元素
|
||||
#
|
||||
# 设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。
|
||||
# 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。
|
||||
#
|
||||
# 示例:
|
||||
# int k = 3;
|
||||
# int[] arr = [4,5,8,2];
|
||||
# KthLargest kthLargest = new KthLargest(3, arr);
|
||||
# kthLargest.add(3); // returns 4
|
||||
# kthLargest.add(5); // returns 5
|
||||
# kthLargest.add(10); // returns 5
|
||||
# kthLargest.add(9); // returns 8
|
||||
# kthLargest.add(4); // returns 8
|
||||
#
|
||||
# 说明:
|
||||
# 你可以假设 nums 的长度≥ k-1 且k ≥ 1。
|
||||
#######################################################################################
|
||||
|
||||
import heapq
|
||||
|
||||
class KthLargest:
|
||||
|
||||
def __init__(self, k, nums):
|
||||
"""
|
||||
:type k: int
|
||||
:type nums: List[int]
|
||||
"""
|
||||
self.heap = nums
|
||||
heapq.heapify(self.heap) # 用一个列表作为堆(使用heapq对其操作)
|
||||
self.currentSize = len(nums) # 保存当前堆中元素的个数
|
||||
self.k = k
|
||||
while self.currentSize > k:
|
||||
heapq.heappop(self.heap)
|
||||
self.currentSize -= 1
|
||||
|
||||
|
||||
def add(self, val):
|
||||
"""
|
||||
:type val: int
|
||||
:rtype: int
|
||||
|
||||
(knowledge)
|
||||
|
||||
思路:
|
||||
1. 这是堆的应用,每次要返回第K大的元素,则表示我们只要维持当前最大的到第K大的元素即可,更小的可以忽略;
|
||||
2. 对初始传入的nums进行堆构造,并删除堆顶元素直至堆中元素个数小于等于k时停止;
|
||||
3. 每次插入时执行以下流程:
|
||||
- 首先判断当前堆的大小是k还是k-1;(因为题目中指出,nums >= k-1,所以初始堆中元素个数至少为k-1,又因为我们在初始化时进行了堆删除,删到小于等于k为止,所以堆中元素最多有k个)
|
||||
- 如果currentSize == k-1,则插入当前元素到堆中,并返回堆顶元素即可;
|
||||
- 如果currentSuze > k-1, 则将当前元素插入到堆中,接着再删除堆顶元素,并返回堆顶元素;(这样可以保证堆中元素一直是k个)
|
||||
"""
|
||||
if self.currentSize == self.k - 1:
|
||||
heapq.heappush(self.heap, val)
|
||||
self.size += 1
|
||||
else:
|
||||
heapq.heappush(self.heap, val)
|
||||
heapq.heappop(self.heap)
|
||||
|
||||
return self.heap[0]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
kthLargest = KthLargest(3, [4, 5, 8, 2])
|
||||
print(kthLargest.add(3), "= 4")
|
||||
print(kthLargest.add(5), "= 5")
|
||||
print(kthLargest.add(10), "= 5")
|
||||
print(kthLargest.add(9), "= 8")
|
||||
print(kthLargest.add(4), "= 8")
|
||||
|
||||
Reference in New Issue
Block a user