这是我在采访中提出的一个问题。对于给定的BST,找到第k个最接近的元素。穿越整棵树是不可接受的。解决方案不应该是o(n),并且空间复杂性不是问题。 感谢。
我的尝试 - 遍历树的一个分支以获取可能的元素,然后从这些元素开始遍历分支。
答案 0 :(得分:1)
首先我们必须找到。 1,首先你必须获得节点(来自BST根目录) 你必须得到它下面和远处k的节点。 你必须得到一个上面是k节点的祖先。 4.你必须得到距离它第k个的节点。 (在同一级别或其他级别)
A(8)
/ \
B(6) C(22)
/ \ / \
D(5) E(7) F(17) G(26)
/ \ \
(15)H I(19) N(29)
/ \
(14) K L(20)
Okie认为树是BST树(A,B,C d不是BST的序列,*认为它们是节点引用以标识节点而不是值*) 我已经附上了一个代表价值观的数字。
再考虑一下。 因为它被宣布为BST树。没有父指针。 *
您获得了树的根A. 给出数字17,并给出k = 2的值。 第17号获得参考(F) 对于k = 2,即从2节点距离获得树的所有节点。 作为F的死者你必须检测K(14)和L(20) 作为F的中心你必须得到节点A. 再次你必须得到节点G(2节点距离)(虽然没有父指针你必须得到它)。
一步一步 1 首先是数字 - > 17得到参考F(你有的根)做一个简单的二进制搜索。
ArrayList get_it( Node root_node, int number) {
node = root_node;
if (node ==null)
throw new IllegarArgumentException("null root node");
ArrayList pathtracker = new ArrayList();
//is the root node matches
pathtracker.add(node); // fix
if( node.data=number) // fix
return pathtracker;
while(node !=null) {
if ( node.data==number){
return pathtracker;
}
if ( node.data >= number ){
node=node.left;
}
else{
node=node.right;
}
pathtracker.add(node);
} // end of while loop
return new ArrayList(); //search failed node is not present.
// returning empty arrayList
}
现在我们将使用pathtracker。 这具有从根到此节点的轨道节点。 第0个节点是root,length() - 第1个节点是我们拥有的节点 搜索。
for ( int i = pathtracker.length() - 1 , depth=k ;
( depth => 0 && i => 0 ) ; i--,depth-- ){
if ( i == pathtracker.length() - 1) {//first case
printnodeDistancek( pathtracker.get(i), depth);
}else {
if( pathtracker.get(i).left ! = pathtracker.get(i+1) ){
printnodeDistancek( pathtracker.get(i).left, depth);
}else{
printnodeDistancek( pathtracker.get(i).right, depth);
}
} // end of else block
} // end of loop
void printnodeDistancek( node n, k) {
if (node==null)
return;
if ( k = 0) {
print node.data;
return;
}
printnodeDistancek( n.left, k-1);
printodeDistanceK( node.right, k-1);
}
给出的数字是17(F节点)和 现在如果k = 3,则应该打印N和B. 如果K = 4,则应打印D(5)和E97)
答案 1 :(得分:1)
我想这个问题是关于将BST的第K个最接近的元素找到值V,
注意:除非BST平衡,否则在O(n)时间内不可能做到这一点,
要找到第K个最接近的元素: 到目前为止,我们保持与V最接近的K个整数, 1.访问每个节点(从根开始),我们将节点的值,其前身的值和后继值添加到目前为止看到的最接近的值。 (如果数组已满,我们只将一个值放入接近V的数组中。我们用这个值替换最大的一个)
2.如果当前节点的后继接近V,则选择正确的分支;如果前一个接近,则选择左分支。
3.我们重复,直到没有更多的节点访问(我们得到一片叶子)
4.时间复杂度:O(n ^ 2 * k),如果我们假设k是常数(例如k = 3)并且树是平衡的,则时间复杂度将是:O(log(n)^ 2)Integer[] closest = new Integer[3]; // initialized with null
void find_3rd_closest(Node current , int K){
Node succ = Successor(current);
Node pred = Predecessor(current);
insert(closest , current.val , K);
if (succ != null)
insert(closest , succ.val , K);
if (pred != null)
insert(closest , pred.val , K);
if (succ != null && pred != null)
if (Math.abs(pred.val - K) < Math.abs(succ.val - K))
find_3rd_closest(pred , K);
else
find_3rd_closest(succ , K);
else if (pred != null)
find_3rd_closest(pred , K);
else if (succ != null)
find_3rd_closest(succ , K);
else
return;
}
void insert(int[] closest , int val, int K){
for (int i = 0 ; i < closest.length ; i++){
if (closest[i] != null && Math.abs(K - val) < Math.abs(K - closest[i])){
for (int j = i ; i < closest.length - 1 ; i++){
int temp = closest[i+1];
closest[i+1] = closest[i];
closest[i] = temp;
}
}
closest[i] = succ.value;
}
}
Node Successor(Node current){
if (current.rightChild == null)
return null;
current = current.rightChild;
while (current.leftChild != null)
current = current.leftChild;
return current;
}
Node Predecessor(Node current){
if (current.leftChild == null)
return null;
current = current.leftChild;
while (current.rigthChild != null)
current = current.rightChild;
return current;
}
答案 2 :(得分:0)
我假设两个节点之间的接近程度是由它们之间的边数定义的,并且为了解决模糊性,也假设在相等距离的情况下,父节点最接近然后是右节点然后是左节点。
根节点的第k个最接近的元素将是第k个元素是树的级别顺序遍历。
对于树中的任何节点,我们将从距离一个边缘的节点开始,即其父,右,左,然后距离2边缘,即距离1处的节点的父,右,左等,依此类推。我们将继续计数直到达到k个节点,同时确保我们不计算两个节点。考虑以下伪代码。
KthClosest(Node * node, k)
{
std::queue<Node *> queue;
std::map<Node *, bool> mapToCheckIFNodeIsCounted;
int count = 0;
queue.push_back(node);
while(count <k)
{
Node* node = queue.pop();
if(node ->parent != NULL)
{
if(mapToCheckIFNodeIsCounted.find(node->parent) ==mapToCheckIFNodeIsCounted.end())
{
queue->push_back(node->parent);
mapToCheckIFNodeIsCounted.insert(std::pair<node->parent,true>);
}
}
if(node -> right != NULL)
{
if(mapToCheckIFNodeIsCounted.find(node->right) == mapToCheckIFNodeIsCounted.end())
{
queue->push_back(node->right);
mapToCheckIFNodeIsCounted.insert(std::pair<node->right,true>);
}
}
if(node -> left != NULL)
{
if(mapToCheckIFNodeIsCounted.find(node->parent) == mapToCheckIFNodeIsCounted.end())
{
queue->push_back(node->left);
mapToCheckIFNodeIsCounted.insert(std::pair<node->left,true>);
}
}
count++;
}
// Kth node is the node in queue after loop has finished fraversing k closest elements
Node *node = queue.pop();
print(node->value);
}