最大数-头条2018校招笔试题(第一批)

题目内容
P为给定的二维平面整数点集。定义 P 中某点x,如果x满足 P 中任意点都不在 x 的右上方区域内(横纵坐标都大于x),则称其为“最大的”。求出所有“最大的”点的集合。(所有点的横坐标和纵坐标都不重复, 坐标轴范围在[0, 1e9) 内)
如下图:实心点为满足条件的点的集合。请实现代码找到集合 P 中的所有 ”最大“ 点的集合并输出。

输入
第一行输入点集的个数 N, 接下来 N 行,每行两个数字代表点的 X 轴和 Y 轴。
对于 50%的数据, 1 <= N <= 10000;
对于 100%的数据, 1 <= N <= 500000;
示例如下:
5
1 2
5 3
4 6
7 5
9 0

输出
输出“最大的” 点集合, 按照 X 轴从小到大的方式输出,每行两个数字分别代表点的 X 轴和 Y轴。
示例如下:
4 6
7 5
9 0

解决问题思路

O(n^2)的解法

如果对于乱序数据,用一个容器存储最大数的数据点,容器初始化为空,然后线性扫描所有的数据点:对于每扫描一个数据点xn,对比容器中的所有数据xi,看是否存在:

  1. 若xn.x<=xi.x&&n.y<=xi.y,则pass数据点xn,继续下一个点
  2. 若xn.x>=xi.x&&n.y>=xi.y,则说明xi不是数据点,应该从容器中丢掉
  3. 除了情况(1)外,都应该将数据点xn放入容器,继续下一个点的扫描
    从上面的运算来看,最坏的情况下是所有数据点都是最大数,需要 n(n1)/2 n ∗ ( n − 1 ) / 2 次比较,应该能过50%数据,但是不建议。
O(n log n)的解法

上面的解法是对于乱序的数据,只能进行暴力扫描。那换言之,我们能不能先将其转为有序,再使用更加快捷的方法了,答案是肯定的!
我们注意到,虽然我们不能对2维的数据进行直接排序,但是我们可以先根据其中的一维进行排序(这也是常见的方法),比如我们就直接对所有数据点根据x排序,那我们再去逐个扫描数据,当前扫描的数据点xn对于前面扫描的数据点而言肯定是最大数(因为x坐标上不可能有比它大的),只要比对前面的数据点是不是也是最大数,而这个时候,只要判断xi.y<=xn.y即可,如果成立,即将xi移除(因为排序,所以已经有xi.x<=xn.x成立)。这里我们会发现,最后一个加入的数据点xn的y是当前容器数据点中最小的(比它小的xi.y<=xn.y都会被移除了),所以加入容器的最大数是按照x递增,y递减的方向的规律去的。如果我们用容器stack存储最大数,每次加入一个数据点xn时,只要比对后面加入到容器的数据,看是否满足xi.y<=xn.y,是则将xi从容器中剔除,直到stack的top不满足该条件,将xn加入到stack中。
从上面的分析来看,运算复杂度主要是排序需要O(n log n)的复杂度,扫描的复杂度为O(n),实现代码如下:

#include
#include
using namespace std;
struct Point{
    int x;
    int y;

};
bool cmp(Point x1,Point x2){
    return x1.xint main(){
    int N;
    cin >>N;

    Point p[N];
    for(int i=0;i>p[i].x>>p[i].y;

    sort(p,p+N,cmp);

    int index[N];      //存放当前认为输入最大点的下标,用数组模拟deque的功能
    index[0]=0;
    int count = 1;
    for(int i=1;iwhile(count>0&&p[index[count-1]].y<=p[i].y){  
            count--;
        }
        index[count++]=i;
    }
    for(int i=0;i<count;i++){
        cout<index[i]].x<<" "<index[i]].y<return 0;
}

你可能感兴趣的:(算法题)