From ecca4239b96c303224f3809612b0f575d6614c74 Mon Sep 17 00:00:00 2001 From: SunnyQjm Date: Mon, 22 Jun 2020 10:08:57 +0800 Subject: [PATCH] add: chapter10 --- ...common-ancestor-of-a-binary-search-tree.py | 74 +++++++++++++++++++ chapter10/2_balanced-binary-tree.py | 66 +++++++++++++++++ chapter10/3_binary-tree-paths.py | 63 ++++++++++++++++ .../4_kth-largest-element-in-a-stream.py | 74 +++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 chapter10/1_lowest-common-ancestor-of-a-binary-search-tree.py create mode 100644 chapter10/2_balanced-binary-tree.py create mode 100644 chapter10/3_binary-tree-paths.py create mode 100644 chapter10/4_kth-largest-element-in-a-stream.py diff --git a/chapter10/1_lowest-common-ancestor-of-a-binary-search-tree.py b/chapter10/1_lowest-common-ancestor-of-a-binary-search-tree.py new file mode 100644 index 0000000..002b9ee --- /dev/null +++ b/chapter10/1_lowest-common-ancestor-of-a-binary-search-tree.py @@ -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) + + diff --git a/chapter10/2_balanced-binary-tree.py b/chapter10/2_balanced-binary-tree.py new file mode 100644 index 0000000..0a6d50e --- /dev/null +++ b/chapter10/2_balanced-binary-tree.py @@ -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 diff --git a/chapter10/3_binary-tree-paths.py b/chapter10/3_binary-tree-paths.py new file mode 100644 index 0000000..8f37412 --- /dev/null +++ b/chapter10/3_binary-tree-paths.py @@ -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 + diff --git a/chapter10/4_kth-largest-element-in-a-stream.py b/chapter10/4_kth-largest-element-in-a-stream.py new file mode 100644 index 0000000..7a5b003 --- /dev/null +++ b/chapter10/4_kth-largest-element-in-a-stream.py @@ -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") +