設計一種資料結構能夠實現以下幾個操作
在結構中插入乙個數字x
在結構中刪除乙個數字x(如果沒有該數字,應當不操作)
查詢結構中的第k小數字(相同數字應當累計,如 1 5 3 3 1,第 3 大的數字是 3, 第 5 大的數字是 5.
其中1 <= x <= 100000
一秒需要執行100000次隨機操作,所以三項操作時間複雜度應當不超過log級。
插入乙個數字x就是令陣列的第x位置 + 1,實際上就是個桶排序。
刪除乙個數字就是令陣列的第x位置 - 1,如果本來就是 0 了就不操作。
查潤第 k 小數字,我們只需要從 1 開始列舉個數cnt,直到 cnt 第一次大於等於 k 那麼作為答案輸出。
在上面的思路中可以看到,插入和刪除都是o(1)的,但是查詢操作是o(n)的。可以可能就會有乙個**的資料,插入乙個數字100000然後查詢99999次第1小的數字,那麼時間複雜度就會是o(n2),然後就會tle 。
不過可以看到實際上第三個步驟就是一直在求前n項的和,所以選擇用樹狀陣列(線段樹)維護該項操作,使得查詢某一段的數字的個數變成o(logn),比如我要快速知道0 ~ 1000 元素的個數是多少個,只需要o(log)運算(10次),而原先需要o(n)運算(1000次列舉)。代價是插入和刪除的時間複雜度都會變成o(logn)灑灑水啦 。
最後,在查詢的是時候使用二分設定左邊界為0,右邊界為n,先看看0 ~ n之間的個數,如果小於 k 直接返回 -1 表示查詢不合法,如果大於 k ,說明這部分元素太多了,求出 mid = (l + r) / 2,求得 0 ~ mid 之間有多少個數字,如果大於 k 再往左邊( r = mid)查詢, 否則說明數字個數比較少了,往右邊(l = mid + 1)查詢,直到 l >= r 結果收斂,把 l 作為結果返回。
向集合中插入乙個元素的最壞時間複雜度為logn(樹狀陣列修改)
刪除集合中乙個元素的最壞時間複雜度為logn(樹狀陣列修改)
查詢集合中第k小元素的最壞時間複雜度為logn * log n(二分 + 樹狀陣列查詢)
#include
using
namespace std;
const
int n =
100010
;/****
設計一種資料結構能夠實現以下幾個操作
向集合中插入乙個數字x
向集合中刪除乙個數字x(如果沒有該數字,應當不操作)
查詢集合中的第k小數字(相同數字應當累計,如 1 5 3 3 1,第 3 大的數字是 3, 第 5 大的數字是 5.
其中 1 <= x <= 100000
一秒需要執行100000次隨機操作,所以三項操作時間複雜度應當不超過log級
***/
int tr[n]
;void
init()
intlowbit
(int x)
void
add(
int x,
int k)
intquery
(int x)
void
insert
(int x)
intdel
(int x)
return
false;}
intkth
(int k)
return l;
}int
main()
字典序的第K小數字
給定整數 n 和 k,找到 1 到 n 中字典序第 k 小的數字。1 k n 109。n 10時,字典序 1,10,2,3,4,5,6.可以把這n個數字看成字典樹,那麼每乙個字首都代表乙個數字,其中每個節點有10個兒子,0 9.那麼字典樹的先序遍歷的第k個就是答案。所以得到了乙個o k 的做法。這類...
第 K 小數字問題 (優先佇列實現)
首先了解優先佇列 可以理解優先佇列就是乙個含有內部排序的佇列,具有佇列的一切屬性,本質上是通過堆來實現的。定義語法 priority queue type 是資料型別 注意 資料元素的型別可以是pair型別 container 由陣列實現的一些資料結構,如 vector,deque,不可以是list...
廈門1165 第K小數 樹狀陣列 不重複數字
1165.第k小數 time limit 1000 ms memory limit 65536 k total submissions 467 117 users accepted 117 66 users my solution description 給定乙個空的正整數集合s,然後再給定一組操作...