您的位置:首页 > 职场人生

算法面试题之求前1000大&在树上判断节点父子关系

2015-01-13 14:19 357 查看
一、有10亿个杂乱无章的数,怎样最快地求出其中前1000大的数。

想答对这个题是非常简单的,建立一个大小为1000的小根堆就可以了。这个堆满足两个性质:

1.堆中的元素个数总是小于等于1000的

2.堆顶取出的元素总是这个堆里面最小的那一个

这样,这个题可以这样做:

priority_queue<int> q;
while (cin>>n)
{
n=-n; //c++中默认优先队列是一个大根堆,因此把所有元素乘以-1就可以当小根堆用了
if (q.size()<1000)
q.push(n);
else
{
int t=q.top();
if (t>n)
{
q.pop();
q.push(n);
}
}
}
这个做法时间复杂度是O(Nlog(1000)),空间复杂度是O(1000),对于这个题来说已经非常快了大约是O(10n)。

二、一棵树节点1,
2, 3, ... , n. 怎样实现:先进行O(n)预处理,然后任给两个节点,用O(1)判断它们的父子关系

这个题目是DFS序的简单应用,首先来看看什么是DFS序,对于一棵树,有下面4条边:

1-2,1-3,2-4,2-5

那么,它的DFS序是:1,2,4,5,3,这里只是通过一次简单的深度优先搜索把每个节点访问的次序标了出来,如果每个节点在被访问的这一刻记录一次,访问结束的时候再记录一次,那又能是什么样子呢?代码是这样的:

int dfs(int i)
{
q.push_back(i);
for (int j=0;j<edge[i].size();j++)
if (!vis[edge[i][j]])
{
vis[edge[i][j]]=1;
dfs(edge[i][j]);
}
q.push_back(i);
}


此时,上面这幅图,它的dfs序变成了:1,2,4,4,5,5,2,3,3,1。

观察这个序列,可以发现:节点i是节点j的祖先,当且仅当节点i出现的两个位置x1,x2在节点j出现的两个位置y1,y2的两边,也就是x1<y1<y2<x2。所以,在生成dfs序的时候顺便记录每个节点dfs序出现的位置,之后每读入一个询问,直接O(1)判断并输出就可以了。

三. 给定一个二叉树,求其中N(N>=2)个节点的最近公共祖先节点。

这道题跟上面那道题解法非常像,首先求出来dfs序,拿第二题为例,dfs序为1,2,4,4,5,5,2,3,3,1,此时,要求4,5,3三个节点的最近公共祖先,怎么求呢?直接从4,5,3dfs序出现的最早位置开始枚举,遇到的第一个dfs序出现位置小于等于它,结束位置大于等于这三个节点最早结束位置的节点,就是我们要求的解,对于这个样例,l=3,r=9,代表4,5,3出现的最早和最迟位置,答案是1,因为L[1]=1<=3,R[1]=11>=9。

时间复杂度O(N)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