📜  在平衡的BST中找到具有给定总和的货币对

📅  最后修改于: 2021-05-24 21:14:16             🧑  作者: Mango

给定一个平衡二进制搜索树和一个目标和,编写一个函数,如果存在一对总和等于目标和的函数,则返回true,否则返回false。预期的时间复杂度为O(n),并且只能使用O(Logn)多余的空间。不允许对二进制搜索树进行任何修改。请注意,平衡BST的高度始终为O(Logn)。

这个问题主要是前一篇文章的扩展。在这里,我们不允许修改BST。

蛮力解决方案是考虑BST中的每一对,并检查总和是否等于X。此解决方案的时间复杂度将为O(n ^ 2)。
更好的解决方案是创建一个辅助数组,并在该数组中存储BST的有序遍历。数组将被排序,因为BST的顺序遍历始终会产生排序的数据。一旦我们进行了有序遍历,就可以配对O(n)时间(有关详细信息,请参见此内容)。该解决方案的工作时间为O(n),但需要O(n)辅助空间。

Java
// Java code to find a pair with given sum
// in a Balanced BST
import java.util.ArrayList;
 
// A binary tree node
class Node {
 
    int data;
    Node left, right;
 
    Node(int d)
    {
        data = d;
        left = right = null;
    }
}
 
class BinarySearchTree {
 
    // Root of BST
    Node root;
 
    // Constructor
    BinarySearchTree()
    {
        root = null;
    }
 
    // Inorder traversal of the tree
    void inorder()
    {
        inorderUtil(this.root);
    }
 
    // Utility function for inorder traversal of the tree
    void inorderUtil(Node node)
    {
        if (node == null)
            return;
 
        inorderUtil(node.left);
        System.out.print(node.data + " ");
        inorderUtil(node.right);
    }
 
    // This method mainly calls insertRec()
    void insert(int key)
    {
        root = insertRec(root, key);
    }
 
    /* A recursive function to insert a new key in BST */
    Node insertRec(Node root, int data)
    {
 
        /* If the tree is empty, return a new node */
        if (root == null) {
            root = new Node(data);
            return root;
        }
 
        /* Otherwise, recur down the tree */
        if (data < root.data)
            root.left = insertRec(root.left, data);
        else if (data > root.data)
            root.right = insertRec(root.right, data);
 
        return root;
    }
 
    // Method that adds values of given BST into ArrayList
    // and hence returns the ArrayList
    ArrayList treeToList(Node node, ArrayList
                                                 list)
    {
        // Base Case
        if (node == null)
            return list;
 
        treeToList(node.left, list);
        list.add(node.data);
        treeToList(node.right, list);
 
        return list;
    }
 
    // method that checks if there is a pair present
    boolean isPairPresent(Node node, int target)
    {
        // This list a1 is passed as an argument
        // in treeToList method
        // which is later on filled by the values of BST
        ArrayList a1 = new ArrayList<>();
 
        // a2 list contains all the values of BST
        // returned by treeToList method
        ArrayList a2 = treeToList(node, a1);
 
        int start = 0; // Starting index of a2
 
        int end = a2.size() - 1; // Ending index of a2
 
        while (start < end) {
 
            if (a2.get(start) + a2.get(end) == target) // Target Found!
            {
                System.out.println("Pair Found: " + a2.get(start) + " + " + a2.get(end) + " "
                                   + "= " + target);
                return true;
            }
 
            if (a2.get(start) + a2.get(end) > target) // decrements end
            {
                end--;
            }
 
            if (a2.get(start) + a2.get(end) < target) // increments start
            {
                start++;
            }
        }
 
        System.out.println("No such values are found!");
        return false;
    }
 
    // Driver function
    public static void main(String[] args)
    {
        BinarySearchTree tree = new BinarySearchTree();
        /*
                   15
                /     \
              10      20
             / \     /  \
            8  12   16  25    */
        tree.insert(15);
        tree.insert(10);
        tree.insert(20);
        tree.insert(8);
        tree.insert(12);
        tree.insert(16);
        tree.insert(25);
 
        tree.isPairPresent(tree.root, 33);
    }
}
 
// This code is contributed by Kamal Rawal


C#
// C# code to find a pair with given sum
// in a Balanced BST
using System;
using System.Collections.Generic;
 
// A binary tree node
public class Node {
 
    public int data;
    public Node left, right;
 
    public Node(int d)
    {
        data = d;
        left = right = null;
    }
}
 
public class BinarySearchTree {
 
    // Root of BST
    Node root;
 
    // Constructor
    BinarySearchTree()
    {
        root = null;
    }
 
    // Inorder traversal of the tree
    void inorder()
    {
        inorderUtil(this.root);
    }
 
    // Utility function for inorder traversal of the tree
    void inorderUtil(Node node)
    {
        if (node == null)
            return;
 
        inorderUtil(node.left);
        Console.Write(node.data + " ");
        inorderUtil(node.right);
    }
 
    // This method mainly calls insertRec()
    void insert(int key)
    {
        root = insertRec(root, key);
    }
 
    /* A recursive function to insert a new key in BST */
    Node insertRec(Node root, int data)
    {
 
        /* If the tree is empty, return a new node */
        if (root == null) {
            root = new Node(data);
            return root;
        }
 
        /* Otherwise, recur down the tree */
        if (data < root.data)
            root.left = insertRec(root.left, data);
        else if (data > root.data)
            root.right = insertRec(root.right, data);
 
        return root;
    }
 
