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是原始資料的順序,要去重另加程式碼
}
}