Below is a block of code from leetcode, I'm wondering what does the second line mean. I never saw this kind of initializing set. Could anyone help? Thank!
bool containsDuplicate(vector<int>& nums) {
unordered_set<int> s (nums.begin(), nums.end());
return s.size()!=nums.size();
}
unordered_set<int> s (nums.begin(), nums.end());
This initializes the set by iterating over the specified vector, starting at the beginning of the vector and iterating until it reaches the end, calling s.insert(theVal) for each int in the vector.
return s.size()!=nums.size();
Since an unordered_set, by its nature, does not allow any duplicate keys to exist in the set (i.e. trying to insert a key into the set, while that key is already a member of the set, will not modify the set at all), then we know that if the final size of the set is less than the size of the input vector, that the input vector must have had at least one duplicate value in it.
Related
I have to run a loop (the looping on t) on an unordered map in C++ and each time the loop is run, the unordered map gets updated. But what I want to do is, start with an empty map each time the loop is run. How do I initialise an empty unordered map?
while (t--){
unordered_map<int, int> freq;
//perform various insertions and deletions in the map
//print all the elements in the map
}
Unordered maps are a bit tricky in the sense that they use two things:
A chain of {key,value} pairs (STL uses a std::forward_list).
An array of positions to the chain elements (hash table).
When you insert elements to the map, the array gets filled (load factor increases) and hash collisions start to become frequent. This ends up in that array being resized, and all its elements (positions to the chain of pairs) being re-created (this is called rehashing).
That being said, your code does exactly what you are asking for: declaring a variable of type std::unordered_map<int,int> initialises it by default. When the program loops back, the map gets out of scope before the following iteration (destructor is called) and a new variable is initialised when the new iteration begins.
However, you might consider using another alternative: calling clear() instead, at the beginning of your loop, and declare your map outside the loop:
std::unordered_map<int, int> freq;
while (t--) {
freq.clear();
// do something with freq
}
If all the iterations are similar (you introduce a similar amount of pairs in freq), the first iteration will find the appropriate size of the hash table (rehashing takes place), but subsequent iterations won't see this effect as often: during clear() we erase all the chain's elements but we keep the array, which will be reused during the whole loop.
Say I have a std::unordered_map<std::string, int> that represents a word and the number of times that word appeared in a book, and I want to be able to sort it by the value.
The problem is, I want the sorting to be stable, so that in case two items have equal value I want the one who got inserted first to the map to be first.
It is simple to implement it by adding addition field that will keep the time it got inserted. Then, create a comperator that uses both time and the value. Using simple std::sort will give me O(Nlog(N)) time complexity.
In my case, space is not an issue whenever time can be improved. I want to take advantage of it and do a bucket sorting. Which should give me O(N) time complexity. But when using bucket sorting, there is no comperator, when iterating the items in the map the order is not preserved.
How can I both make it stable and still keep the O(N) time complexity via bucket sorting or something else?
I guess that if I had some kind of hash map that preserves the order of insertion while iterating it, it would solve my issue.
Any other solutions with the same time complexity are acceptable.
Note - I already saw this and that and due to the fact that they are both from 2009 and that my case is more specific I think, I opened this question.
Here is a possible solution I came up with using an std::unordered_map and tracking the order of inserting using a std::vector.
Create a hash map with the string as key and count as value.
In addition, create a vector with iterators to that map type.
When counting elements, if the object is not yet in the map, add to both map and vector. Else, just increment the counter. The vector will preserve the order the elements got inserted to the map, and the insertion / update will still be in O(1) time complexity.
Apply bucket sort by iterating over the vector (instead of the map), this ensures the order is preserved and we'll get a stable sort. O(N)
Extract from the buckets to make a sorted array. O(N)
Implementation:
unordered_map<std::string, int> map;
std::vector<std::unordered_map<std::string,int>::iterator> order;
// Lets assume this is my string stream
std::vector<std::string> words = {"a","b","a" ... };
// Insert elements to map and the corresponding iterator to order
for (auto& word : words){
auto it = map.emplace(word,1);
if (!it.second){
it.first->second++;
}
else {
order.push_back(it.first);
}
max_count = std::max(max_count,it.first->second);
}
// Bucket Sorting
/* We are iterating over the vector and not the map
this ensures we are iterating by the order they got inserted */
std::vector<std::vector<std::string>> buckets(max_count);
for (auto o : order){
int count = o->second;
buckets[count-1].push_back(o->first);
}
std::vector<std::string> res;
for (auto it = buckets.rbegin(); it != buckets.rend(); ++it)
for (auto& str : *it)
res.push_back(str);
I need to insert an object to existing vector of objects. I know that i need to use iterator to do it but i dont know how it exactly works.
I have alphabetically sorted vector and i need to insert new object by its name in exact index that i got after some search . So i have this.
vector<Person>people;
int index =54;
Person temp;
people.push_back(temp);//insert at end of vector
people.insert(index, temp);//doesnt work for int
Can anyone help me how to use iterator properly to insert my object to 54th index of vector and move all following object by one index ?
Thank you for any help.
The straight forward answer is you need an iterator. The iterator for std::vector supports random access, which means you can add or subtract an integer value to or from an iterator.
people.insert(people.begin() + index, temp);
The better answer is don't use an index, use an iterator. What is your loop? You should be able to refactor the loop to use an iterator instead of an index.
I have alphabetically sorted vector and i need to insert new object by its name in exact index that i got after some search.
If the vector is sorted alphabetically, then the proper way of inserting an item in the correct position while maintaining the sort order is using the upper_bound function:
people.insert(upper_bound(people.begin(), people.end(), temp), temp);
The function searches the sorted range, and returns the position of the first element that is greater than temp.
Here is a demo on ideone.
Solution:
vector<Person>::iterator iter = people.begin() + index;
people.insert(iter, temp);
Reference:
std::vector::insert()
RandomAccessIterator
I have a std::map called myMap in my C++ application, and I want to get an element using either myMap.find(key) or myMap[key]. However, I would also like to get the index of that element in the map.
std::map<string, int> myMap;
// Populate myMap with a bunch of items...
myElement = myMap["myKey"];
// Now I need to get the index of myElement in myMap
Is there a clean way to do that?
Thank you.
I came here seeking for this answer but i found this
distance function takes 2 iterators and returns an index
cout << distance(mymap.begin(),mymap.find("198765432"));
hope this helps :D
A std::map doesn't really have an index, instead it has an iterator for a key / value pair. This is similar to an index in that it represents a position of sorts in the collection but it is not numeric. To get the iterator of a key / value pair use the find method
std::map<string, int>::iterator it = myMap.find("myKey");
Most of the time when you are working with indices and maps, it usually means that your map is fixed after some insertions. If this assumption holds true for your use case, you can use my answer.
If your map is already fixed (you wouldn't add/delete any key afterward), and you want to find an index of a key, just create a new map that maps from key to index.
std::map<string, int> key2index; // you can use unordered_map for it to be faster
int i = 0;
for (pair<K, V> entry : yourMap) {
key2index[entry.first] = i++;
}
From this key2index map you can query the key as often as you can. Just call key2index['YourKey'] to get your index.
The benefit of this method over distance function is access time complexity. It's O(1) and very fast if you do query often.
Extra Section
If you want to do the opposite, you want to access key from index then do the following.
Create an array or vector that stores keys of your entire map. Then you can access the key by specifying the index.
vector<int> keys;
for (pair<K,V> entry : yourMap) {
keys.push_back(entry.first);
}
To access an index i of your map, use yourMap[keys[i]]. This is also O(1) and significantly faster because it's using only an array/vector, not a map.
Well - map is keeping the key and the data as a pair
so you can extract key by dereferecing the map's iterator into pair or directly into pair's first element.
std::map<string, int> myMap;
std::map<string, int>::iterator it;
for(it=myMap.begin();it!=myMap.end();it++)
{
std::cout<<it->first<<std::endl;
}
Use
int k = distance(mymap.begin(), mymap.find(mykey));
It will give you the index of the key element.
There is no such thing as an index in a map. Maps are not stored (not necessarly, at least; and indeed they are not in most implementations) as a sequence of "pairs".
Regardless of the implementation, however, std::map does not model a container having an index.
Depending on what you are asking this question for, the "index" can be an iterator (as suggested by others) or the key itself.
However, it sounds strange you asked this question. If you could give us a bit more details we would probably be able to point you to a better solution to your problem.
The semantic of a map does not include indexes. To understand that, you can note that Maps are typically implemented as trees. Therefore, elements in it do not have an index (try to define an index in a natural way for a tree).
Map is a key-value data structure which internally data in a tree structure. There are O(n) solution stated above.
" distance(mymap.begin(),mymap.find("198765432")) " will not bring you the correct answer.
For your requirement, you have to build your own segment tree type data structure for O log(n) competitive operations.
A use case: if you want to know how many items are smaller or equal as you progress on a vector. Constraint : i < = j, how many v[i]'s are smaller or equal to v[j]). let's insert it into a map or set.
vector<int> v={1, 4, 2, 3};
set<int> s;
s = {1}; // 1's position is 1 (one based)
s = {1,4}; //4's positon is 2
s = {1, 2, 4} ;//2's position is 2
s = {1 , 2, 3, 4}; //3's positon is 3
it seems std:distance would need a O(n) time.
I could achieve same affect using set.lower_bound() and counting backward till set.begin(). Does anyone have a better solution than requiring O(n) , perhaps using additional data structures?
OK, on a second thought here is a solution to store index (1 based) for this specific problem. However it may not solve the problem for get the correct index of items in the finished map.
vector<int> arr={1 , 1 , 2, 4, 2};
multimap<int, int> track;
for(auto a:arr)
{
auto it = track.insert(make_pair(a, 1)); //first item is 1
if(it!=track.begin())
{
--it;
int prev=it->second;
it++;
it->second+=prev;
}
cout<<a<<','<<it->second-1<<endl;
}
I have a map of key-value pairs. A priori I don't know it's size, i.e. how many and which keys I will have. Now, within a look, the keys "appear" and I need to increase the value for the corresponding key, each time it appears.
Example:
std::map<int, unsigned int> myMap;
std::vector<int> vectorOfValues; // 123,456,123,789,123,456
for(unsigned int i=0; i<vectorOfValues.size(); ++i) {
myMap[vectorOfValues.at(i)] += 1;
}
So now myMap should contain <123,3>, <456,2>, <789,1>.
Question:
Is this the correct? I'm afraid the using the map without initialising the values isn't a good idea. But I'd like avoid to search for the entry each time I want to increase it.
Cheers!
IMO, it's fine, the unsigned int will be default constructed (i.e. zero initialized), one comment is that the at() call is superfluous - use the operator[] (as you already constrain by size()).
This is correct; previously non-existing values will be initialized to zero.