    // Method that adds values of given BST into ArrayList
    // and hence returns the ArrayList
    List treeToList(Node node, List list)
    {
        // Base Case
        if (node == null)
            return list;
 
        treeToList(node.left, list);
        list.Add(node.data);
        treeToList(node.right, list);
 
        return list;
    }
 
    // method that checks if there is a pair present
    bool isPairPresent(Node node, int target)
    {
        // This list a1 is passed as an argument
        // in treeToList method
        // which is later on filled by the values of BST
        List a1 = new List();
 
        // a2 list contains all the values of BST
        // returned by treeToList method
        List a2 = treeToList(node, a1);
 
        int start = 0; // Starting index of a2
 
        int end = a2.Count - 1; // Ending index of a2
 
        while (start < end) {
 
            if (a2[start] + a2[end] == target) // Target Found!
            {
                Console.WriteLine("Pair Found: " + a2[start] + " + " + a2[end] + " "
                                  + "= " + target);
                return true;
            }
 
            if (a2[start] + a2[end] > target) // decrements end
            {
                end--;
            }
 
            if (a2[start] + a2[end] < target) // increments start
            {
                start++;
            }
        }
 
        Console.WriteLine("No such values are found!");
        return false;
    }
 
    // Driver code
    public static void Main(String[] args)
    {
        BinarySearchTree tree = new BinarySearchTree();
        /*
                15
                /     \
            10     20
            / \     / \
            8 12 16 25 */
        tree.insert(15);
        tree.insert(10);
        tree.insert(20);
        tree.insert(8);
        tree.insert(12);
        tree.insert(16);
        tree.insert(25);
 
        tree.isPairPresent(tree.root, 33);
    }
}
 
// This code contributed by Rajput-Ji


C++
/* In a balanced binary search tree
isPairPresent two element which sums to
a given value time O(n) space O(logn) */
#include 
using namespace std;
#define MAX_SIZE 100
 
// A BST node
class node {
public:
    int val;
    node *left, *right;
};
 
// Stack type
class Stack {
public:
    int size;
    int top;
    node** array;
};
 
// A utility function to create a stack of given size
Stack* createStack(int size)
{
    Stack* stack = new Stack();
    stack->size = size;
    stack->top = -1;
    stack->array = new node*[(stack->size * sizeof(node*))];
    return stack;
}
 
// BASIC OPERATIONS OF STACK
int isFull(Stack* stack)
{
    return stack->top - 1 == stack->size;
}
 
int isEmpty(Stack* stack)
{
    return stack->top == -1;
}
 
void push(Stack* stack, node* node)
{
    if (isFull(stack))
        return;
    stack->array[++stack->top] = node;
}
 
node* pop(Stack* stack)
{
    if (isEmpty(stack))
        return NULL;
    return stack->array[stack->top--];
}
 
// Returns true if a pair with target
// sum exists in BST, otherwise false
bool isPairPresent(node* root, int target)
{
    // Create two stacks. s1 is used for
    // normal inorder traversal and s2 is
    // used for reverse inorder traversal
    Stack* s1 = createStack(MAX_SIZE);
    Stack* s2 = createStack(MAX_SIZE);
 
    // Note the sizes of stacks is MAX_SIZE,
    // we can find the tree size and fix stack size
    // as O(Logn) for balanced trees like AVL and Red Black
    // tree. We have used MAX_SIZE to keep the code simple
 
    // done1, val1 and curr1 are used for
    // normal inorder traversal using s1
    // done2, val2 and curr2 are used for
    // reverse inorder traversal using s2
    bool done1 = false, done2 = false;
    int val1 = 0, val2 = 0;
    node *curr1 = root, *curr2 = root;
 
    // The loop will break when we either find a pair or one of the two
    // traversals is complete
    while (1) {
        // Find next node in normal Inorder
        // traversal. See following post
        // https:// www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
        while (done1 == false) {
            if (curr1 != NULL) {
                push(s1, curr1);
                curr1 = curr1->left;
            }
            else {
                if (isEmpty(s1))
                    done1 = 1;
                else {
                    curr1 = pop(s1);
                    val1 = curr1->val;
                    curr1 = curr1->right;
                    done1 = 1;
                }
            }
        }
 
        // Find next node in REVERSE Inorder traversal. The only
        // difference between above and below loop is, in below loop
        // right subtree is traversed before left subtree
        while (done2 == false) {
            if (curr2 != NULL) {
                push(s2, curr2);
                curr2 = curr2->right;
            }
            else {
                if (isEmpty(s2))
                    done2 = 1;
                else {
                    curr2 = pop(s2);
                    val2 = curr2->val;
                    curr2 = curr2->left;
                    done2 = 1;
                }
            }
        }
 
        // If we find a pair, then print the pair and return. The first
        // condition makes sure that two same values are not added
        if ((val1 != val2) && (val1 + val2) == target) {
            cout << "Pair Found: " << val1 << "+ " << val2 << " = " << target << endl;
            return true;
        }
 
        // If sum of current values is smaller,
        // then move to next node in
        // normal inorder traversal
        else if ((val1 + val2) < target)
            done1 = false;
 
        // If sum of current values is greater,
        // then move to next node in
        // reverse inorder traversal
        else if ((val1 + val2) > target)
            done2 = false;
 
        // If any of the inorder traversals is
        // over, then there is no pair
        // so return false
        if (val1 >= val2)
            return false;
    }
}
 
// A utility function to create BST node
node* NewNode(int val)
{
    node* tmp = new node();
    tmp->val = val;
    tmp->right = tmp->left = NULL;
    return tmp;
}
 
