最近做了一些需要離散資料的題目,比如ural 1019 以及poj 2528等,由於資料較大,如果用傳統的方法建立對應的資料結構消耗的記憶體和時間肯定是不能被接受的。由於以前沒有怎麼接觸過需要離散化的題目,於是就通過自己最近的做題經驗以及網上的部分資料,整理並講解了常用的離散資料的方法。
何為離散化?離散化,就是把無限空間中有限的個體對映到有限的空間中去,以此提高演算法的時空效率。
比如給你n個數:98998988,32434234,433234556,32434234,8384733,……
讓你統計其中每個數出現的次數,傳統的做法有好幾種,比如一遍一遍的掃過去,比對疊加,這樣演算法的效率是o(n2),效率低下;
再比如先排序,再統計連續的相同的個數,這裡的效率已經有所提高了,不過假如上面的資料是一道線段樹的題目給出的資料,那麼建樹需要的空間開銷實在是太大了。
再改進一下,採用雜湊的方法,開乙個大於其中最大數的陣列並初始化為零,o(n)掃一下,在該數字對應的下標的元素上+1,如果對於比較小的數字還好說,但是對於上面出現的數字直接採用雜湊對空間的開銷是十分大的也是沒有必要的,所以這裡用到了資料的離散化。
首先將數字排序:32434234,32434234,43324556,8384733,98998988
去重後給予其對應的索引:0,0,1,2,3分別對應每個數,就可以簡化很多操作,減少了很多不必要的資源開銷。
除了對於較大整數需要使用離散化之外,對於一些需要使用整型資料結構,但給出的資料卻是小數的也可以使用離散化,將其索引為整數就可以了。
那麼可以總結出離散化的步驟:
1、排序
2、去重
3、索引
為了簡化**,我們採用stl演算法離散化:
int a[n], b[n], sub[n]; //a[n]是即將被離散化的陣列,b[n]是a[n]的副本,sub用於排序去重後提供離散化後的值
sort(sub, sub +n);
int size = unique(sub, sub + n) -sub;
for(int i = 0; i < n; i++)
a[i] = lower_bound(sub, sub + size, a[i]) - sub; //
即a[i]為b[i]離散化後對應的值
對於第3步,若離散化後序列為0, 1, 2, ..., size - 1則用lower_bound,從1, 2, 3, ..., size則用upper_bound,其中lower_bound返回第1個不小於b[i]的值的指標,而upper_bound返回第1個大於b[i]的值的指標,當然也可以用lower_bound然後再加1得到與upper_bound相同結果,兩者都是針對以排好序列。使用stl離散化大大減少了**量且結構相當清晰。
離散化後查詢的問題(採用的如上**的離散方式):
1、通過離散後的值查詢離散前的值:
若離散後的值為x,那麼對應的離散前的值為sub[x];
2、通過離散前的下標查詢離散後的值:
若離散前的下標為i,那麼對應的離散後的值為a[i];
3、通過離散前的值查詢離散後的值:
如果沒有相應的儲存的話,首先要確定y在sub中的位置,或者在b中的位置,前者可以使用pos = lower_bound(sub, sub+size, y) - sub。那麼pos即為下標,通過第二步再查詢就好了。
感覺stl演算法的離散是最實用的,**量最小的,適合競賽的時候使用,若還有更加簡便高效的方法,我肯定還會再將其整理上來。
離散化思想
離散化,把無限空間中有限的個體對映到有限的空間中去,以此提高演算法的時空效率。通俗的說,離散化是在不改變資料相對大小的條件下,對資料進行相應的縮小。例如 原資料 1,999,100000,15 處理後 1,3,4,2 原資料 處理後 include include include using nam...
離散化思想
離散化是什麼 一些數字,他們的範圍很大 0 1e9 但是個數不算多 1 1e5 並且這些數本身的數字大小不重要,重要的是這些數字之間的相對大小 比如說某個數字是這些數字中的第幾小,而與這個數字本身大小沒有關係,要的是相對大小 6 8 9 4 離散化後即為2 3 4 1 要理解相對大小的意思 6在這4...
離散化思想
離散化是程式設計中乙個非常常用的技巧,它可以有效的降低時間複雜度。其基本思想就是在眾多可能的情況中 只考慮我需要用的值 下面我將用三個例子說明,如何運用離散化改進乙個低效的,甚至根本不可能實現的演算法。演算法藝術與資訊學競賽 中的計算幾何部分,黃亮舉了乙個經典的例子,我認為很適合用來介紹離散化思想。...