Is there a better (more efficient) way to find if a string can be formed from chars of another string?

こ雲淡風輕ζ 提交于 2020-01-05 05:51:30

问题


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;
}

回答1:


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.



来源:https://stackoverflow.com/questions/17991135/is-there-a-better-more-efficient-way-to-find-if-a-string-can-be-formed-from-ch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!