// Driver program to test above functions
int main()
{
    /*
                15
                / \
            10 20
            / \ / \
            8 12 16 25 */
    node* root = NewNode(15);
    root->left = NewNode(10);
    root->right = NewNode(20);
    root->left->left = NewNode(8);
    root->left->right = NewNode(12);
    root->right->left = NewNode(16);
    root->right->right = NewNode(25);
 
    int target = 33;
    if (isPairPresent(root, target) == false)
        cout << "\nNo such values are found\n";
    return 0;
}
 
// This code is contributed by rathbhupendra


C
/* In a balanced binary search tree isPairPresent two element which sums to
   a given value time O(n) space O(logn) */
#include 
#include 
#define MAX_SIZE 100
 
// A BST node
struct node {
    int val;
    struct node *left, *right;
};
 
// Stack type
struct Stack {
    int size;
    int top;
    struct node** array;
};
 
// A utility function to create a stack of given size
struct Stack* createStack(int size)
{
    struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));
    stack->size = size;
    stack->top = -1;
    stack->array = (struct node**)malloc(stack->size * sizeof(struct node*));
    return stack;
}
 
// BASIC OPERATIONS OF STACK
int isFull(struct Stack* stack)
{
    return stack->top - 1 == stack->size;
}
 
int isEmpty(struct Stack* stack)
{
    return stack->top == -1;
}
 
void push(struct Stack* stack, struct node* node)
{
    if (isFull(stack))
        return;
    stack->array[++stack->top] = node;
}
 
struct node* pop(struct Stack* stack)
{
    if (isEmpty(stack))
        return NULL;
    return stack->array[stack->top--];
}
 
// Returns true if a pair with target sum exists in BST, otherwise false
bool isPairPresent(struct node* root, int target)
{
    // Create two stacks. s1 is used for normal inorder traversal
    // and s2 is used for reverse inorder traversal
    struct Stack* s1 = createStack(MAX_SIZE);
    struct Stack* s2 = createStack(MAX_SIZE);
 
    // Note the sizes of stacks is MAX_SIZE, we can find the tree size and
    // fix stack size as O(Logn) for balanced trees like AVL and Red Black
    // tree. We have used MAX_SIZE to keep the code simple
 
    // done1, val1 and curr1 are used for normal inorder traversal using s1
    // done2, val2 and curr2 are used for reverse inorder traversal using s2
    bool done1 = false, done2 = false;
    int val1 = 0, val2 = 0;
    struct node *curr1 = root, *curr2 = root;
 
    // The loop will break when we either find a pair or one of the two
    // traversals is complete
    while (1) {
        // Find next node in normal Inorder traversal. See following post
        // https:// www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
        while (done1 == false) {
            if (curr1 != NULL) {
                push(s1, curr1);
                curr1 = curr1->left;
            }
            else {
                if (isEmpty(s1))
                    done1 = 1;
                else {
                    curr1 = pop(s1);
                    val1 = curr1->val;
                    curr1 = curr1->right;
                    done1 = 1;
                }
            }
        }
 
        // Find next node in REVERSE Inorder traversal. The only
        // difference between above and below loop is, in below loop
        // right subtree is traversed before left subtree
        while (done2 == false) {
            if (curr2 != NULL) {
                push(s2, curr2);
                curr2 = curr2->right;
            }
            else {
                if (isEmpty(s2))
                    done2 = 1;
                else {
                    curr2 = pop(s2);
                    val2 = curr2->val;
                    curr2 = curr2->left;
                    done2 = 1;
                }
            }
        }
 
        // If we find a pair, then print the pair and return. The first
        // condition makes sure that two same values are not added
        if ((val1 != val2) && (val1 + val2) == target) {
            printf("\n Pair Found: %d + %d = %d\n", val1, val2, target);
            return true;
        }
 
        // If sum of current values is smaller, then move to next node in
        // normal inorder traversal
        else if ((val1 + val2) < target)
            done1 = false;
 
        // If sum of current values is greater, then move to next node in
        // reverse inorder traversal
        else if ((val1 + val2) > target)
            done2 = false;
 
        // If any of the inorder traversals is over, then there is no pair
        // so return false
        if (val1 >= val2)
            return false;
    }
}
 
// A utility function to create BST node
struct node* NewNode(int val)
{
    struct node* tmp = (struct node*)malloc(sizeof(struct node));
    tmp->val = val;
    tmp->right = tmp->left = NULL;
    return tmp;
}
 
// Driver program to test above functions
int main()
{
    /*
                   15
                /     \
              10      20
             / \     /  \
            8  12   16  25    */
    struct node* root = NewNode(15);
    root->left = NewNode(10);
    root->right = NewNode(20);
    root->left->left = NewNode(8);
    root->left->right = NewNode(12);
    root->right->left = NewNode(16);
    root->right->right = NewNode(25);
 
    int target = 33;
    if (isPairPresent(root, target) == false)
        printf("\n No such values are found\n");
 
    getchar();
    return 0;
}


