二进制搜索树中的两个和问题

201 阅读4分钟

在这篇文章中,我们用三种不同的方法解决了二进制搜索树中的两个和问题,涉及深度优先搜索、顺序遍历和增强二进制搜索树。

内容表:

  1. 问题说明
  2. 方法1:使用DFS
  3. 方法2:使用无序遍历法
  4. 方法3:使用增强的BST

让我们开始吧。

问题陈述

给定一个二进制搜索树和一个整数k,我们必须确定BST中是否有两个节点的值之和等于给定的目标。输入是树的根,输出可以是真或假。

例如,
给定的二进制搜索树是:

BST_Ex1

输入:根 = [5, 3, 6, 2, 4, null, 7], k = 9
输出:真
说明:节点(3,6)、(5,4)和(2,7)的总和等于9。

这个问题可以用下面讨论的方法来解决。

方法1:使用DFS

在这种方法中,我们将对树进行DFS(深度优先搜索)遍历,并寻找具有给定目标的配对。这可以通过使用hashtable有效地进行。(查找时间为O(1))。

我们可以使用java中的hashset或C++中的unordered_set创建一个hashable来存储我们遇到的节点的值。如果当前节点和任何一个存储的值相加为目标值,那么我们就找到了一对,并返回true。如果我们到达树的末端,我们返回false。

这种方法的步骤:

  1. 设和为S,定义一个Hashtable H

  2. 对二进制搜索树B做DFS遍历
    2.1.对于每个节点N,检查S-N是否存在于hashtable H中
    2.2.如果S-N存在,则返回TRUE
    2.3.如果S-N不存在,则在哈希特表H中插入N

  3. 如果没有找到一对,则返回FALSE。

C++代码:

/*
// Structure of the Tree node.
struct TreeNode {
  int val;
  TreeNode* left;
  TreeNode* right;
  }
 
  */
 
 bool findPair(TreeNode * root, int k){
 unordered_set<int> values;   // to store the values
 return dfs(root, k, values);
 }
 
 bool dfs(TreeNode* root, int k, unordered_set<int> &values){
     // If complement not found beyond the leaf node, then return false;
     if(root == NULL) return false;
     
     // Find the complement of the current node in the hash table.
     // If found complement, then return true.
     if(values.find(k - root -> val) != values.end()){
             return true;
      }
      
      //Insert the current node value in hashtable.  
      values.insert(root -> val);
      // Same process for node in left and right subtrees.
      return dfs(root -> left, k, values) || 
             dfs(root -> right, k, values);
   }
   

时间复杂度O(N)
空间复杂度 O(N)

其中n是BST中的节点数。

这种方法可以应用在任何树上。我们尤其可以利用BST的特殊属性来解决这个问题。

方法2:使用无序遍历

在这种方法中,我们可以使用无序遍历将树的节点值存储在一个数组中。由于我们知道BST的无序遍历是排序的,我们可以使用两个指针来找到所需的一对。我们可以在数组的起点和终点使用两个指针并搜索目标。

这种方法的步骤:

  1. 设和为S
  2. 遍历二进制搜索树B,并存储依次遍历I
  3. 使用2个指针技术(一个指针在起点,另一个指针在终点),找到一对总和等于S的指针

C++代码

  // Function to store the inorder traversal in array.
  void inorder(vector<int> &nodes, TreeNode *root){
        if(root == NULL)return;
        inorder(nodes, root -> left);
        nodes.push_back(root -> val);
        inorder(nodes, root -> right);
    }
    
    // Function to search pair in array using two pointers.
    bool twoPointers(vector<int> &nodes, int k){
        // left and right pointer
        int l = 0, r = nodes.size() - 1;
        
        while(l < r){
        int sum = nodes[l] + nodes[r];
            if(sum == k)return true; //If found valid pair, return true.
            else if(sum < k) l++;   
            else if(sum > k) r--;
        }
        return false;     // If pair not found, return false.
    }
    // Given Function
    bool findPair(TreeNode* root, int k) {
       vector<int> nodes;
        inorder(nodes, root);
        return twoPointers(nodes, k);
       } 
       

时间复杂度O(n)
空间复杂度 O(n)
其中n是BST中的节点数。

方法3:使用增强的BST

这种方法可以用来优化问题的空间复杂性。直观地说,我们可以在BST中保留一个指向最左边叶子节点和最右边叶子节点的左右指针。我们可以找到这两个指针所指向的节点值之和。

由于二进制搜索树的结构被修改,这种技术被称为增强型BST。

如果总和大于目标值,那么我们可以将右边的指针移到前一个更大的节点上,也就是前任。

如果总和小于目标值,我们可以将左边的指针移到下一个更大的节点或继承者。

这种方法在O(1) 空间和O(nlogn) 时间,因为在最坏的情况下,我们会遍历所有的节点,而findNext()和findPrevious()函数在最坏的情况下需要O(logn) 时间。

用C++实现:

 bool findPairs(TreeNode* root, int k){
   if (root == NULL) {
           return false;
       }
       TreeNode* start = root;
       TreeNode* end = root;
       
       // start pointer will point to leftmost leaf.
       while (start -> left != NULL) {
           start = start -> left;
       }
       
       //end pointer will point to rightmost leaf.
       while (end -> right != NULL) {
           end = end -> right;
       }
       
       // check for sum of nodes pointed by two pointers, 
       //if equal to target then return true.
       while (start != end) {
           int sum = start -> val + end -> val;
           // end pointer is moved to previous greater node.
           if (sum > k) {
               end = findPrevious(root, end);
              } 
           // start pointer is moved to next greater node.
           else if (sum < k) {
               start = findNext(root, start);
              } 
           else {
               return true;
              }
       }
       return false;  // if pair not found, return false.
   }
   TreeNode* findPrevious(TreeNode* root, TreeNode* end) {
       TreeNode* pred = NULL;  // pointer to the desired node.
       TreeNode* now = root;  // pointer to traverse tree.
       while (now != NULL) {
           if (now -> val < end -> val) {
               pred = now;
               now = now -> right;
           } else {
               now = now -> left;
           }
       }
       return pred;
   }
   TreeNode* findNext(TreeNode* root, TreeNode* start) {
       TreeNode* succ = NULL;   // pointer to the desired node.
       TreeNode* now = root;    // pointer to traverse tree.
       while (now != NULL) {
           if (now -> val > start -> val) {
               succ = now;
               now = now -> left;
           } else {
               now = now -> right;
           }
       }
       return succ;
   }  

时间复杂度: O(N logN)

空间复杂度: O(1)

其中n 是节点的数量。
这些方法可以用来寻找BST中具有给定和的一对。

通过OpenGenus的这篇文章,你一定对用多种方法解决BST中两个和的问题有了一个完整的概念。