Substring with Concatenation of All Words字符串中找到包含所有單詞的子串

Substring with Concatenation of All Words

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.

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

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

這道題相對來說還是比較簡單的, 題意中規定了所有的單詞長度是一樣的.

所以大致考察的就是字符串的查找. 自己做過後網上發現解決的代碼更加清晰, 值得學習, 所以記錄在這裏:


#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;

class Solution {
public:
/*    vector<int> findSubstring(string s, vector<string>& words) {
        int nWords = words.size();
        int wordsLen = words[0].size();
        vector<int> ret;
        map<string, int> Map;
        
        for(int i=0; i<nWords; i++){
		map<string, int>::iterator it = Map.find(words[i]);
		if(it == Map.end())
			Map[words[i]] = 1;
		else
			Map[words[i]] = Map[words[i]] + 1;
	}
        
        int strLen = s.size();
        map<string, int>::iterator it;
        int i = 0;
	//cout << "strLen = " << strLen << endl;
        while(i<strLen) {
            map<string, int> Store;
	    int curSize = 0;
            if((strLen - i) < (nWords * wordsLen))
                return ret;

            string word(s.begin()+i, s.begin()+i+wordsLen);
            it = Map.find(word);
	    //cout << "i = " << i << endl;
            if(it == Map.end()){
		i++;
                continue;
	    }
            else{
                Store[word] = 1;
		curSize ++;
		if(curSize == nWords){
                    ret.push_back(i);
                    i ++;
                    continue;
                }
                for(int j = i+wordsLen; ; j += wordsLen){
                    string word(s.begin()+j, s.begin()+j+wordsLen);
		    //cout << "j is " << j << " and word is " << word << " and curSize is " << curSize << endl;
                    it = Map.find(word);
                    if(it == Map.end()){
                        i ++;
                        break;
                    }
                    else{
                        map<string, int>::iterator itt;
                        itt = Store.find(word);
                        if(itt == Store.end()){
			    curSize ++;
                            Store[word] = 1;
			    //cout << "--------now size is " << curSize << endl;
                            if(curSize == nWords){
                                ret.push_back(i);
                                i ++;
                                break;
                            }
                        }
                        else{
                            if(Store[word] == Map[word]){
			    	i ++;
                            	break;
			    }
			    else{
			        curSize ++;
			    	Store[word] = Store[word] + 1;
                            	if(curSize == nWords){
                                    ret.push_back(i);
                                    i ++;
                                    break;
                                }
			    }
                        }
                    }
                }
            }
	    //cout << "i is changed to " << i << endl;
        }
        
        return ret;
    }
*/

	//almost a same solution, but a better implement
	vector<int> findSubstring(string s, vector<string>& words) {
		int strLen = s.size();
		int nWords = words.size();
		int wordLen = words[0].size();

		vector<int> ret;
		map<string, int> Map;
		//將單詞放到map中, key爲string, value爲該單詞出現的次數
        	for(int i=0; i<nWords; i++){
			if(Map.find(words[i]) == Map.end())
				Map[words[i]] = 1;
			else
				Map[words[i]]++;
		}

		//既然題目說明了, 每個單詞的長度是相同的. 那麼我們以後就是按照單詞的長度來判斷一個單詞是否爲words中存在的
		//比如單詞長度爲4, 那麼就是每4個字母組成一個單詞進行比較
		//要把所有長度爲4的單詞都訪問一遍的方法是用兩層for循環, 像這樣:
		//[a ,b, c, d, e, f, g, h] 的話所有長度爲4的單詞有: (abcd, bcde, cdef, defg, efgh)
		//for(int i=0; i<4; i++)
		//	for(int j=i; j<=len-4; j+=l)
		//		string.substr(j, 4);
		for(int i=0; i<wordLen; i++){
			map<string, int> Store;
			int curSize = 0;
			//這個變量用於二層循環的start. 因爲如果abcd不滿足, 還是要繼續查找下去. 接下里就是從efgh開始查找
			int windLeft = i;
			cout << "i = " << i << endl;
			for(int j=i; j<=strLen-wordLen; j+=wordLen){
				string word = s.substr(j, wordLen);
				if(Map.find(word) == Map.end()){
					Store.clear();
					curSize = 0;
					windLeft = j+wordLen;
					continue;
				}

				//該單詞符合條件, 那麼繼續看是否滿足出現的次數要求. 比如給定的words中出現多個abcd
				curSize ++;
				if(Store.find(word) == Store.end())
					Store[word] = 1;
				else
					Store[word]++;

 				//出現次數過多了, 那麼比如我只要兩個, 居然出現了三個. 那麼下次就從第一個這個單詞出現的後面開始繼續查找
				string tmp;
				if(Store[word] > Map[word]){
					do{
						tmp = s.substr(windLeft, wordLen);
						Store[tmp] --;
						curSize --;
						windLeft += wordLen;
					}while(tmp != word);
				}

				//出現了滿足題目要求的了,將開始下標(即windLeft)放到結果vector中去
				if(curSize == nWords){
					ret.push_back(windLeft);
					//可能給定的words是{"abcd", "efgh"}
					//給定的s是 "abcdefghabcd", 這裏面存在兩對呢.
					//於是在得到第一個結果後, 把最左邊的元素"abcd"刪掉, 把efgh作爲開頭繼續尋找
					string tmp = s.substr(windLeft, wordLen);
					Store[tmp]--;
					curSize--;
					windLeft += wordLen;
				}
			}
		}

		return ret;
	}
};

int main()
{
	Solution x;
	string s("lingmindraboofooowingdingbarrwingmonkeypoundcake");
	vector<int> ret;
	vector<string> v;
	v.push_back("fooo");
	v.push_back("barr");
	v.push_back("wing");
	v.push_back("ding");
	v.push_back("wing");
	ret = x.findSubstring(s, v);
	cout << ret.size() <<endl;
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章