Java
/* In a balanced binary search tree
isPairPresent two element which sums to
a given value time O(n) space O(logn) */
import java.util.*;
class GFG
{
static final int MAX_SIZE= 100;
 
// A BST node
static class node
{
    int val;
    node left, right;
};
 
// Stack type
static class Stack
{
    int size;
    int top;
    node []array;
};
 
// A utility function to create a stack of given size
static Stack createStack(int size)
{
    Stack stack = new Stack();
    stack.size = size;
    stack.top = -1;
    stack.array = new node[stack.size];
    return stack;
}
 
// BASIC OPERATIONS OF STACK
static int isFull(Stack stack)
{
    return (stack.top - 1 == stack.size)?1:0 ;
}
 
static int isEmpty(Stack stack)
{
    return stack.top == -1?1:0;
}
 
static void push(Stack stack, node node)
{
    if (isFull(stack)==1)
        return;
    stack.array[++stack.top] = node;
}
 
static node pop(Stack stack)
{
    if (isEmpty(stack) == 1)
        return null;
    return stack.array[stack.top--];
}
 
// Returns true if a pair with target
// sum exists in BST, otherwise false
static boolean isPairPresent(node root, int target)
{
    // Create two stacks. s1 is used for
    // normal inorder traversal and s2 is
    // used for reverse inorder traversal
    Stack s1 = createStack(MAX_SIZE);
    Stack s2 = createStack(MAX_SIZE);
 
    // Note the sizes of stacks is MAX_SIZE,
    // we can find the tree size and fix stack size
    // as O(Logn) for balanced trees like AVL and Red Black
    // tree. We have used MAX_SIZE to keep the code simple
 
    // done1, val1 and curr1 are used for
    // normal inorder traversal using s1
    // done2, val2 and curr2 are used for
    // reverse inorder traversal using s2
    boolean done1 = false, done2 = false;
    int val1 = 0, val2 = 0;
    node curr1 = root, curr2 = root;
 
    // The loop will break when we either
  // find a pair or one of the two
    // traversals is complete
    while (true)
    {
       
        // Find next node in normal Inorder
        // traversal. See following post
        // https:// www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
        while (done1 == false)
        {
            if (curr1 != null)
            {
                push(s1, curr1);
                curr1 = curr1.left;
            }
            else
            {
                if (isEmpty(s1) == 1)
                    done1 = true;
                else
                {
                    curr1 = pop(s1);
                    val1 = curr1.val;
                    curr1 = curr1.right;
                    done1 = true;
                }
            }
        }
 
        // Find next node in REVERSE Inorder traversal. The only
        // difference between above and below loop is, in below loop
        // right subtree is traversed before left subtree
        while (done2 == false)
        {
            if (curr2 != null)
            {
                push(s2, curr2);
                curr2 = curr2.right;
            }
            else {
                if (isEmpty(s2) == 1)
                    done2 = true;
                else {
                    curr2 = pop(s2);
                    val2 = curr2.val;
                    curr2 = curr2.left;
                    done2 = true;
                }
            }
        }
 
        // If we find a pair, then print the pair and return. The first
        // condition makes sure that two same values are not added
        if ((val1 != val2) && (val1 + val2) == target)
        {
            System.out.print("Pair Found: " +
                             val1+ "+ " +
                             val2+ " = " + 
                             target +"\n");
            return true;
        }
 
        // If sum of current values is smaller,
        // then move to next node in
        // normal inorder traversal
        else if ((val1 + val2) < target)
            done1 = false;
 
        // If sum of current values is greater,
        // then move to next node in
        // reverse inorder traversal
        else if ((val1 + val2) > target)
            done2 = false;
 
        // If any of the inorder traversals is
        // over, then there is no pair
        // so return false
        if (val1 >= val2)
            return false;
    }
}
 
// A utility function to create BST node
static node NewNode(int val)
{
    node tmp = new node();
    tmp.val = val;
    tmp.right = tmp.left = null;
    return tmp;
}
 
// Driver program to test above functions
public static void main(String[] args)
{
    /*
                15
                / \
            10 20
            / \ / \
            8 12 16 25 */
    node root = NewNode(15);
    root.left = NewNode(10);
    root.right = NewNode(20);
    root.left.left = NewNode(8);
    root.left.right = NewNode(12);
    root.right.left = NewNode(16);
    root.right.right = NewNode(25);
 
    int target = 33;
    if (isPairPresent(root, target) == false)
        System.out.print("\nNo such values are found\n");
}
}
 
// This code is contributed by aashish1995


C#
/* In a balanced binary search tree
isPairPresent two element which sums to
a given value time O(n) space O(logn) */
using System;
using System.Collections.Generic;
 
