Skip to main content
added 75 characters in body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152

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::arrays 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.

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::arrays 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.

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::arrays 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.

deleted 167 characters in body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152

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, 256>1 << CHAR_BIT> seen{};
    std::array<std::size_t, 256>1 << CHAR_BIT> pos;
    pos.fill(s.npos);

    for (std::size_t i = 0; i < s.size(); ++i) {
        uint8_tauto ch = s[i];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::arrays are used; since you know there are only 256 possible characters¹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.


¹) Technically, you can't rely on a char being 8 bits, and you have to check CHAR_BITS to see how large the arrays should be. But it's rare today to find a computer architecture where chars are not 8 bits.

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 <cstdint>
#include <string>

std::size_t FirstOccurrenceOfUniqueChar(const std::string& s) {
    std::array<bool, 256> seen{};
    std::array<std::size_t, 256> pos;
    pos.fill(s.npos);

    for (std::size_t i = 0; i < s.size(); ++i) {
        uint8_t ch = 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::arrays are used; since you know there are only 256 possible 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.


¹) Technically, you can't rely on a char being 8 bits, and you have to check CHAR_BITS to see how large the arrays should be. But it's rare today to find a computer architecture where chars are not 8 bits.

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::arrays 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.

added 283 characters in body
Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152

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 <cstdint>
#include <string>

std::size_t FirstOccurrenceOfUniqueChar(const std::string& s) {
    std::array<bool, 256> seen{};
    std::array<std::size_t, 256> pos;
    pos.fill(s.npos);

    for (std::size_t i = 0; i < s.size(); ++i) {
        uint8_t ch = 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::arrays are used; since you know there are only 256 possible 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.


¹) Technically, you can't rely on a char being 8 bits, and you have to check CHAR_BITS to see how large the arrays should be. But it's rare today to find a computer architecture where chars are not 8 bits.

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 <cstdint>
#include <string>

std::size_t FirstOccurrenceOfUniqueChar(const std::string& s) {
    std::array<bool, 256> seen{};
    std::array<std::size_t, 256> pos;
    pos.fill(s.npos);

    for (std::size_t i = 0; i < s.size(); ++i) {
        uint8_t ch = 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::arrays are used; since you know there are only 256 possible 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.

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 <cstdint>
#include <string>

std::size_t FirstOccurrenceOfUniqueChar(const std::string& s) {
    std::array<bool, 256> seen{};
    std::array<std::size_t, 256> pos;
    pos.fill(s.npos);

    for (std::size_t i = 0; i < s.size(); ++i) {
        uint8_t ch = 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::arrays are used; since you know there are only 256 possible 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.


¹) Technically, you can't rely on a char being 8 bits, and you have to check CHAR_BITS to see how large the arrays should be. But it's rare today to find a computer architecture where chars are not 8 bits.

Source Link
G. Sliepen
  • 61.7k
  • 3
  • 61
  • 152
Loading