Question

This is interesting because it's a possible interview question, so it would be good to know the most efficient algorithm for this problem. I came up with a solution (which contains elements of other people's solutions) that requires a map<char, int> to store letters from the first string as keys, and numbers of their occurrences as values. The algorithm then looks through each letter in the container string and checks if there's already an entry in the map. If so, decrement its value until it's zero and so on; until the container is finished (failure), or until the mapis empty (success).

The complexity of this algorithm is O(n), O(n) being the worst-case scenario (failure).

Do you know a better way?

Here is the code that I've written, tested and commented:

// takes a word we need to find, and the container that might the letters for it
bool stringExists(string word, string container) {

    // success is initially false
    bool success = false;       

    // key = char representing a letter; value = int = number of occurrences within a word
    map<char, int> wordMap;     

    // loop through each letter in the word
    for (unsigned i = 0; i < word.length(); i++) {

        char key = word.at(i); // save this letter as a "key" in a char

        if (wordMap.find(key) == wordMap.end())     // if letter doesn't exist in the map...
            wordMap.insert(make_pair(key, 1));      // add it to the map with initial value of 1

        else
            wordMap.at(key)++;                      // otherwise, increment its value

    }

    for (int i = 0; i < container.size() && !success; i++) {

        char key = container.at(i);

        // if found
        if (wordMap.find(key) != wordMap.end()) {

            if (wordMap.at(key) == 1) { // if this is the last occurrence of this key in map 

                wordMap.erase(key);     // remove this pair

                if (wordMap.empty())    // all the letters were found in the container!
                    success = true;     // this will stop the for loop from running

            }

            else                        // else, if there are more values of this key
                wordMap.at(key)--;      // decrement the count

        }
    }

    return success;
}
Was it helpful?

Solution

Do not use std::map. Usually it has O(log N) write, and O(log N) access. And malloc call on write.

For char you can use simple int freq[256] table (or std::vector if you are so inclined).

bool stringExists(const string& word, const string& cont) {
  int freq[CHAR_MAX-CHAR_MIN+1]={0};
  for (int c: cont) ++freq[c-CHAR_MIN];
  for (int c: word) if(--freq[c-CHAR_MIN]<0)  return false;
  return true;
}

Complexity of this code is O(N + M), where N and M are: word.size() and cont.size(). And I would guess that it is at least 100 times faster even from small sized inputs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top