public class GFG
{
static readonly int MAX_SIZE= 100;
 
// A BST node
public
 class node
{
    public
 int val;
    public
 node left, right;
};
 
// Stack type
public
 class Stack
{
    public
 int size;
    public
 int top;
    public
 node []array;
};
 
// A utility function to create a stack of given size
static Stack createStack(int size)
{
    Stack stack = new Stack();
    stack.size = size;
    stack.top = -1;
    stack.array = new node[stack.size];
    return stack;
}
 
// BASIC OPERATIONS OF STACK
static int isFull(Stack stack)
{
    return (stack.top - 1 == stack.size) ? 1 : 0 ;
}
 
static int isEmpty(Stack stack)
{
    return stack.top == -1?1:0;
}
 
static void push(Stack stack, node node)
{
    if (isFull(stack)==1)
        return;
    stack.array[++stack.top] = node;
}
 
static node pop(Stack stack)
{
    if (isEmpty(stack) == 1)
        return null;
    return stack.array[stack.top--];
}
 
// Returns true if a pair with target
// sum exists in BST, otherwise false
static bool isPairPresent(node root, int target)
{
    // Create two stacks. s1 is used for
    // normal inorder traversal and s2 is
    // used for reverse inorder traversal
    Stack s1 = createStack(MAX_SIZE);
    Stack s2 = createStack(MAX_SIZE);
 
    // Note the sizes of stacks is MAX_SIZE,
    // we can find the tree size and fix stack size
    // as O(Logn) for balanced trees like AVL and Red Black
    // tree. We have used MAX_SIZE to keep the code simple
 
    // done1, val1 and curr1 are used for
    // normal inorder traversal using s1
    // done2, val2 and curr2 are used for
    // reverse inorder traversal using s2
    bool done1 = false, done2 = false;
    int val1 = 0, val2 = 0;
    node curr1 = root, curr2 = root;
 
    // The loop will break when we either
  // find a pair or one of the two
    // traversals is complete
    while (true)
    {
       
        // Find next node in normal Inorder
        // traversal. See following post
        // https:// www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
        while (done1 == false)
        {
            if (curr1 != null)
            {
                push(s1, curr1);
                curr1 = curr1.left;
            }
            else
            {
                if (isEmpty(s1) == 1)
                    done1 = true;
                else
                {
                    curr1 = pop(s1);
                    val1 = curr1.val;
                    curr1 = curr1.right;
                    done1 = true;
                }
            }
        }
 
        // Find next node in REVERSE Inorder traversal. The only
        // difference between above and below loop is, in below loop
        // right subtree is traversed before left subtree
        while (done2 == false)
        {
            if (curr2 != null)
            {
                push(s2, curr2);
                curr2 = curr2.right;
            }
            else {
                if (isEmpty(s2) == 1)
                    done2 = true;
                else {
                    curr2 = pop(s2);
                    val2 = curr2.val;
                    curr2 = curr2.left;
                    done2 = true;
                }
            }
        }
 
        // If we find a pair, then print the pair and return. The first
        // condition makes sure that two same values are not added
        if ((val1 != val2) && (val1 + val2) == target)
        {
            Console.Write("Pair Found: " +
                             val1+ "+ " +
                             val2+ " = " + 
                             target +"\n");
            return true;
        }
 
        // If sum of current values is smaller,
        // then move to next node in
        // normal inorder traversal
        else if ((val1 + val2) < target)
            done1 = false;
 
        // If sum of current values is greater,
        // then move to next node in
        // reverse inorder traversal
        else if ((val1 + val2) > target)
            done2 = false;
 
        // If any of the inorder traversals is
        // over, then there is no pair
        // so return false
        if (val1 >= val2)
            return false;
    }
}
 
// A utility function to create BST node
static node NewNode(int val)
{
    node tmp = new node();
    tmp.val = val;
    tmp.right = tmp.left = null;
    return tmp;
}
 
// Driver program to test above functions
public static void Main(String[] args)
{
    /*
                15
                / \
            10 20
            / \ / \
            8 12 16 25 */
    node root = NewNode(15);
    root.left = NewNode(10);
    root.right = NewNode(20);
    root.left.left = NewNode(8);
    root.left.right = NewNode(12);
    root.right.left = NewNode(16);
    root.right.right = NewNode(25);
 
    int target = 33;
    if (isPairPresent(root, target) == false)
        Console.Write("\nNo such values are found\n");
}
}
 
// This code is contributed by aashish1995


输出 :

Pair Found: 8 + 25 = 33
  • 复杂度分析:
    • 时间复杂度: O(n)。
      BST的有序遍历需要线性时间。
    • 辅助空间: O(n)。
      使用数组存储有序遍历。

在上一篇文章中讨论了空间优化的解决方案。这个想法是首先将BST原地转换为双链表(DLL),然后在O(n)的时间内在排序的DLL中找到对。此解决方案需要O(n)时间和O(Logn)额外空间,但是会修改给定的BST。
下面讨论解决方案占用O(n)时间,O(Logn)空间,并且不修改BST 。这个想法与在已排序的数组中查找对相同(有关详细信息,请参见此方法1)。我们同时以正常顺序和反向顺序遍历BST。相反,我们从最右边的节点开始,该节点是最大值节点。按照正常顺序,我们从最左侧的节点开始,该节点是最小值节点。我们在两个遍历中都加上当前节点的总和,然后将此总和与给定的目标总和进行比较。如果总和与目标总和相同,则返回true。如果总和大于目标总和,我们将以反向有序遍历的方式移至下一个节点,否则,我们以正常有序遍历的方式移至下一个节点。如果任何遍历都结束而没有找到对,则返回false。以下是此方法的C++实现。

C++

/* In a balanced binary search tree
isPairPresent two element which sums to
a given value time O(n) space O(logn) */
#include 
using namespace std;
#define MAX_SIZE 100
 
// A BST node
class node {
public:
    int val;
    node *left, *right;
};
 
// Stack type
class Stack {
public:
    int size;
    int top;
    node** array;
};
 
// A utility function to create a stack of given size
Stack* createStack(int size)
{
    Stack* stack = new Stack();
    stack->size = size;
    stack->top = -1;
    stack->array = new node*[(stack->size * sizeof(node*))];
    return stack;
}
 
// BASIC OPERATIONS OF STACK
int isFull(Stack* stack)
{
    return stack->top - 1 == stack->size;
}
 
int isEmpty(Stack* stack)
{
    return stack->top == -1;
}
 
void push(Stack* stack, node* node)
{
    if (isFull(stack))
        return;
    stack->array[++stack->top] = node;
}
 
node* pop(Stack* stack)
{
    if (isEmpty(stack))
        return NULL;
    return stack->array[stack->top--];
}
 
