1. 程式人生 > >acm資料預處理 —— 離散化的兩種方法

acm資料預處理 —— 離散化的兩種方法

部落格目錄

引言

如果我們要處理一些資料,如果:

我們只關心資料之間相對大小,而不關心每個資料到底有多大

離散化的大體意思就是:給資料重新編號,使新號碼依然具有跟之前相同的大小關係,來使資料更加緊湊。

比如說:給一個無向圖,每個節點都以一個字元表示,那麼我們就可以將字元替換成數字123...

再比如說:現在有1000個[-1e9,1e9]範圍的整數,計數統計一下每個數出現的次數。由於開一個2e9大小的陣列實在是太浪費空間了,而且只有一千個數,遍歷2e9的時間開銷也實在是浪費,所以我們可以根據原資料的相對大小重新編號,對編號進行計數,也也就達到了對元資料進行計數的目的。

方法1:排序加折半查詢(nlogn的時間複雜度,我之前不太喜歡用的方法但是大家都用,程式碼比較精簡,但是不易還原輸入順序)

    cin>>n;

    int co[1000];
    for(int i=0;i<n;i++){
        cin>>co[i];
    }
    sort(co,co+n);
    int size=unique(co,co+n)-co;//去重函式,將重複的都移到後邊,然後用size截掉,相同元素僅保留一個, 
                                //如果不需要去重則刪掉這一句。size為離散化後元素個數 
    for(int i=0;i<n;i++)
        arr[i]=lower_bound(co,co+size,arr[i])-co + 1;//arr存放了排序後,第i個數字新的編號。

方法2:捆綁排序,時間複雜度O(nlogn),老實說是我自己的土辦法。如果想還原輸入順序直接對i在進行排序即可

struct inp{
    int i,v,n;
};

inp co[1000];

int operator<(inp a,inp b){
    return a.v<b.v;
}
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>co[i].v;
        co[i].i=i;
    }
    sort(co,co+i);
    for(int i=0;i<n;i++){
        co[i].n=i+1; //n是新的標號,v是原始資料,i是原始資料的順序,要去重另加程式碼
    }
}