As already mentioned, you can do this in a one-pass algorithm. You only need to keep track of whether you have seen a character before, and what the position of its first occurence is. Here is a possible implementation:
#include <algorithm>
#include <array>
#include <climits>
#include <cstdint>
#include <string>
std::size_t FirstOccurrenceOfUniqueChar(const std::string& s) {
std::array<bool, 1 << CHAR_BIT> seen{};
std::array<std::size_t, 1 << CHAR_BIT> pos;
pos.fill(s.npos);
for (std::size_t i = 0; i < s.size(); ++i) {
auto ch = static_cast<unsigned char>(s[i]);
pos[ch] = seen[ch] ? s.npos : i;
seen[ch] = true;
}
return *std::min_element(pos.begin(), pos.end());
}
Note that in the above code, only two std::array
s are used; since there are only a fixed number of characters, you can use a fixed-size container instead of the slower std::list
and std::unordered_map
.
Also note that this version returns a std::size_t
; this is necessary to support strings longer than an int
can represent. Also, std::string::npos
is used to indicate that there is no unique character. It's the largest possible value of std::size_t
, which is very convenient here.
Also, if you cast std::string::npos
to an int
, it will become -1
.