// Returns true if a pair with target
// sum exists in BST, otherwise false
bool isPairPresent(node* root, int target)
{
    // Create two stacks. s1 is used for
    // normal inorder traversal and s2 is
    // used for reverse inorder traversal
    Stack* s1 = createStack(MAX_SIZE);
    Stack* s2 = createStack(MAX_SIZE);
 
    // Note the sizes of stacks is MAX_SIZE,
    // we can find the tree size and fix stack size
    // as O(Logn) for balanced trees like AVL and Red Black
    // tree. We have used MAX_SIZE to keep the code simple
 
    // done1, val1 and curr1 are used for
    // normal inorder traversal using s1
    // done2, val2 and curr2 are used for
    // reverse inorder traversal using s2
    bool done1 = false, done2 = false;
    int val1 = 0, val2 = 0;
    node *curr1 = root, *curr2 = root;
 
    // The loop will break when we either find a pair or one of the two
    // traversals is complete
    while (1) {
        // Find next node in normal Inorder
        // traversal. See following post
        // https:// www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
        while (done1 == false) {
            if (curr1 != NULL) {
                push(s1, curr1);
                curr1 = curr1->left;
            }
            else {
                if (isEmpty(s1))
                    done1 = 1;
                else {
                    curr1 = pop(s1);
                    val1 = curr1->val;
                    curr1 = curr1->right;
                    done1 = 1;
                }
            }
        }
 
        // Find next node in REVERSE Inorder traversal. The only
        // difference between above and below loop is, in below loop
        // right subtree is traversed before left subtree
        while (done2 == false) {
            if (curr2 != NULL) {
                push(s2, curr2);
                curr2 = curr2->right;
            }
            else {
                if (isEmpty(s2))
                    done2 = 1;
                else {
                    curr2 = pop(s2);
                    val2 = curr2->val;
                    curr2 = curr2->left;
                    done2 = 1;
                }
            }
        }
 
        // If we find a pair, then print the pair and return. The first
        // condition makes sure that two same values are not added
        if ((val1 != val2) && (val1 + val2) == target) {
            cout << "Pair Found: " << val1 << "+ " << val2 << " = " << target << endl;
            return true;
        }
 
        // If sum of current values is smaller,
        // then move to next node in
        // normal inorder traversal
        else if ((val1 + val2) < target)
            done1 = false;
 
        // If sum of current values is greater,
        // then move to next node in
        // reverse inorder traversal
        else if ((val1 + val2) > target)
            done2 = false;
 
        // If any of the inorder traversals is
        // over, then there is no pair
        // so return false
        if (val1 >= val2)
            return false;
    }
}
 
// A utility function to create BST node
node* NewNode(int val)
{
    node* tmp = new node();
    tmp->val = val;
    tmp->right = tmp->left = NULL;
    return tmp;
}
 
// Driver program to test above functions
int main()
{
    /*
                15
                / \
            10 20
            / \ / \
            8 12 16 25 */
    node* root = NewNode(15);
    root->left = NewNode(10);
    root->right = NewNode(20);
    root->left->left = NewNode(8);
    root->left->right = NewNode(12);
    root->right->left = NewNode(16);
    root->right->right = NewNode(25);
 
    int target = 33;
    if (isPairPresent(root, target) == false)
        cout << "\nNo such values are found\n";
    return 0;
}
 
// This code is contributed by rathbhupendra

C

/* In a balanced binary search tree isPairPresent two element which sums to
   a given value time O(n) space O(logn) */
#include 
#include 
#define MAX_SIZE 100
 
// A BST node
struct node {
    int val;
    struct node *left, *right;
};
 
// Stack type
struct Stack {
    int size;
    int top;
    struct node** array;
};
 
// A utility function to create a stack of given size
struct Stack* createStack(int size)
{
    struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));
    stack->size = size;
    stack->top = -1;
    stack->array = (struct node**)malloc(stack->size * sizeof(struct node*));
    return stack;
}
 
// BASIC OPERATIONS OF STACK
int isFull(struct Stack* stack)
{
    return stack->top - 1 == stack->size;
}
 
int isEmpty(struct Stack* stack)
{
    return stack->top == -1;
}
 
void push(struct Stack* stack, struct node* node)
{
    if (isFull(stack))
        return;
    stack->array[++stack->top] = node;
}
 
struct node* pop(struct Stack* stack)
{
    if (isEmpty(stack))
        return NULL;
    return stack->array[stack->top--];
}
 
// Returns true if a pair with target sum exists in BST, otherwise false
bool isPairPresent(struct node* root, int target)
{
    // Create two stacks. s1 is used for normal inorder traversal
    // and s2 is used for reverse inorder traversal
    struct Stack* s1 = createStack(MAX_SIZE);
    struct Stack* s2 = createStack(MAX_SIZE);
 
    // Note the sizes of stacks is MAX_SIZE, we can find the tree size and
    // fix stack size as O(Logn) for balanced trees like AVL and Red Black
    // tree. We have used MAX_SIZE to keep the code simple
 
    // done1, val1 and curr1 are used for normal inorder traversal using s1
    // done2, val2 and curr2 are used for reverse inorder traversal using s2
    bool done1 = false, done2 = false;
    int val1 = 0, val2 = 0;
    struct node *curr1 = root, *curr2 = root;
 
    // The loop will break when we either find a pair or one of the two
    // traversals is complete
    while (1) {
        // Find next node in normal Inorder traversal. See following post
        // https:// www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
        while (done1 == false) {
            if (curr1 != NULL) {
                push(s1, curr1);
                curr1 = curr1->left;
            }
            else {
                if (isEmpty(s1))
                    done1 = 1;
                else {
                    curr1 = pop(s1);
                    val1 = curr1->val;
                    curr1 = curr1->right;
                    done1 = 1;
                }
            }
        }
 
        // Find next node in REVERSE Inorder traversal. The only
        // difference between above and below loop is, in below loop
        // right subtree is traversed before left subtree
        while (done2 == false) {
            if (curr2 != NULL) {
                push(s2, curr2);
                curr2 = curr2->right;
            }
            else {
                if (isEmpty(s2))
                    done2 = 1;
                else {
                    curr2 = pop(s2);
                    val2 = curr2->val;
                    curr2 = curr2->left;
                    done2 = 1;
                }
            }
        }
 
        // If we find a pair, then print the pair and return. The first
        // condition makes sure that two same values are not added
        if ((val1 != val2) && (val1 + val2) == target) {
            printf("\n Pair Found: %d + %d = %d\n", val1, val2, target);
            return true;
        }
 
        // If sum of current values is smaller, then move to next node in
        // normal inorder traversal
        else if ((val1 + val2) < target)
            done1 = false;
 
        // If sum of current values is greater, then move to next node in
        // reverse inorder traversal
        else if ((val1 + val2) > target)
            done2 = false;
 
        // If any of the inorder traversals is over, then there is no pair
        // so return false
        if (val1 >= val2)
            return false;
    }
}
 
