出题:要求将一个有序整数数组转换成最小深度的Binary Search Tree表示;

分析:由于需要是最小深度,所以BST应保持平衡,左右节点数大致相当,并且BST中当前根节点大于所有其左子树中的元素,小于所有其右子树中的元素。对于排序数组而言,中间元素必然作为根节点,然后递归对由中间元素分割的左右数组部分进行处理;

解题:

 struct Node {
int value;
Node *left;
Node *right;
}; Node* Array2BST(int *array, int i, int j) {
/**
* 如果上下范围相同说明只有一个节点
* 直接返回
* */
if(i==j) {
Node *root=new Node();
root->value=array[i];
root->left=NULL;
root->right=NULL;
return root;
} int m=(i+j)/;
Node *root=new Node();
root->value=array[m];
/**
* 由于(i+j)/2是向下取整,所以i+1=j时
* m=i,这个时候root的左子树为空
* */
if(m==i)
root->left=NULL;
else
root->left=Array2BST(array, i, m-);
root->right=Array2BST(array, m+, j); return root;
}

出题:要求实现函数:
  size_t foo(unsigned int *a1, size_t a1l, unsigned int *a2, size_t a2l)
  其中a1和a2都是无符号数组,a1l和a2l是对应数组的长度,并且都为偶数。
  无符号数分成两个数字组成的多个数字区间,如下:
    a1为0,1,3,8,10,20
    a2为0,1,20,50,4,5
  则a1表示的区间为[0,1],[3,8],[10,20]
  则a2表示的区间为[0,1],[20,50],[4,5]
  所以a1和a2重叠的部分为[0,1],[4,5],长度为2
  foo函数用于求给定区间数组a1和a2的重叠长度
  注意:a1和a2长度不超过100万,并且同一个区间数组内部可能出现重叠

分析:

  • 线段树(Interval Tree)是BST的一种特例,它将一个区间划分成单元区间(最小元素),每个单元区间对应一个叶子节点;对于一个内部节点而言[a,b],它的左子树节 点表示为[a,(a+b)/2],它的右子树节点表示为[(a+b)/2+1,b]。由于每次划分都是对等划分所以IT为平衡树,最终子节点数为N(对于 整数区间而言就是所有数字分布的范围大小),深度为logN +1。快速确定某一个元素在哪些区间节点出现,时间复杂度为O(NlogN),但是空间复杂度为O(N);
  • 确定区间数组A和B中差值较小的的最大值m和最小值n(假设数组A的区间范围更小,O(A)),并构建区间[m,n]的线段树(O(AlogA)),这样 可以节省空间,如果区间范围较大,可以使用离散的建树方法针对区间元素出现的范围构建多棵区间树,或者使用压缩的方法减少区间节点;
  • 在线段树中标记在A中出现的区间节点(O(AlogA));将B的区间节点插入线段树(实际上并没有新节点的插入,只是检测是否有A标记过的节点),如果有A区间节点标记的节点,则说明有重复(O(BlogA))。总时间复杂度O(AlogA);

