变相的字符串匹配

给定一个字符串,然后再给定一组同样长度的单词列表,要求在字符串中查找满足下面条件的起始位置:

1)从这个位置開始包括单词列表中全部的单词。且每一个单词仅且必须出现一次。

2)在出现的过程中不能出现其它的干扰单词。

3)出现的位置可能有多个。

4)单词的出现顺序不做要求。

以下是一个样例:

S:"barfoothefoobarman"

L:"foo","bar"

位置0是出现位置,。两个单词均出现仅出现一次,且没有干扰。

相同位置9也是满足的。

原题要求例如以下:

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

思路例如以下:

首先初始化一个map容器,内含单词列表中出现的单词,以及单词出现的次数。

把容器当做比較的模板。

string int
bar 1
foo 1
其次,指针i从0指向可能的最后位置。上例中是12,由于单词列表中总长度是6,在S中留下足够6的长度位置就可以。

由于中间干扰词的长度是不确定的。因此i仅仅能是逐一的后移来寻找匹配的位置。

我们首先获得字符串中的第一个单词,bar。查看在上述的容器中是否有这个单词,假设没有,直接指针后移匹配下一个位置開始的单词。查找后是有的,因此我们把这个单词增加到一个新的map容器中,这个容器存储的是从当前指针位置開始满足单词列表的单词。这这个样例中就是bar在初始化的容器中存在,那么就把他增加新容器中。同一时候。统计次数也要递增,接下来查看这个单词在新容器中出现的次数是否小于等于初始化容器中的次数。假设大于说明这是错误的。也须要指针后移。

最后,当我们后移单词列表中指定个数的单词或者由于不匹配而终止从指针位置i開始的查找时。在循环外面我们要推断一下单词匹配的个数是否和单词列表中的次数一样,假设一样说明从当前指针的位置是匹配的。那么就把这个指针位置保存起来。如此循环往复就可以。代码例如以下。顺着走一遍就明确了。

class Solution {
public:
    vector<int> findSubstring(string S, vector<string> &L) {
        map<string,int> words,cur;
        int wordNum = L.size();
        int wordLen = L[0].size();
        vector<int> res;
        for(int k = 0;k<wordNum;k++)
          words[L[k]]++;//初始化容器
        for(int i = 0;i<=static_cast<int>(S.length()-wordLen*wordNum);i++)
        {
          cur.clear();//每次使用之前要清空,这个容器是不断变化的
          int j;
          for(j = 0;j<wordNum;j++)
          {
            string word = S.substr(i+j*wordLen,wordLen);//获取这个单词
            if(words.find(word) == words.end())//这个单词不是单词列表中的
              break;
            cur[word]++;
            if(words[word]<cur[word])//出现的次数多了
              break;

          }
          if(j == wordNum)//这时候是匹配的
            res.push_back(i);
        }
        return res;
    }
};



posted on 2017-06-10 12:41  lxjshuju  阅读(111)  评论(0编辑  收藏  举报