1. 程式人生 > >2018頭條面試演算法方向程式設計題

2018頭條面試演算法方向程式設計題

P為給定的二維平面整數點集。定義 P 中某點x,如果x滿足 P 中任意點都不在 x 的右上方區域內(橫縱座標都大於x),則稱其為“最大的”。求出所有“最大的”點的集合。(所有點的橫座標和縱座標都不重複, 座標軸範圍在[0, 1e9) 內)

如下圖:實心點為滿足條件的點的集合。請實現程式碼找到集合 P 中的所有 ”最大“ 點的集合並輸出。



輸入描述:
第一行輸入點集的個數 N, 接下來 N 行,每行兩個數字代表點的 X 軸和 Y 軸。
對於 50%的資料,  1 <= N <= 10000;
對於 100%的資料, 1 <= N <= 500000;


輸出描述:
輸出“最大的” 點集合, 按照 X 軸從小到大的方式輸出,每行兩個數字分別代表點的 X 軸和 Y軸。

輸入例子1:
5
1 2
5 3
4 6
7 5
9 0

輸出例子1:
4 6
7 5
9 0

題解:

    按x軸排序和按y軸排序,標記其id。按x軸從大到小排序,第一個肯定符合,下一個要想符合就要保證上面的y值都小於當前值,因為當前的x值一定比上面的值小,所以如果y值也有比上面小的那這個點肯定不符合,尋找y軸排序的一樣。注意重複的,就用id標記一下

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5+7;
struct node{
    int x,y;
    int id;
}a[N],b[N],c[N];
int vis[N];
bool cmp1(node u,node v){
    if(u.x!=v.x)return u.x>v.x;
    return u.y>v.y;
}
bool cmp2(node u,node v){
    if(u.y!=v.y)return u.y>v.y;
    return u.x>v.x;
}
int main(){
    int n;
    scanf("%d",&n);
    memset(vis,0,sizeof(vis));
    for(int i = 0;i<n;i++){
        scanf("%d%d",&a[i].x,&a[i].y);
        a[i].id = i;
        b[i] = a[i];
    }
    sort(a,a+n,cmp1);
    sort(b,b+n,cmp2);
//    printf("----------------\n");
//    for(int i = 0;i<n;i++){
//        printf("%d %d + ",a[i].x,a[i].y);
//        printf("%d %d\n",b[i].x,b[i].y);
//    }
//    printf("----------------\n");
//    for(int i = 0;i<n;i++){
//        printf("%d %d\n",b[i].x,b[i].y);
//    }
    //printf("----------------\n");
    int j = 0;
    int cnt = 0;
    int my = -1,mx = -1;
    while(j<n){
        if(vis[a[j].id]==0){
            vis[a[j].id]=1;
            if(my>a[j].y)continue;
            c[cnt++] = a[j];
            my = max(my,a[j].y);
        }
        j++;
    }
    j = 0;
    while(j<n){
        if(vis[a[j].id]==0){
            vis[a[j].id]=1;
            if(mx>a[j].x)continue;
            c[cnt++] = a[j];
            mx = max(mx,a[j].y);
        }
        j++;
    }
    sort(c,c+cnt,cmp1);
    for(int i = cnt-1;i>=0;i--){
        printf("%d %d\n",c[i].x,c[i].y);
    }
    return 0;
}