解题:

 struct Interval {
int left;
int right;
int count;
};
/**
* 此函数用于创建线段树的基本结构
* */
void ConstructIT(int min, int max, Interval** InterTree, int index) {
/**
* 构建当前节点
* index用于索引InterTree中当前元素的位置
* 遵循父节点为i,则做有子节点分别为2*i, 2*i+1
* */
Interval *temp=new Interval();
temp->count=;
temp->left=min;
temp->right=max;
InterTree[index]=temp;
/**
* 如果min和max相等,则说明已经到叶子节点
* */
if(min==max)
return;
/**
* 分别递归创建左右子节点
* */
int middle=(min+max)/;
ConstructIT(min,middle,InterTree,index*);
ConstructIT(middle+,max,InterTree,index*+);
}
/**
* 此函数用于注入线段树的线段标记信息
* */
void InsertInfor(int min, int max, Interval** InterTree, int index) {
int middle=(InterTree[index]->left + InterTree[index]->right)/;
if(max<middle) {
InsertInfor(min, max, InterTree, *index);
} else if(min>middle) {
InsertInfor(min, max, InterTree, *index+);
} else if(min==InterTree[index]->left &&
max==InterTree[index]->right) {
InterTree[index]->count+=;
return;
} else {
InsertInfor(min, middle, InterTree, *index);
InsertInfor(middle+, max, InterTree, *index+);
}
}
/**
* 此函数用于检查覆盖区间,注意此时的min和max可能超出
* InterTree的范围
* */
int CheckInterval(int min, int max, Interval** InterTree, int index) {
int middle=(InterTree[index]->left + InterTree[index]->right)/;
if(max<middle) {
return CheckInterval(min, max, InterTree, *index);
} else if(min>middle) {
return CheckInterval(min, max, InterTree, *index+);
} else if(min==InterTree[index]->left &&
max==InterTree[index]->right) {
if(InterTree[index]->count>)
return InterTree[index]->count;
} else {
CheckInterval(min, middle, InterTree, *index);
CheckInterval(middle+, max, InterTree, *index+);
}
}
int GetOverlapSize(int *first, int lfirst, int *second, int lsecond) {
/**
* 获取first和second数组中各自的最大值与最小值的差值
* 选取差值较小的一个范围作为线段树的构建区间
* 节省空间消耗
* */
int minf=, maxf=,mins=,maxs=;
for(int i=;i<lfirst;i+=) {
if(maxf<first[i])
maxf=first[i];
if(minf>first[i])
minf=first[i];
}
for(int i=;i<lsecond;i+=) {
if(maxs<second[i])
maxs=second[i];
if(mins>second[i])
mins=second[i];
}
int min=minf,max=maxf;
int isFirst=true;
if((max-min)>(maxs-mins)) {
min=mins;
max=maxs;
isFirst=false;
}
/**
* 构建一个数组,数组元素为Interval*类型,
* 数组大小为线段树节点个数,由于线段树是
* 完全二叉树,所以节点数肯定为2N-1,N为区间
* 大小,也为叶节点数
* */
Interval *InterTree[*(max-min+)-];
/**
* 首先构建线段树的基本结构
* */
ConstructIT(min, max, InterTree, );
/**
* 然后将线段树范围大小对应的区间数组元素
* 插入到线段树中,如果区间在线段树之外则
* 需要特殊处理
* */
int *temp=NULL, length=;
int overlapSize=;
if(isFirst) {
for(int i=;i<lfirst;i+=) {
if(first[i]<InterTree[]->left ||
first[i-]>InterTree[]->right)
continue;
else if(first[i]==InterTree[]->left ||
first[i-]==InterTree[]->right)
overlapSize++;
else
InsertInfor(first[i-],first[i], InterTree, );
}
temp=second;
length=lsecond;
} else {
for(int i=;i<lsecond;i+=) {
if(second[i]<InterTree[]->left ||
second[i-]>InterTree[]->right)
continue;
else if(second[i]==InterTree[]->left ||
second[i-]==InterTree[]->right)
overlapSize++;
else
InsertInfor(second[i-],second[i], InterTree, );
}
temp=first;
length=lfirst;
}
/**
* 顺序将temp中的区间元素插入到InterTree中
* */ for(int i=;i<length;i+=) {
length+=CheckInterval(temp[i-],temp[i],InterTree,);
} }

