[英]How to erase elements more efficiently from a vector or set?
問題陳述:
輸入:
前兩個輸入是整數n和m。 n是在比賽中戰斗的騎士數量(2 <= n <= 100000,1 <= m <= n-1)。 m是將要發生的戰斗次數。
下一行包含n個功率電平。
接下來的m行包含兩個整數l和r,表示在第i場戰斗中參加騎士陣地的范圍。
每次戰斗結束后,除了最高功率級別之外的所有夜晚都將被淘汰。
每場戰斗的范圍是根據騎士的新位置而不是原始位置給出的。
輸出:
輸出m行,第i行包含該戰斗中騎士的原始位置(指數)。 每行按升序排列。
樣本輸入:
8 4
1 0 5 6 2 3 7 4
1 3
2 4
1 3
0 1
樣本輸出:
1 2
4 5
3 7
0
以下是此過程的可視化。
1 2
[(1,0),(0,1),(5,2),(6,3),(2,4),(3,5),(7,6),(4,7)]
-----------------
4 5
[(1,0),(6,3),(2,4),(3,5),(7,6),(4,7)]
-----------------
3 7
[(1,0),(6,3),(7,6),(4,7)]
-----------------
0
[(1,0),(7,6)]
-----------
[(7,6)]
我已經解決了這個問題。 我的程序產生正確的輸出,但是,它是O(n * m)= O(n ^ 2)。 我相信如果我從矢量中更有效地消除騎士,效率可以提高。 使用集合擦除元素會更有效嗎? 即擦除連續的段而不是單個騎士。 有沒有其他方法可以做到更有效率?
#define INPUT1(x) scanf("%d", &x)
#define INPUT2(x, y) scanf("%d%d", &x, &y)
#define OUTPUT1(x) printf("%d\n", x);
int main(int argc, char const *argv[]) {
int n, m;
INPUT2(n, m);
vector< pair<int,int> > knights(n);
for (int i = 0; i < n; i++) {
int power;
INPUT(power);
knights[i] = make_pair(power, i);
}
while(m--) {
int l, r;
INPUT2(l, r);
int max_in_range = knights[l].first;
for (int i = l+1; i <= r; i++) if (knights[i].first > max_in_range) {
max_in_range = knights[i].first;
}
int offset = l;
int range = r-l+1;
while (range--) {
if (knights[offset].first != max_in_range) {
OUTPUT1(knights[offset].second));
knights.erase(knights.begin()+offset);
}
else offset++;
}
printf("\n");
}
}
好吧,從矢量中刪除肯定不會有效。 從set或unordered set中刪除會更有效(使用迭代器而不是索引)。
然而問題仍然是O(n ^ 2), 因為你有兩個嵌套的運行n * m次。
- 編輯 -
我相信我現在理解這個問題:)首先讓我們計算一下上面代碼的復雜性。 最糟糕的情況是所有戰斗中的最大射程為1(每場戰斗兩晚)並且戰斗不是根據位置進行的。 這意味着你有戰斗(在這種情況下m = n-1~ = O(n) )
因此,隨着向量的復雜性,總復雜度為O(n ^ 2)
首先,你並不需要內部for循環。 將第一個騎士作為范圍內的最大值,將其中的其余部分逐一進行比較並移除失敗的騎士。
現在,我相信它可以在使用std :: map的O(nlogn)中完成。 地圖的關鍵是位置,值是騎士的等級。
在繼續之前,在map中查找和刪除元素是對數的,迭代是不變的。
最后,您的代碼應如下所示:
while(m--) // n times
strongest = map.find(first_position); // find is log(n) --> n*log(n)
for (opponent = next of strongest; // this will run 1 times, since every range is 1
opponent in range;
opponent = next opponent) // iterating is constant
// removing from map is log(n) --> n * 1 * log(n)
if strongest < opponent
remove strongest, opponent is the new strongest
else
remove opponent, (be careful to remove it after iterating to next)
好的,現在上限是O(2 * nlogn)= O(nlogn) 。 如果范圍增加,則會使上部循環的運行時間減少,但會增加刪除操作的數量。 我確定上限不會改變,讓我們把它作為你的家庭作業來計算:)
采用treap的解決方案非常簡單。
對於每個查詢,您需要通過隱式鍵拆分treap以獲取與[l, r]
范圍對應的子樹(它需要O(log n)
時間)。 之后,您可以迭代子樹並找到具有最大強度的騎士。 之后,您只需要將treap的[0, l)
和[r + 1, end)
部分與對應於此騎士的節點合並。
很明顯,除了子樹遍歷和打印之外,解決方案的所有部分都在每個查詢的O(log n)
時間內工作。 但是,每個操作只重新插入一個騎士並從范圍中擦除其余部分,因此輸出的大小(以及子樹大小的總和)在n
是線性的。 因此總時間復雜度為O(n log n)
。
我不認為你可以使用標准的stl容器來解決,因為沒有標准的容器支持通過索引快速獲取迭代器並刪除任意元素。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.