[英]Get number of elements greater than a number
我正在嘗試解決以下問題:正在將數字插入到容器中。 每次插入一個數字時,我都需要知道容器中有多少元素大於或等於當前插入的數字。 我相信這兩種操作都可以在對數復雜度中完成。
我的問題: C++ 庫中是否有可以解決問題的標准容器? 我知道std::multiset
可以在對數時間內插入元素,但是如何查詢呢? 或者我應該實現一個數據結構(例如二叉搜索樹)來解決它?
很好的問題。 我認為 STL 中沒有任何東西可以滿足您的需求(前提是您必須有對數時間)。 正如 aschepler 在評論中所說,我認為最好的解決方案是實現 RB 樹。 您可以查看 STL 源代碼,特別是在stl_tree.h
,看看您是否可以使用它的一部分。
更好的是,看看:( C++ 中的排名樹)
其中包含實現的鏈接:
您應該使用多重集來計算對數復雜度,是的。 但是計算距離是問題所在,因為 set/map 迭代器是雙向的,而不是 RandomAccess,std::distance 的復雜度為 O(n):
multiset<int> my_set;
...
auto it = my_map.lower_bound(3);
size_t count_inserted = distance(it, my_set.end()) // this is definitely O(n)
my_map.insert(make_pair(3);
您的復雜性問題很復雜。 這是一個完整的分析:
如果你想要每次插入的復雜度為 O(log(n)),你需要一個排序的結構作為一個集合。 如果您希望結構在添加新項目時不重新分配或移動項目,插入點距離計算將為 O(n)。 如果預先知道插入大小,則在已排序的容器中不需要對數插入時間。 您可以將所有的物品然后進行排序,這是盡可能多的O(n.log(N))為N * O(日志(n))的一組插入。 唯一的選擇是使用專用容器,如加權 RB 樹。 根據您的問題,這可能是解決方案,或東西真的矯枉過正。
multiset
和distance
,你是 O(n.log(n)) 插入(是的,n 插入 * log(n) 插入時間為每個),O(nn) 在距離計算上,但計算距離非常快。存在稱為有序集的東西,它允許您在 O(logN) 時間內插入/刪除元素(以及 std::set 必須提供的幾乎所有其他功能)。 它還提供了另外 2 個功能:查找第 K 個元素和**查找第 X 個元素的等級。 問題是這不允許重復:(
不過不用擔心! 我們將使用單獨的索引/優先級映射重復項,並定義一個新結構(稱為有序多集)! 我在下面附上了我的實現以供參考。
最后,每次你想找到大於 x 的元素數時,調用函數 upper_bound(小於或等於 x 的元素數)並從有序多重集的大小中減去這個數字!
注意:PBDS 使用大量內存,所以這是一個限制,我建議使用二叉搜索樹或 Fenwick 樹。
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
struct ordered_multiset { // multiset supporting duplicating values in set
int len = 0;
const int ADD = 1000010;
const int MAXVAL = 1000000010;
unordered_map<int, int> mp; // hash = 96814
tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> T;
ordered_multiset() { len = 0; T.clear(), mp.clear(); }
inline void insert(int x){
len++, x += MAXVAL;
int c = mp[x]++;
T.insert((x * ADD) + c); }
inline void erase(int x){
x += MAXVAL;
int c = mp[x];
if(c) {
c--, mp[x]--, len--;
T.erase((x*ADD) + c); } }
inline int kth(int k){ // 1-based index, returns the
if(k<1 || k>len) return -1; // K'th element in the treap,
auto it = T.find_by_order(--k); // -1 if none exists
return ((*it)/ADD) - MAXVAL; }
inline int lower_bound(int x){ // Count of value <x in treap
x += MAXVAL;
int c = mp[x];
return (T.order_of_key((x*ADD)+c)); }
inline int upper_bound(int x){ // Count of value <=x in treap
x += MAXVAL;
int c = mp[x];
return (T.order_of_key((x*ADD)+c)); }
inline int size() { return len; } // Number of elements in treap
};
ordered_multiset s;
for(int i=0; i<n; i++) {
int x; cin>>x;
s.insert(x);
int ctr = s.size() - s.upper_bound(x);
cout<<ctr<<" ";
}
輸入 (n = 6) : 10 1 3 3 2
輸出: 0 1 1 1 3
參考資料: mochow13 的 GitHub
聽起來像是count_if
一個例子——雖然我承認這不能以對數復雜度解決它,但這需要一個排序類型。
vector<int> v = { 1, 2, 3, 4, 5 };
int some_value = 3;
int count = count_if(v.begin(), v.end(), [some_value](int n) { return n > some_value; } );
已完成編輯以修復 lambda 函數的語法問題
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.