Leetcode: 30. Substring with Concatenation of All Words

Keywords: C++

Description

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.

Example

For example, given:
s: "barfoothefoobarman"
words: ["foo", "bar"]

You should return the indices: [0,9].
(order does not matter).

thinking

  • It hurts me to do this. When doing this, we always consider optimization and optimization. When submitting, we found that there are too many special cases. Optimize the fart. Optimize half a day or more than 800 ms.
  • Do not write your own specific ideas, paste a code out
  • Move a big man's code online. Alas.

Code

class Solution {
public:
   vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> res;

        if (s.empty() || words.empty()) return res;

        unordered_map<string, int> hashMap;
        unordered_map<string, int> copyMap;
        unordered_map<string, int> cmpMap;
        int len = words[0].size(), sumLen = 0;
        for (int i = 0; i < words.size(); ++i){
            hashMap[words[i]]++;
            cmpMap[words[i]] = 0;
            sumLen += words[i].size();
        }
        copyMap = hashMap;

        int i = 0, sum = 0;
        string tmp;
        int flag = 1, curLen = 0, start = 0;
        while (i < s.size()){
            sum = 0;
            tmp = s.substr(i, len);
            if (copyMap.find(tmp) == copyMap.end()){
                start++;
                flag++;
                curLen = 0;
                hashMap = copyMap;
                i = start;
            }
            else{
                if (cmpMap[tmp] == flag){
                    if (hashMap[tmp] == 0){
                        hashMap = copyMap;
                        start++;
                        curLen = 0;
                        ++flag;
                        i = start;
                    }
                    else{
                        hashMap[tmp]--;
                        curLen += len;
                        i += len;
                    }   
                }
                else{
                    cmpMap[tmp] = flag;
                    hashMap[tmp]--;
                    curLen += len;
                    i += len;
                }
            }

            if (curLen == sumLen){
                res.push_back(start);
                start++;
                curLen = 0;
                flag++;
                i = start;
                hashMap = copyMap;
            }
        }

        return res;
    }
   
};
  • Analysis of a Big Man's Code

    class Solution {
    public:
     vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> res;
    
        if (s.empty() || words.empty() || s.size() < words[0].size()) return res;
    
        //One is used to save the original dictionary, and the other is used to assist.
        unordered_map<string, int> hashMap;
        unordered_map<string, int> cmpMap;
        int num = words.size();
        int len = words[0].size();
        for (int i = 0; i < num; ++i){
            hashMap[words[i]]++;
        }
    
        int count = 0, start = 0;
        string tmp;
        //There is no need to traverse the past from 0 - s.size(), one by one. In fact, it is only possible to start with 0-len. This is a key point and can be pushed forward.
        for (int i = 0; i < len; ++i){
            count = 0;
            //Reset start and map
            start = i;
            cmpMap.clear();
    
            //Compare one word at a time, not one character at a time.
            for (int j = i; j <= s.size() - len; j += len){
                tmp = s.substr(j, len);
    
                //On the inside
                if (hashMap.find(tmp) != hashMap.end()){
                    cmpMap[tmp]++;   
    
                    //The current word may be in the result
                    if (cmpMap[tmp] <= hashMap[tmp]) count++;
                    else{
                       //The current word has been repeated
                       //start and subtract from the top.
                        while (cmpMap[tmp] > hashMap[tmp]){
                            string strTemp = s.substr(start, len);
                            cmpMap[strTemp]--;
                            if (cmpMap[strTemp] < hashMap[strTemp])
                                count--;
                            start += len;
                        }
                    }
    
                    //Save results
                    if (count == num){
                        res.push_back(start);
    
                        cmpMap[s.substr(start, len)]--;
                        start += len;
                        count--;
                    }
                }
                else{
                    //Not in the dictionary, start over
                    cmpMap.clear();
                    start = j + len;
                    count = 0;
                }
            }
        }
        return res;
    }
    };
  • Big man's code has learned a lot, but now there is no time for analysis.

Posted by lunas on Tue, 12 Feb 2019 13:39:18 -0800