0

I have with myself n integers. I am given with starting value(SV) and ending value(EV), I need to delete the values that lie within the range of these values. The starting value as well the ending value may not exist in the set of n integers. This I need to do in O(No. Of elements deleted). Container such as vector of integers is failing since I need to B.Search and get the iterator that is greater than equal to the SV and for EV as well which takes an additional time of Log n. Any approach appreciated.

Edit : I was even thinking of using maps, storing the values as keys, and erasing on the basis of those key values. But the problem again is that the operation lower_bound and upper_bound occur in log time.

Akash
  • 939
  • 1
  • 8
  • 27
  • 1
    "Adds a factor of Log N" is rather confusing. A "factor" usually refers to a multiplier. In this case, it's not a multiplication. You have `O(N) + O(log N) + O(log N)` which is just `O(N)`. (Since O(log N) is a subset of O(N) and 3*O(N) is still O(N)). On a c++ note, what's wrong with `std::set` ? – MSalters May 17 '17 at 11:33
  • @MSalters corrected it. – Akash May 17 '17 at 11:37
  • Assuming you use an already sorted data structure, you won't be able to delete your elemens in `O(No. of elements deleted)` since already searching for an element in a sorted datastructure needs in general `log(N)` where N is the number of elements in the datastructure. The best you can achieve is `O(No. of elements deleted + log(N))` – blacktemplar May 17 '17 at 11:39
  • @Akash, with std::set the compexity will be `O(No. of elements deleted + logN)`. It's not a factor. – DAle May 17 '17 at 11:40
  • Can you please elaborate how ! @DAle – Akash May 17 '17 at 11:41
  • @Akash, you'll find two iterators (your range) with `lower_bound` in `O(logN)` and then erase all elements in that range with `erase` in `O(No of elements deleted)` – DAle May 17 '17 at 11:44
  • @DAle Oh yes, but my problem is if I repeat this operation a certain number of times, the `log n` becomes a factor, while the number of elements deleted becomes O(n), n = no. of elements deleted. I want the latter. No `log n` factor. – Akash May 17 '17 at 11:46
  • 2
    When assigning `O` complexity only the largest factor is considered. Erasing `n` elements should dominate a binary search to find the elements to erase. – Galik May 17 '17 at 11:49
  • @Galik Suppose each time I delete only `1` element and repeat the operation `n` no. of times, then the time for delete is `O(n)` and searching adds each time overhead of `log n` , i.e. total of `O(nlogn)`, hence `O(nlogn)` dominates in the case, and not the erasing part. – Akash May 17 '17 at 11:53
  • 2
    @Akash, I don't think you could get rid of logarithmic search operations if you don't have any details that you didn't tell us. May be you have some restrictions on numbers or delete operations? – DAle May 17 '17 at 11:55
  • Seems like it. Thanks anyways ! – Akash May 17 '17 at 11:56
  • 1
    @Galik: True, but we have two different variables here: container size and erase size. If the container size is much, much larger than the erase size, even log(container size) > erase size. In particular, Akash suggests that the erase size can be as small as 1. – MSalters May 17 '17 at 11:59
  • Even with a full space over time tradeoff (`std::vector`), you only get O(1) searching of elements, but erasure now is O(EV-SV). – MSalters May 17 '17 at 12:00
  • Is this about Standard Template Library of C++ Standard Library? I know the term STL is used ambiguously. – Persixty May 17 '17 at 12:04
  • Given that the container size and number to erase size are unknown then we can assume that *on average* the erase size would be half the container size all things being random. – Galik May 17 '17 at 12:04
  • But with that you cant formulate O() time bounds @Galik – Akash May 17 '17 at 12:05
  • @Akash You can usually contrive a *worst case scenario* for an algorithm. But you have to take the unknwn as completely random unless you have more details to add to the problem – Galik May 17 '17 at 12:06
  • You can provide an *amortized* `O` value – Galik May 17 '17 at 12:07
  • Ya thats ok, but I require O() time bounds and must inlcude in it worst case. :( @Galik – Akash May 17 '17 at 12:07

3 Answers3

3

If you need keep order in container just use: set http://www.cplusplus.com/reference/set/set/ or multiset http://www.cplusplus.com/reference/set/multiset/ if values can repeat.

Both have lower_bound and upper_bound functionality.

Marek R
  • 32,568
  • 6
  • 55
  • 140
0

You can use the erase-remove idiom with std::remove_if to check if each value is between the two bounds.

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> values = {1,2,3,4,5,6,7,8,9};
    int start = 3;
    int stop = 7;
    values.erase(std::remove_if(values.begin(),
                                values.end(),
                                [start, stop](int i){ return i > start && i < stop; }),
                 values.end());
    for (auto i : values)
    {
        std::cout << i << " ";
    }
}

Output

1 2 3 7 8 9  
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • Can you please elaborate on the functioning of this and the time complexity. – Akash May 17 '17 at 11:40
  • The erase-remove idiom is O(N) in time complexity, where N is the original number of elements in the container. This is because you must compare every element against your predicate (in this case, if the number is outside the allowable bounds) – Cory Kramer May 17 '17 at 11:43
  • But I want my algo to be `O(no of elements deleted)` and not `O(N)`,`N` being no of elements in container. – Akash May 17 '17 at 11:50
0

As Marek R suggested there is std::multiset.

Complexity of the whole exercise is O(log(values.size()+std::distance(first,last)) where that distance is 'number of elements erased'.

It's difficult to see how you can beat that. At the end of it there is always going to be something that increases with the size of the container and log of it is a good deal!

#include <iostream>
#include <set>

void dump(const std::multiset<int>& values);

int main() {
    std::multiset<int> values;
    values.insert(5);
    values.insert(7);

    values.insert(9);
    values.insert(11);
    values.insert(8);
    values.insert(8);
    values.insert(76);

    dump(values);
    auto first=values.lower_bound(7);
    auto last=values.upper_bound(10);    
    values.erase(first,last);
    dump(values);

    return 0;
}

void dump(const std::multiset<int>& values){
    auto flag=false;
    std::cout<<'{';
    for(auto curr : values){
        if(flag){
            std::cout<<',';
        }else{
            flag=true;
        }
        std::cout<< curr;
    }
    std::cout<<'}'<<std::endl;
}
Persixty
  • 8,165
  • 2
  • 13
  • 35