The Truth of Sisyphus
  • Introduction
  • Deep Learning
    • Basics
      • Hinge Loss
      • Regularizations
      • Linear Classification
      • Multi-Class and Cross Entropy Loss
      • Batch Norm and other Normalizations
      • Optimization
      • Optimization Functions
      • Convolution im2col
      • Activation Functions
      • Derivatives
        • Derivatives of Softmax
        • A Smooth (differentiable) Max Function
      • Model Ensemble
      • Layers Python Implementation
    • Classification
      • Mobile friendly networks
      • Non-local Neural Networks
      • Squeeze-and-Excitation Networks
      • Further Attention Utilization -- Efficience & Segmentation
      • Group Norm
      • ShuffleNet V2
    • Segmentation
      • Several Instance Segmentation
      • A Peek at Semantic Segmentation
      • Design Choices for Mobile Friendly Deep Learning Models, Semantic Segmentation
      • Efficient Video Object Segmentation via Network Modulation
      • BiSeNet
      • DeepLabV3+
    • Detection
      • CornerNet
      • IoU-Net
      • Why smooth L1 is popular in BBox Regression
      • MTCNN-NCNN
      • DetNet
      • SSD Illustration
    • RNN Related
      • GRU vs LSTM
      • BERT
    • Reinforcement Learning
      • AutoML in Practice Review
      • DRL for optimal execution of profolio transaction
    • Multi-task
      • Multi-task Overview
      • What are the tricks in Multi-Task network design?
    • Neural Network Interpretation
      • Neuron Visualization
    • Deep Learning Frameworks
      • How does Caffe work
      • [Gluon] When to use (Hybrid)Sequential and (Hybrid)Block
      • Gluon Hybrid Intro
      • Gluon HybridBlocks Walk-Through
      • A quick tour of Torch internals
      • NCHW / NHWC in Pytorch
      • Static & Dynamic Computation Graph
    • Converting Between DL Frameworks
      • Things To Be Considered When Doing Model Converting
      • Caffe to TensorFlow
    • Computation Graph Optimization
      • Two ways of TensorRT to optimize Neural Network Computation Graph
      • Customized Caffe Memory Optimization
      • NCNN Memory Optimization
      • Symbolic Programs Advantages: More Efficient, Reuse Intermediate Memory, Operation Folding
    • Deep Learning Debug
      • Problems caused by dead ReLU
      • Loss jumps to 87.3365
      • Common Causes of NANs During Training
    • Deployment
      • Efficient Convolution Operation
      • Quantization
    • What I read recently
      • Know Google the Paper Way
      • ECCV 2018
      • Neural Machine Translation
      • Street View OCR Extraction System
      • Teaching Machines to Draw
      • Pixel to Graph
      • Burst Image Deblurring
      • Material for Masses
      • Learning to Separate Object Sounds by Watching Unlabeled Video
    • Papers / Posts to be read
    • Dummy thoughts
  • Machine Learning
    • Classification
    • Regression
    • Clustering
    • Dimension Reduction
    • Metrics
    • Regularization
    • Bayesian Example
    • Machine Learning System Design
    • Recommendation
    • Essentials of Machine Learning
    • Linear Regression
    • Logistic Regression
      • Logistic Function
    • Gaussian Discriminant Analysis
    • Naive Bayes
    • SVM
    • MLE vs MAP
    • Boosting
    • Frequent Questions
    • Conclusion of Machine Learning
  • Python notes
    • Python _ or __ underscores usage
    • Python Multiprocess and Threading Differences
    • Heapq vs. Q.PriorityQueue
    • Python decorator
    • Understanding Python super()
    • @ property
    • Python __all__
    • Is Python List a Linked List or Array
    • What is the "u" in u'Hello world'
    • Python "self"
    • Python object and class
    • Python Class' Instance method, Class method, and Static Methods Demystified
    • Python WTF
    • Python find first value index in a list: [list].index(val)
    • Sort tuples, and lambda usecase
    • Reverse order of range()
    • Python check list is empty
    • Python get ASCII value from character
    • An A-Z of useful Python tricks
    • Python nested function variable scope
    • Python reverse a list
    • Python priority queue -- heapq
  • C++ Notes
    • Templates
    • std::string (C++) and char* (or c-string "string" for C)
    • C++ printf and cout
    • Class Member Function
    • Inline
    • Scope Resolution Operator ::
    • Constructor
    • Destructor
    • Garbage Collection is Critical
    • C++ Question Lists
  • Operating System
    • Basics
    • Mutex & Semaphore
    • Ticket Selling System
    • OS and Memory
    • Sort implementation in STL
    • Compile, link, loading & run
    • How to understand Multithreading and Multiprocessing from the view of Operating System
  • Linux & Productivity
    • Jupyter Notebook on Remote Server
    • Nividia-smi monitoring
  • Leetcode Notes
    • Array
      • 11. Container With Most Water
      • 35. Search Insert Position
    • Linked List
      • Difference between Linked List and Array
      • Linked List Insert
      • Design of Linked List
      • Two Pointers
        • 141. Linked List Cycle
        • 142. Linked List Cycle II
        • 160. Intersection of two Linked List
        • 19. Remove N-th node from the end of linked list
      • 206. Reverse Linked List
      • 203. Remove Linked List Elements
      • 328. Odd Even Linked List
      • 234. Palindrome Linked List
      • 21. Merge Two Sorted Lists
      • 430. Flatten a Multilevel Doubly Linked List
      • 430. Flatten a Multilevel Doubly Linked List
      • 708. Insert into a Cyclic Sorted List
      • 138. Copy List with Random Pointer
      • 61. Rotate List
    • Binary Tree
      • 144. Binary Tree Preorder Traversal
      • 94. Binary Tree Iterative In-order Traverse
    • Binary Search Tree
      • 98. Validate Binary Search Tree
      • 285. Inorder Successor in BST
      • 173. Binary Search Tree Iterator
      • 700. Search in a Binary Search Tree
      • 450. Delete Node in a BST
      • 701. Insert into a Binary Search Tree
      • Kth Largest Element in a Stream
      • Lowest Common Ancestor of a BST
      • Contain Duplicate III
      • Balanced BST
      • Convert Sorted Array to Binary Search Tree
    • Dynamic Programming
      • 198. House Robber
      • House Robber II
      • Unique Path
      • Unique Path II
      • Best time to buy and sell
      • Partition equal subset sum
      • Target Sum
      • Burst Ballons
    • DFS
      • Clone Graph
      • General Introduction
      • Array & String
      • Sliding Window
  • Quotes
    • Concert Violinist Joke
    • 船 Ship
    • What I cannot create, I do not understand
    • Set your course by the stars
    • To-do list