// A utility function to create BST node
struct node* NewNode(int val)
{
    struct node* tmp = (struct node*)malloc(sizeof(struct node));
    tmp->val = val;
    tmp->right = tmp->left = NULL;
    return tmp;
}
 
// Driver program to test above functions
int main()
{
    /*
                   15
                /     \
              10      20
             / \     /  \
            8  12   16  25    */
    struct node* root = NewNode(15);
    root->left = NewNode(10);
    root->right = NewNode(20);
    root->left->left = NewNode(8);
    root->left->right = NewNode(12);
    root->right->left = NewNode(16);
    root->right->right = NewNode(25);
 
    int target = 33;
    if (isPairPresent(root, target) == false)
        printf("\n No such values are found\n");
 
    getchar();
    return 0;
}

Java

/* In a balanced binary search tree
isPairPresent two element which sums to
a given value time O(n) space O(logn) */
import java.util.*;
class GFG
{
static final int MAX_SIZE= 100;
 
// A BST node
static class node
{
    int val;
    node left, right;
};
 
// Stack type
static class Stack
{
    int size;
    int top;
    node []array;
};
 
// A utility function to create a stack of given size
static Stack createStack(int size)
{
    Stack stack = new Stack();
    stack.size = size;
    stack.top = -1;
    stack.array = new node[stack.size];
    return stack;
}
 
// BASIC OPERATIONS OF STACK
static int isFull(Stack stack)
{
    return (stack.top - 1 == stack.size)?1:0 ;
}
 
static int isEmpty(Stack stack)
{
    return stack.top == -1?1:0;
}
 
static void push(Stack stack, node node)
{
    if (isFull(stack)==1)
        return;
    stack.array[++stack.top] = node;
}
 
static node pop(Stack stack)
{
    if (isEmpty(stack) == 1)
        return null;
    return stack.array[stack.top--];
}
 
// Returns true if a pair with target
// sum exists in BST, otherwise false
static boolean isPairPresent(node root, int target)
{
    // Create two stacks. s1 is used for
    // normal inorder traversal and s2 is
    // used for reverse inorder traversal
    Stack s1 = createStack(MAX_SIZE);
    Stack s2 = createStack(MAX_SIZE);
 
    // Note the sizes of stacks is MAX_SIZE,
    // we can find the tree size and fix stack size
    // as O(Logn) for balanced trees like AVL and Red Black
    // tree. We have used MAX_SIZE to keep the code simple
 
    // done1, val1 and curr1 are used for
    // normal inorder traversal using s1
    // done2, val2 and curr2 are used for
    // reverse inorder traversal using s2
    boolean done1 = false, done2 = false;
    int val1 = 0, val2 = 0;
    node curr1 = root, curr2 = root;
 
    // The loop will break when we either
  // find a pair or one of the two
    // traversals is complete
    while (true)
    {
       
        // Find next node in normal Inorder
        // traversal. See following post
        // https:// www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
        while (done1 == false)
        {
            if (curr1 != null)
            {
                push(s1, curr1);
                curr1 = curr1.left;
            }
            else
            {
                if (isEmpty(s1) == 1)
                    done1 = true;
                else
                {
                    curr1 = pop(s1);
                    val1 = curr1.val;
                    curr1 = curr1.right;
                    done1 = true;
                }
            }
        }
 
        // Find next node in REVERSE Inorder traversal. The only
        // difference between above and below loop is, in below loop
        // right subtree is traversed before left subtree
        while (done2 == false)
        {
            if (curr2 != null)
            {
                push(s2, curr2);
                curr2 = curr2.right;
            }
            else {
                if (isEmpty(s2) == 1)
                    done2 = true;
                else {
                    curr2 = pop(s2);
                    val2 = curr2.val;
                    curr2 = curr2.left;
                    done2 = true;
                }
            }
        }
 
        // If we find a pair, then print the pair and return. The first
        // condition makes sure that two same values are not added
        if ((val1 != val2) && (val1 + val2) == target)
        {
            System.out.print("Pair Found: " +
                             val1+ "+ " +
                             val2+ " = " + 
                             target +"\n");
            return true;
        }
 
        // If sum of current values is smaller,
        // then move to next node in
        // normal inorder traversal
        else if ((val1 + val2) < target)
            done1 = false;
 
        // If sum of current values is greater,
        // then move to next node in
        // reverse inorder traversal
        else if ((val1 + val2) > target)
            done2 = false;
 
        // If any of the inorder traversals is
        // over, then there is no pair
        // so return false
        if (val1 >= val2)
            return false;
    }
}
 
// A utility function to create BST node
static node NewNode(int val)
{
    node tmp = new node();
    tmp.val = val;
    tmp.right = tmp.left = null;
    return tmp;
}
 
// Driver program to test above functions
public static void main(String[] args)
{
    /*
                15
                / \
            10 20
            / \ / \
            8 12 16 25 */
    node root = NewNode(15);
    root.left = NewNode(10);
    root.right = NewNode(20);
    root.left.left = NewNode(8);
    root.left.right = NewNode(12);
    root.right.left = NewNode(16);
    root.right.right = NewNode(25);
 
    int target = 33;
    if (isPairPresent(root, target) == false)
        System.out.print("\nNo such values are found\n");
}
}
 
