【问题标题】:BST - interval deletion/multiple nodes deletionBST - 间隔删除/多节点删除
【发布时间】:2017-11-26 23:10:27
【问题描述】:

假设我有一个二叉搜索树,我应该按照在标准输入上给我的顺序插入 N 个唯一编号的键,然后我要删除所有具有 I = [min,max 间隔的键的节点] 以及与这些节点相邻的所有连接。这给了我很多较小的树,我要用特定的方式将它们合并在一起。更准确的问题描述:

给定一个包含不同键的 BST 和区间 I,区间删除分两个阶段进行。在第一阶段,它会删除所有键在 I 中的节点以及与被删除节点相邻的所有边。让结果图包含 k 个连通分量 T1,...,Tk。每个组件都是一个BST,其中根是原始BST中该组件的所有节点中深度最小的节点。我们假设树 Ti 的序列是排序的,因此对于每个 i

编辑:我还应该删除连接节点的任何边缘,这些边缘由给定的间隔分隔,这意味着在示例 2 中连接节点 10 和 20 的边缘被删除,因为间隔 [13,15] 介于两者之间它们'从而将它们分开。

对于一个空的树序列,Merge() 给出一个空的 BST。 对于包含树 T 的单元素序列,Merge(T) = T。 对于一系列树 T1,...,Tk,其中 k > 1,令 A1

完成此操作后,我的任务是找到生成的合并树的深度 D 和深度 D-1 中的节点数。即使对于 100000 个节点的树(第 4 个示例),我的程序也应该在几秒钟内完成。

我的问题是我不知道如何执行此操作或什至从哪里开始。我设法在删除之前构建了所需的树,但仅此而已。 我将不胜感激实施解决此问题的程序或任何建议。最好用一些 C-ish 编程语言。

例子:

输入(第一个数字是要插入到空树中的键的数量,第二个是要按给定顺序插入的唯一键,第三行包含两个数字,表示要删除的区间):

13    
10 5 8 6 9 7 20 15 22 13 17 16 18  
8 16

程序的正确输出:3 3,第一个数字是深度 D,第二个节点的深度是 D-1

输入:

13
10 5 8 6 9 7 20 15 22 13 17 16 18
13 15

正确输出:4 3

pictures of the two examples

示例 3:https://justpaste.it/1du6l 正确输出:13 6

示例 4:link 正确输出:58 9

【问题讨论】:

  • 您的第二段并没有真正解释 ex-2 中的边缘去除。
  • @ShihabShahriar 对不起,我没有注意到,我编辑了这个问题。希望现在很清楚
  • 合并运算符的定义直接转化为递归方法。如果您允许自己遍历整棵树,则查找要合并的树很简单。只需遍历它即可同时创建一个未删除节点的外生集合 U,并通过将指针设置为 null 来删除区间中的节点。然后遍历 U 找到 U 中没有父节点的所有节点。这些是要合并的子树根。如果您将自己限制为仅接触区间中的节点,那就有点挑战了。

标签: algorithm merge binary-search-tree


【解决方案1】:

这是一个很大的答案,我会在高层次上讨论。请查看源以获取详细信息,或在评论中寻求澄清。

全局变量

  • vector<Node*> roots : 存储所有新树的根。
  • map<Node*,int> smap : 对于每棵新树,存储它的大小
  • vector<int> prefixroots 向量的前缀和,便于在merge 中进行二分查找

功能

  • inorder : 查找 BST 的大小(所有调用加起来 O(N))
  • delInterval :主题是,如果根不在区间内,那么它的两个孩子可能都是新树的根。最后两个 if 在您的编辑中检查该特殊边缘。为每个节点执行此操作,后订购。 (O(N))
  • merge :将位于start 的所有新根合并到roots 中的end 索引。首先,我们在total 中找到新树的总成员(使用roots 的前缀和,即prefix)。 mid 在您的问题中表示 mind 是包含mid-th 节点的根索引,我们在root 变量中检索它。现在递归地构建左/右子树并将它们添加到最左/右节点中。 O(N) 复杂度。
  • traverse:在level 映射中,计算每个树深度的节点数。 (O(N.logN), unordered_map 会变成 O(N))

