簡體   English   中英

如何從矢量或集合中更有效地擦除元素?

[英]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)

  • 第一個while循環運行n
  • 對於每次運行一次,使得總共n * 1 = n
  • 第二個while循環每次運行一次,再次使它成為n
    • 從向量中刪除意味着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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM