出题:要求将一个有序整数数组转换成最小深度的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. spoj 371 Boxes【最小费用最大流】

    对于ai==0连接(i,t,1,0),对于ai>1(s,i,ai-1,0),然后对以相邻的两个点(i,j)连接(i,j,inf,1),注意这里是一个环的形式,所以1和n+1相连 #include ...

  2. 洛谷P4114 Qtree1(树链剖分+线段树)

    传送门 LCT秒天秒地用什么树剖 这题可以算是树剖的比较裸的题目了 把每一条边的权值下放到他两边的点中深度较深的那个 然后直接用树剖+线段树带进去乱搞就可以了 //minamoto #include& ...

  3. 深入学习Ajax

    1.什么是Ajax? AJAX的全称是Asynchronous Javascript And XML (异步的JavaScript和XML).是一种在无需重新加载整个网页的情况下,能够更新部分网页的技 ...

  4. _bzoj2005 [Noi2010]能量采集

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2005 令F(i)表示i | gcd(x, y)的对数,f(i)表示gcd(x, y) = i ...

  5. 题解报告:hdu 1228 A+B(字符串)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1228 Problem Description 读入两个小于100的正整数A和B,计算A+B. 需要注意 ...

  6. 题解报告:hdu 2087 剪花布条(KMP入门)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面 ...

  7. Class.getResourceAsStream()与ClassLoader.getResourceAsStream()获取资源时的路径说明

    Class.getResourceAsStream(): com.xusweeter.iot.ws.vodafone.config.VodafoneServiceConfig.class.getRes ...

  8. 求指教--hadoop2.4.1集群搭建及管理遇到的问题

    集群规划: 主机名 IP 安装的软件 运行的进程 hadooop 192.168.1.69 jdk.hadoop NameNode.DFSZKFailoverController(zkfc) hado ...

  9. 工具类学习-java实现邮件发送激活码

    问题:用java实现服务器发送激活码到用户邮件. 步骤一:如果是个人的话,确保在本地安装邮件服务器(易邮服务器)和邮件客户端(foxmail). 步骤二:导入jar包  mail.jar,其他的需要什 ...

  10. vue项目中安装cnpm和node_modules

    1.安装cnpm的nodejs包管理工具,命令行: npm install -g cnpm --registry=https://registry.npm.taobao.org   2. 每个vue项 ...