【Substring with Concatenation of All Words】cpp

题目:

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).

代码:

复制代码
class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
            vector<int> ret;
            if ( words.empty() || s.empty() ) return ret;
            const int len_w = words[0].size();  // length of substring in words
            const int end = words.size()*len_w; // total length of words
            if ( end>s.size() ) return ret;     // s size not enough
            map<string, int> ori;
            for ( int i=0; i<words.size(); ++i ) 
            {
                if ( ori.find(words[i])==ori.end() ){
                    ori[words[i]] = 1;
                }
                else{
                    ori[words[i]]++;
                }
            }
            map<string, int> found;
            int match_num = 0;
            int begin = 0;
            int i = 0;
            while ( i<s.size() )
            {
                //cout << "i:" << i << endl;
                //cout << "m:" << match_num << endl;
                //cout << "begin:" << begin << endl;
                // match one substring in words
                if ( ori.find(s.substr(i,len_w))!=ori.end() )
                {
                    found[s.substr(i,len_w)]++;
                    // substring occur more than times in words 
                    if ( found[s.substr(i,len_w)]>ori[s.substr(i,len_w)] )
                    {
                        found.clear();
                        match_num = 0;
                        begin++;
                        i=begin;
                        continue;                        
                    }
                    i = i+len_w;
                    match_num++;
                    //cout << match_num << endl;
                    // match all substrings in words and push back a starting indices
                    if ( match_num==words.size() )
                    {
                        ret.push_back(i-end);
                        found.clear();
                        begin++;
                        i = begin;
                        match_num=0;
                    }
                }
                // not match
                else
                {
                    found.clear();
                    match_num = 0;
                    begin++;
                    i=begin;
                }
            }
            return ret;
    }
};
复制代码

tips:

采用双指针技巧。

维护几个关键变量:

1. begin:可能的有效开始位置

2. match_num: 已经匹配上的words中的个数

3. ori: words中每个string,及其出现的次数

4. found: 当前已匹配的interval中,words中每个string,及其出现的次数

思路就是如果找到了匹配的某个string,i就不断向后跳;跳的过程中可能有两种情况不能跳了:

a) 下一个固定长度的子字符串不匹配了

b) 下一个固定长度的子字符串虽然匹配上了words中的一个,但是匹配的数量已经超过了ori中该string的数量

如果一旦不能跳了,就要把match_num和found归零;而且需要回溯到begin++的位置,开始新一轮的搜寻。

这里有个细节要注意:

直接用found.clear()就可以了,如果一个一个清零,会超时。

======================================

第二次过这道题,代码简洁了,一些细节回忆着也写出来了。保留一个ori用于判断的,再维护一个wordHit用于计数的;ori不能动,wordHit每次clear后默认的value=0。

复制代码
class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
            vector<int> ret;
            if ( words.empty() ) return ret;
            int len = words[0].size();
            if ( len*words.size()>s.size() ) return ret;
            map<string, int> wordHit;
            map<string ,int> ori;
            for ( int i=0; i<words.size(); ++i ) ori[words[i]]++;
            for ( int i=0; i<=s.size()-len*words.size(); ++i )
            {
                wordHit.clear();
                int j = i;
                int hitCouts = 0;
                while ( hitCouts<words.size() && j<=s.size()-len )
                {
                    // find word and not hit already
                    if ( ori.find(s.substr(j,len))==ori.end() ) break;
                    if ( wordHit[s.substr(j,len)]<ori[s.substr(j,len)] )
                    {
                        wordHit[s.substr(j,len)]++;
                        j += len;
                        hitCouts++;
                    }
                    else { break; }
                }
                // if hits all words
                if ( hitCouts==words.size() ) ret.push_back(i);
            }
            return ret;
    }
};
复制代码

 

posted on   承续缘  阅读(228)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示