简体   繁体   中英

Unordered map in c++

I am trying to implement this problem in C++ using unordered map :

Given a non-empty array of integers, every element appears twice except for one. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Example 1:

Input: [2,2,1]
Output: 1

Example 2:

Input: [4,1,2,1,2]
Output: 4

My solution:

class Solution {
 public:
  int singleNumber(vector<int>& nums) {
    std::unordered_map<int, int> umap;

    for (auto i = nums.begin(); i != nums.end(); i++) {
      umap[*i] = umap[*i] + 1;
    }

    for (auto i = umap.begin(); i != umap.end(); i++) {
      if (umap[*i] == 1) {
        return *i;
      }
    } 
  }
};

But unfortunately, it does not work. I get this error while compiling

Line 16: Char 17: fatal error: no viable overloaded operator[] for type 'std::unordered_map'
        if (umap[*i] == 1) {
            ~~~~^~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/unordered_map.h:973:7: note: candidate function not viable: no known conversion from 'std::pair' to 'const std::unordered_map, std::equal_to, std::allocator > >::key_type' (aka 'const int') for 1st argument
      operator[](const key_type& __k)
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/unordered_map.h:977:7: note: candidate function not viable: no known conversion from 'std::pair' to 'std::unordered_map, std::equal_to, std::allocator > >::key_type' (aka 'int') for 1st argument
      operator[](key_type&& __k)
      ^
1 error generated.

I cannot understand the error. Can anyone explain to me?

The relevant bit of the error is:

candidate function not viable: no known conversion from
   'std::pair' to
   'const std::unordered_map, std::equal_to, std::allocator > >::key_type'
       (aka 'const int')
for 1st argument operator[](const key_type& __k)

So what this means is then when using the subscript operator in umap[*i] == 1 the type of *i is some std::pair and the type that the operator expects is const int (look at the "aka").

That's because map iterators return an std::pair containing a reference to the key data and to the value data. You can get the value data easily just from the iterator without invoking the subscript operator:

if (i->second == 1)
  return i->first;

However, as stated in the comments you don't need any additional container to solve this puzzle. The constraint "Could you implement it without using extra memory?" is actually a hint to the solution. There is a mathematical property in a non-empty array of integers, where every element appears twice (.) except for one.


Also, I'd recommend using the variable name i for indexes and calling iterators it , but that's just personal preference.

You do not need std::unordered_map as std::unordered_set would be sufficient in this case:

std::unordered_set<int> set;
for( auto i : nums ) {
   auto p = set.insert( i );
   if( !p.second ) set.erase( p.first );
}

So logic is you try to insert a number, but if it was already there you remove it. Another benefit of this approach beside smaller memory footprint is that after loop you will have only one element in the set - one you need. So you do not need to iterate and search.

But proper solution is a trick that you should be aware about. It based of the properties of xor operation:

A xor A == 0 for any A
A xor 0 == A for any A

and because xor operation has commutative property as well:

A xor B xor A == A xor A xor B == 0 xor B == B

I think you now can get the idea of implementation without additional memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM