在这篇文章中,我们用三种不同的方法解决了二进制搜索树中的两个和问题,涉及深度优先搜索、顺序遍历和增强二进制搜索树。
内容表:
- 问题说明
- 方法1:使用DFS
- 方法2:使用无序遍历法
- 方法3:使用增强的BST
让我们开始吧。
问题陈述
给定一个二进制搜索树和一个整数k,我们必须确定BST中是否有两个节点的值之和等于给定的目标。输入是树的根,输出可以是真或假。
例如,
给定的二进制搜索树是:

输入:根 = [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。
这种方法的步骤:
-
设和为S,定义一个Hashtable H
-
对二进制搜索树B做DFS遍历
2.1.对于每个节点N,检查S-N是否存在于hashtable H中
2.2.如果S-N存在,则返回TRUE
2.3.如果S-N不存在,则在哈希特表H中插入N -
如果没有找到一对,则返回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的无序遍历是排序的,我们可以使用两个指针来找到所需的一对。我们可以在数组的起点和终点使用两个指针并搜索目标。
这种方法的步骤:
- 设和为S
- 遍历二进制搜索树B,并存储依次遍历I
- 使用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中两个和的问题有了一个完整的概念。