// This code is contributed by aashish1995

C#

/* In a balanced binary search tree
isPairPresent two element which sums to
a given value time O(n) space O(logn) */
using System;
using System.Collections.Generic;
 
public class GFG
{
static readonly int MAX_SIZE= 100;
 
// A BST node
public
 class node
{
    public
 int val;
    public
 node left, right;
};
 
// Stack type
public
 class Stack
{
    public
 int size;
    public
 int top;
    public
 node []array;
};
 
// A utility function to create a stack of given size
static Stack createStack(int size)
{
    Stack stack = new Stack();
    stack.size = size;
    stack.top = -1;
    stack.array = new node[stack.size];
    return stack;
}
 
// BASIC OPERATIONS OF STACK
static int isFull(Stack stack)
{
    return (stack.top - 1 == stack.size) ? 1 : 0 ;
}
 
static int isEmpty(Stack stack)
{
    return stack.top == -1?1:0;
}
 
static void push(Stack stack, node node)
{
    if (isFull(stack)==1)
        return;
    stack.array[++stack.top] = node;
}
 
static node pop(Stack stack)
{
    if (isEmpty(stack) == 1)
        return null;
    return stack.array[stack.top--];
}
 
// Returns true if a pair with target
// sum exists in BST, otherwise false
static bool isPairPresent(node root, int target)
{
    // Create two stacks. s1 is used for
    // normal inorder traversal and s2 is
    // used for reverse inorder traversal
    Stack s1 = createStack(MAX_SIZE);
    Stack s2 = createStack(MAX_SIZE);
 
    // Note the sizes of stacks is MAX_SIZE,
    // we can find the tree size and fix stack size
    // as O(Logn) for balanced trees like AVL and Red Black
    // tree. We have used MAX_SIZE to keep the code simple
 
    // done1, val1 and curr1 are used for
    // normal inorder traversal using s1
    // done2, val2 and curr2 are used for
    // reverse inorder traversal using s2
    bool done1 = false, done2 = false;
    int val1 = 0, val2 = 0;
    node curr1 = root, curr2 = root;
 
    // The loop will break when we either
  // find a pair or one of the two
    // traversals is complete
    while (true)
    {
       
        // Find next node in normal Inorder
        // traversal. See following post
        // https:// www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
        while (done1 == false)
        {
            if (curr1 != null)
            {
                push(s1, curr1);
                curr1 = curr1.left;
            }
            else
            {
                if (isEmpty(s1) == 1)
                    done1 = true;
                else
                {
                    curr1 = pop(s1);
                    val1 = curr1.val;
                    curr1 = curr1.right;
                    done1 = true;
                }
            }
        }
 
        // Find next node in REVERSE Inorder traversal. The only
        // difference between above and below loop is, in below loop
        // right subtree is traversed before left subtree
        while (done2 == false)
        {
            if (curr2 != null)
            {
                push(s2, curr2);
                curr2 = curr2.right;
            }
            else {
                if (isEmpty(s2) == 1)
                    done2 = true;
                else {
                    curr2 = pop(s2);
                    val2 = curr2.val;
                    curr2 = curr2.left;
                    done2 = true;
                }
            }
        }
 
        // If we find a pair, then print the pair and return. The first
        // condition makes sure that two same values are not added
        if ((val1 != val2) && (val1 + val2) == target)
        {
            Console.Write("Pair Found: " +
                             val1+ "+ " +
                             val2+ " = " + 
                             target +"\n");
            return true;
        }
 
        // If sum of current values is smaller,
        // then move to next node in
        // normal inorder traversal
        else if ((val1 + val2) < target)
            done1 = false;
 
        // If sum of current values is greater,
        // then move to next node in
        // reverse inorder traversal
        else if ((val1 + val2) > target)
            done2 = false;
 
        // If any of the inorder traversals is
        // over, then there is no pair
        // so return false
        if (val1 >= val2)
            return false;
    }
}
 
// A utility function to create BST node
static node NewNode(int val)
{
    node tmp = new node();
    tmp.val = val;
    tmp.right = tmp.left = null;
    return tmp;
}
 
// Driver program to test above functions
public static void Main(String[] args)
{
    /*
                15
                / \
            10 20
            / \ / \
            8 12 16 25 */
    node root = NewNode(15);
    root.left = NewNode(10);
    root.right = NewNode(20);
    root.left.left = NewNode(8);
    root.left.right = NewNode(12);
    root.right.left = NewNode(16);
    root.right.right = NewNode(25);
 
    int target = 33;
    if (isPairPresent(root, target) == false)
        Console.Write("\nNo such values are found\n");
}
}
 
// This code is contributed by aashish1995

输出:

Pair Found: 8 + 25 = 33
  • 复杂度分析:
    • 时间复杂度: O(n)。
      BST的有序遍历需要线性时间。
    • 辅助空间: O(logn)。
      堆栈一次保存对数N的