Powered by GitBook
On this page
  1. Leetcode Notes
  2. Binary Search Tree

Kth Largest Element in a Stream

Previous701. Insert into a Binary Search TreeNextLowest Common Ancestor of a BST

Last updated 6 years ago

We have introduced the properties of a BST and how to perform the basic operations, including search, insertion and deletion, in a BST. Being familiar with these basic ideas, you will be able to apply a BST to solve a real problem.

The strength of a BST is that you can perform all search, insertion and deletion operations in O(h) time complexity even in the worst case.

Usually, if you want to store data in order and need several operations, such as search, insertion or deletion, at the same time, a BST might be a good choice.

An Example

Problem: Design a class to find the kth largest element in a stream.

A most obvious way to solve this problem is to sort the array in descending order first and then return the kth element in the array.

But we have to sort for the new element every time when we insert a new value in order to perform the search operation in O(1) time complexity. But the time complexity of the insertion operation will be O(N) in average. Therefore, time complexity will be O(N^2) in total.

Since we need insertion and search operations at the same time, what about using a BST to store the values?

As we know, for each node in a BST, all the values in the right subtree are larger than the value of the node itself while all the values in the left subtree are smaller than the value of the node.

In other word, for each node in a BST, if m nodes in the right subtree, the node itself is the m + 1 largest element in the existed array.

Think about the problem by yourself first. Feel free to store more than one value in a tree node. You might also want a counter in each node to indicate how many nodes there are in the subtree rooted at this node.

If you still don't have a clear clue about the solution, we provide the animation of an example for you:

1. Insertion

cur-img

2. Search

class KthLargest(object):
    def __init__(self, k, nums):
        self.window = nums
        self.k = k
        heapq.heapify(self.window) # Transform list x into a heap, in-place, in linear time.
        while len(self.window) > k:
            heapq.heappop(self.window) # Pop and return the smallest item from the heap, maintaining the heap invariant. To access the smallest item without popping it, use heap[0].
    
    # keep a K-size priority queue (heapq in python), and always make it updated and return the smallest of this group, which will be the k-th large element 
    def add(self, val):
        if len(self.window) < self.k:
            heapq.heappush(self.window, val) # Push the value item onto the heap, maintaining the heap invariant
        elif val > self.window[0]: # To access the smallest item without popping it, use heap[0]
            heapq.heapreplace(self.window, val) # This heapreplace operation is more efficient than a heappop() followed by heappush() and can be more appropriate when using a fixed-size heap.
        return self.window[0] # To access the smallest item without popping it, use heap[0]

BST solution:

class kthTreeNode(object):
	def __init__(self, x):
		self.val = x
		self.count = 1
		self.left = None
		self.right = None

class KthLargest(object):
    def __init__(self, k, nums):
        self.size = len(nums)
        self.k = k
        if not nums:
        	self.root = None
        else:
            self.root = kthTreeNode(nums[0])
            for i in range(1, len(nums)):
        	    # self.insertNode(nums[i])
                self.insertNodeRecursive(self.root, nums[i])
    
    def insertNode(self, val):
        if not self.root:
            self.root = kthTreeNode(val)
            self.size += 1
            return
    	cur = self.root
    	pre = None
    	while(cur):
    		pre = cur
    		if val < cur.val:
    			cur.count += 1
    			cur = cur.left
    		else:
    			cur.count += 1
    			cur = cur.right
    	if val < pre.val:
    		pre.left = kthTreeNode(val)
    	else:
    		pre.right = kthTreeNode(val)
        self.size += 1
        
    def insertNodeRecursive(self, cur, val):
        if not self.root:
            self.root = kthTreeNode(val)
            self.size += 1
            return self.root
        if not cur:
            self.size += 1
            return kthTreeNode(val)
        if val < cur.val:
            cur.count += 1  # don't forget to add count along the recursive loop
    	    cur.left = self.insertNodeRecursive(cur.left, val)
        else:
            cur.count += 1  # don't forget to add count along the recursive loop
            cur.right = self.insertNodeRecursive(cur.right, val)
        return cur

    def searchKth(self, root, k):
    	while(root):
    		rightCount = 0 if not root.right else root.right.count
    		if k == rightCount + 1: # root 是当前子🌲中 rightCout + 1 大的 node
    			return root.val
    		elif k < rightCount + 1: # k 小于 rightCout + 1 的话,说明 kth node 在右支中
    			return self.searchKth(root.right, k)
    		else: # k 大于 rightCount + 1 的话,说明 kth node 在左支中,且 kth node 变为左支子树里 (k - (rightCount + 1))th node,然后迭代进行
    			return self.searchKth(root.left, k - rightCount - 1)

    def add(self, val):
    	# self.insertNode(val)
        self.insertNodeRecursive(self.root, val)
    	return self.searchKth(self.root, self.k)
cur-img