You are given a binary tree where all the node values have been contaminated and set to -1
. The original binary tree satisfied the following rules:
0
.x
:
2 * x + 1
.2 * x + 2
.Your tasks are:
find
function that returns true
if a given target
value exists in the tree, and false
otherwise.find
function may be called many times.
The key to this problem is understanding how to reconstruct the original values of the binary tree. Since all nodes initially have the value -1
, we must traverse the tree and assign the correct values based on their position and the rules provided.
A brute-force approach would be to reconstruct the value of each node on-the-fly during every find
call, but this would be inefficient, especially if find
is called multiple times.
To optimize, we can recover the tree once (at initialization) and store all valid node values in a fast-access data structure (like a hash set). This way, every find
operation becomes a simple and efficient lookup.
Here’s how we can efficiently solve the problem:
0
.2 * parent + 1
and its right child 2 * parent + 2
(if they exist).find
method, simply check if the target value is in the hash set.
This approach ensures that tree recovery is done only once, and all subsequent find
calls are extremely fast.
Suppose the contaminated tree structure is:
-1 / \ -1 -1 / -1
Step-by-step recovery:
2*0+1 = 1
2*0+2 = 2
2*1+1 = 3
The recovered values are: 0, 1, 2, 3
Sample find calls:
find(1)
returns true
(since 1 exists)find(4)
returns false
(since 4 doesn't exist)# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class FindElements:
def __init__(self, root: TreeNode):
self.values = set()
def recover(node, val):
if not node:
return
node.val = val
self.values.add(val)
recover(node.left, 2 * val + 1)
recover(node.right, 2 * val + 2)
recover(root, 0)
def find(self, target: int) -> bool:
return target in self.values
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class FindElements {
unordered_set<int> values;
void recover(TreeNode* node, int val) {
if (!node) return;
node->val = val;
values.insert(val);
recover(node->left, 2 * val + 1);
recover(node->right, 2 * val + 2);
}
public:
FindElements(TreeNode* root) {
recover(root, 0);
}
bool find(int target) {
return values.count(target) > 0;
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
import java.util.HashSet;
import java.util.Set;
class FindElements {
private Set<Integer> values = new HashSet<>();
public FindElements(TreeNode root) {
recover(root, 0);
}
private void recover(TreeNode node, int val) {
if (node == null) return;
node.val = val;
values.add(val);
recover(node.left, 2 * val + 1);
recover(node.right, 2 * val + 2);
}
public boolean find(int target) {
return values.contains(target);
}
}
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
var FindElements = function(root) {
this.values = new Set();
const recover = (node, val) => {
if (!node) return;
node.val = val;
this.values.add(val);
recover(node.left, 2 * val + 1);
recover(node.right, 2 * val + 2);
}
recover(root, 0);
};
FindElements.prototype.find = function(target) {
return this.values.has(target);
};
find
call, you would need to traverse the tree, reconstructing values on the fly. This would be O(N) per find
call, where N is the number of nodes.
The main insight is to recover the contaminated tree only once, storing all valid node values in a hash set for efficient lookup. This design makes the find
operation extremely fast, even if called many times. The solution leverages DFS for tree traversal and a set for O(1) lookups, making it both elegant and efficient for the problem's requirements.