笔试算法题(31):将有序数组转换成BST表示 & 线段树的应用的更多相关文章

  1. LeetCode 108. Convert Sorted Array to Binary Search Tree (将有序数组转换成BST)

    108. Convert Sorted Array to Binary Search Tree Given an array where elements are sorted in ascendin ...

  2. 笔试算法题(05):转换BST为双向链表 & 查找栈中的最小元素

    出题:把二元查找树转变成排序的双向链表.输入一棵二元查找树,要求将该二元查找树按照中序转换成一个排序的双向链表,要求不能创建任何新的节点,只能调整指针的指向: 分析: 递归的思路,当前节点需要进行的处 ...

  3. 笔试算法题(26):顺时针打印矩阵 & 求数组中数对差的最大值

    出题: 输入一个数字矩阵,要求从外向里顺时针打印每一个数字: 分析: 从外向里打印矩阵有多重方法实现,但最重要的是构建合适的状态机,这样才能控制多重不同的操作: 注意有四种打印模式(左右,上下,右左, ...

  4. [LeetCode每日一题]80. 删除有序数组中的重复项 II

    [LeetCode每日一题]80. 删除有序数组中的重复项 II 问题 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度. 不要使用额外 ...

  5. js将一个具有相同键值对的一维数组转换成二维数组

    这两天,一个前端朋友在面试的笔试过程中遇到了一道类似于"用js实现将一个具有相同code值的一维数组转换成相同code值在一起的二维数组"的题目.他面试过后,把这个问题抛给了我,问 ...

  6. LeetCode OJ:Convert Sorted Array to Binary Search Tree(将排序好的数组转换成二叉搜索树)

    Given an array where elements are sorted in ascending order, convert it to a height balanced BST. 讲一 ...

  7. C#字节数组转换成字符串

    C#字节数组转换成字符串 如果还想从 System.String 类中找到方法进行字符串和字节数组之间的转换,恐怕你会失望了.为了进行这样的转换,我们不得不借助另一个类:System.Text.Enc ...

  8. 100怎么变成100.00 || undefined在数字环境下是:NaN || null在数字环境下是0 || 数组的toString()方法把每个元素变成字符串,拼在一起以逗号隔开 || 空数组转换成字符串后是什么?

    100怎么变成100.00?

  9. C/C++中数组转换成指针的情况

    数组转换成指针:在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针.比如: int ia[10]; int *p = ia; //ia转换成指向数组首元素的指针 以下情况上述转换不会发生: ...

随机推荐

  1. Tomcat闪退的解决办法

    1 首先考虑的是端口占用 2 现在讲的是这一种方法 (1)找到解压缩的文件的bin目录 找到startup.bat 记事本打开 开头加上两句话 SET JAVA_HOME=C:\Program Fil ...

  2. bzoj 3609: [Heoi2014]人人尽说江南好【博弈论】

    参考:https://blog.csdn.net/Izumi_Hanako/article/details/80189596 胜负和操作次数有关,先手胜为奇,所以先手期望奇数后手期望偶数,最后一定能达 ...

  3. CF670C Cinema 【离散化+map】

    题意翻译 莫斯科在举办一场重要的有 nn 个不同国家的珂学家参与的国际会议,每个珂学家都只会一种语言.为了方便起见,我们规定一种语言用 11 到 10^9109 的数来描述. 在会议之后的晚上,珂学家 ...

  4. 原生javascript实现计时器

    成品图如意下所示: 实现加到等于5的时候停止 搭建HTML结构 minutes:<input type="text" value="0"> seco ...

  5. 【原创】CentOS 6.5 中安装 Mysql 5.6,并远程连接Mysql

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.在安装CentOS时,若选择的是Basic Server(可支持J2EE开发),则新安装好的CentOS系统中默认是已经安装了一个mysq ...

  6. 团队作业-项目Alpha版本发布

    一. 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2 这个作业要求在哪里 https://edu.cn ...

  7. Python字符串对象常用方法

    安利一句话:字符串是不可变的对象,所以任何操作对原字符串是不改变的! 1.字符串的切割 def split(self, sep=None, maxsplit=-1): # real signature ...

  8. 464 Can I Win 我能赢吗

    详见:https://leetcode.com/problems/can-i-win/description/ C++: class Solution { public: bool canIWin(i ...

  9. Windows 7操作系统下PHP 7的安装与配置(图文详解)

    前提博客 Windows 7操作系统下Apache的安装与配置(图文详解) 从官网下载           PHP的官网 http://www.php.net/         特意,新建这么一个目录 ...

  10. [转]符号和运算符参考 (F#)

    本文转自:http://msdn.microsoft.com/zh-cn/library/dd233228.aspx 本主题包含一个表,其中列出了 F# 语言中使用的符号和运算符. 符号和运算符表   ...