现在是代码(不要惊慌!!!):

#include <bits/stdc++.h>
using namespace std;

int N = 12;

struct Node
{
    Node* parent=NULL,*left=NULL,*right = NULL;
    int value;
    Node(int x,Node* par=NULL) {value = x;parent = par;}
};

void insert(Node* root,int x){
    if(x<root->value){
        if(root->left) insert(root->left,x);
        else root->left = new Node(x,root);
    }
    else{
        if(root->right) insert(root->right,x);
        else root->right = new Node(x,root);
    }
}

int inorder(Node* root){
    if(root==NULL) return 0;
    int l = inorder(root->left);
    return l+1+inorder(root->right);
}

vector<Node*> roots;
map<Node*,int> smap;
vector<int> prefix;

Node* delInterval(Node* root,int x,int y){
    if(root==NULL) return NULL;
    root->left = delInterval(root->left,x,y);
    root->right = delInterval(root->right,x,y);
    if(root->value<=y && root->value>=x){
        if(root->left) roots.push_back(root->left);
        if(root->right) roots.push_back(root->right);
        return NULL;
    }
    if(root->value<x && root->right && root->right->value>y) {
        roots.push_back(root->right);
        root->right = NULL;
    }
    if(root->value>y && root->left && root->left->value<x) {
        roots.push_back(root->left);
        root->left = NULL;
    }
    return root;

}
Node* merge(int start,int end){
    if(start>end) return NULL;
    if(start==end) return roots[start];
    int total = prefix[end] - (start>0?prefix[start-1]:0);//make sure u get this line
    int mid = (total+1)/2 + (start>0?prefix[start-1]:0); //or this won't make sense
    int ind = lower_bound(prefix.begin(),prefix.end(),mid) - prefix.begin();
    Node* root = roots[ind];
    Node* TL = merge(start,ind-1);
    Node* TR = merge(ind+1,end);
    Node* temp = root;
    while(temp->left) temp = temp->left;
    temp->left = TL;
    temp = root;
    while(temp->right) temp = temp->right;
    temp->right = TR;
    return root;
}

void traverse(Node* root,int depth,map<int, int>& level){
    if(!root) return;
    level[depth]++;
    traverse(root->left,depth+1,level);
    traverse(root->right,depth+1,level);
}

int main(){
    srand(time(NULL));
    cin>>N;
    int* arr = new int[N],start,end;
    for(int i=0;i<N;i++) cin>>arr[i];
    cin>>start>>end;

    Node* tree = new Node(arr[0]); //Building initial tree
    for(int i=1;i<N;i++) {insert(tree,arr[i]);}

    Node* x = delInterval(tree,start,end); //deleting the interval
    if(x) roots.push_back(x);

    //sort the disconnected roots, and find their size
    sort(roots.begin(),roots.end(),[](Node* r,Node* v){return r->value<v->value;}); 
    for(auto& r:roots) {smap[r] = inorder(r);}

    prefix.resize(roots.size()); //prefix sum root sizes, to cheaply find 'root' in merge
    prefix[0] = smap[roots[0]];
    for(int i=1;i<roots.size();i++) prefix[i]= smap[roots[i]]+prefix[i-1];

    Node* root = merge(0,roots.size()-1); //merge all trees
    map<int, int> level; //key=depth, value = no of nodes in depth
    traverse(root,0,level); //find number of nodes in each depth

    int depth = level.rbegin()->first; //access last element's key i.e total depth
    int at_depth_1 = level[depth-1]; //no of nodes before
    cout<<depth<<" "<<at_depth_1<<endl; //hoorray

    return 0;
}

【讨论】:

    猜你喜欢
    • 2021-04-06
    • 1970-01-01
    • 2014-05-26
    • 2016-11-11
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    相关资源
    最近更新 更多