给定一个BST,任务是找到大于或等于O(1)空间中第K个最大元素的所有元素的和。
例子:
Input : K = 3
8
/ \
7 10
/ / \
2 9 13
Output : 32
Explanation: 3rd largest element is 9 so sum of all
elements greater than or equal to 9 are
9 + 10 + 13 = 32.
Input : K = 2
8
/ \
5 11
/ \
2 7
\
3
Output : 19
Explanation: 2nd largest element is 8 so sum of all
elements greater than or equal to 8 are
8 + 11 = 19.
方法:这里的方法是进行反向有序遍历,并且在进行此操作时只需对访问的节点数进行计数即可。在访问的节点数小于等于K之前,请继续添加当前节点的数据。利用BST的反向有序遍历为我们提供了一个以降序排序的列表这一事实。但是使用递归或基于堆栈/队列的方法进行反向有序遍历,因为这两种技术都消耗O(n)额外的内存,而是利用反向Morris遍历来进行有序树遍历,这是一种内存有效且速度更快的方法基于线程二叉树的反向有序树遍历。
下面给出的是算法:
1) Initialize Current as root.
2) Initialize a "count" and "sum" variable to 0.
3) While current is not NULL :
3.1) If the current has no right child
a) Increment count and check if count is less than or equal to K.
1) Simply add the current node's data in "sum" variable.
b) Otherwise, Move to the left child of current.
3.2) Else, here we have 2 cases:
a) Find the inorder successor of current Node.
Inorder successor is the left most Node
in the right subtree or right child itself.
b) If the left child of the inorder successor is NULL:
1) Set current as the left child of its inorder successor.
2) Move current Node to its right child.
c) Else, if the threaded link between the current Node
and it's inorder successor already exists :
1) Set left pointer of the inorder successor as NULL.
2) Increment count and check if the count is less than or equal to K.
2.a) Simply add the current node's data in "sum" variable.
3) Otherwise, Move current to it's left child.
4)After the traversal is complete simply return the sum.
下面是上述方法的实现:
C++
// C++ program to find sum of
// K largest elements in BST using
// Reverse Morris Traversal
#include
using namespace std;
struct node {
int data;
struct node *left, *right;
};
// Add a new node
node* newNode(int item)
{
node* temp = new node;
temp->data = item;
temp->left = temp->right = NULL;
return temp;
}
// Function to find the sum of the K largest elements
// space efficient method used
int SumKLargestUsingReverseMorrisTraversal(node* root, int k)
{
node* curr = root;
int sum = 0;
int count = 0;
// while doing reverse inorder traversal
// keep track of visited nodes
while (curr) {
if (curr->right == NULL) {
// till count is less than k
if (++count <= k) {
sum += curr->data;
}
curr = curr->left;
}
else {
// finding the inorder successor node
// inorder successor is the left most in right subtree
node* succ = curr->right;
while (succ->left && succ->left != curr)
succ = succ->left;
if (succ->left == NULL) {
succ->left = curr;
curr = curr->right;
}
// if the threaded link already exists then simply
// revert back the tree to original form.
else {
succ->left = NULL;
if (++count <= k)
sum += curr->data;
curr = curr->left;
}
}
}
return sum;
}
// Driver Code
int main()
{
/* Constructed binary tree is
8
/ \
7 10
/ / \
2 9 13
*/
struct node* root = newNode(8);
root->right = newNode(10);
root->left = newNode(7);
root->left->left = newNode(2);
root->right->left = newNode(9);
root->right->right = newNode(13);
cout << SumKLargestUsingReverseMorrisTraversal(root, 3);
return 0;
}
Java
// Java program to find sum of
// K largest elements in BST using
// Reverse Morris Traversal
class GFG
{
static class node
{
int data;
node left, right;
};
// Add a new node
static node newNode(int item)
{
node temp = new node();
temp.data = item;
temp.left = temp.right = null;
return temp;
}
// Function to find the sum of the K largest elements
// space efficient method used
static int SumKLargestUsingReverseMorrisTraversal(node root, int k)
{
node curr = root;
int sum = 0;
int count = 0;
// while doing reverse inorder traversal
// keep track of visited nodes
while (curr != null)
{
if (curr.right == null)
{
// till count is less than k
if (++count <= k)
{
sum += curr.data;
}
curr = curr.left;
}
else
{
// finding the inorder successor node
// inorder successor is the left most in right subtree
node succ = curr.right;
while (succ.left != null && succ.left != curr)
succ = succ.left;
if (succ.left == null)
{
succ.left = curr;
curr = curr.right;
}
// if the threaded link already exists then simply
// revert back the tree to original form.
else
{
succ.left = null;
if (++count <= k)
sum += curr.data;
curr = curr.left;
}
}
}
return sum;
}
// Driver Code
public static void main(String[] args)
{
/* Constructed binary tree is
8
/ \
7 10
/ / \
2 9 13 */
node root = newNode(8);
root.right = newNode(10);
root.left = newNode(7);
root.left.left = newNode(2);
root.right.left = newNode(9);
root.right.right = newNode(13);
System.out.println(SumKLargestUsingReverseMorrisTraversal(root, 3));
}
}
// This code is contributed by PrinciRaj1992
Python3
# Python3 program to find sum of
# K largest elements in BST using
# Reverse Morris Traversal
class node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# Add a new node
def newNode(item):
temp = node(item)
return temp
# Function to find the sum of
# the K largest elements
# space efficient method used
def SumKLargestUsingReverseMorrisTraversal(root, k):
curr = root
sum = 0
count = 0
# while doing reverse inorder traversal
# keep track of visited nodes
while (curr):
if (curr.right == None):
# till count is less than k
count += 1
if (count <= k):
sum += curr.data
curr = curr.left
else:
# finding the inorder successor node
# inorder successor is the left most
# in right subtree
succ = curr.right
while (succ.left and
succ.left != curr):
succ = succ.left
if (succ.left == None):
succ.left = curr
curr = curr.right
# if the threaded link already exists
# then simply revert back the tree to
# original form.
else:
succ.left = None
count += 1
if (count <= k):
sum += curr.data
curr = curr.left
return sum
# Driver code
if __name__ == "__main__":
''' Constructed binary tree is
8
/ \
7 10
/ / \
2 9 13 '''
root = newNode(8)
root.right = newNode(10)
root.left = newNode(7)
root.left.left = newNode(2)
root.right.left = newNode(9)
root.right.right = newNode(13)
print(SumKLargestUsingReverseMorrisTraversal(root, 3))
# This code is contributed by Rutvik_56
C#
// C# program to find sum of
// K largest elements in BST using
// Reverse Morris Traversal
using System;
class GFG
{
public class node
{
public int data;
public node left, right;
};
// Add a new node
static node newNode(int item)
{
node temp = new node();
temp.data = item;
temp.left = temp.right = null;
return temp;
}
// Function to find the sum of the K largest elements
// space efficient method used
static int SumKLargestUsingReverseMorrisTraversal(node root, int k)
{
node curr = root;
int sum = 0;
int count = 0;
// while doing reverse inorder traversal
// keep track of visited nodes
while (curr != null)
{
if (curr.right == null)
{
// till count is less than k
if (++count <= k)
{
sum += curr.data;
}
curr = curr.left;
}
else
{
// finding the inorder successor node
// inorder successor is the left most in right subtree
node succ = curr.right;
while (succ.left != null && succ.left != curr)
succ = succ.left;
if (succ.left == null)
{
succ.left = curr;
curr = curr.right;
}
// if the threaded link already exists then simply
// revert back the tree to original form.
else
{
succ.left = null;
if (++count <= k)
sum += curr.data;
curr = curr.left;
}
}
}
return sum;
}
// Driver Code
public static void Main(String[] args)
{
/* Constructed binary tree is
8
/ \
7 10
/ / \
2 9 13 */
node root = newNode(8);
root.right = newNode(10);
root.left = newNode(7);
root.left.left = newNode(2);
root.right.left = newNode(9);
root.right.right = newNode(13);
Console.WriteLine(SumKLargestUsingReverseMorrisTraversal(root, 3));
}
}
// This code is contributed by 29AjayKumar
输出:
32
时间复杂度: O(N)
空间复杂度:O(1)