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

Example 1:

Input:
s = “barfoothefoobarman”,
words = [“foo”,”bar”]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are “barfoor” and “foobar” respectively.
The output order does not matter, returning [9,0] is fine too.
Example 2:

Input:
s = “wordgoodstudentgoodword”,
words = [“word”,”student”]
Output: []
题源:here;完整实现:here
思路:
两种方案:1 递归法;2 滑动窗法。
方案1
我们依次遍历输入数组s,对每一个位置都判断是否是是words的组合,判断部分采用递归的方式。思路和实现都很简单,但是时间复杂度高,提交后超时,代码如下:

    bool isSubstring_1(string s, vector<string>& words){
        if (words.size() == 0) return true;
        for (int i = 0; i < words.size(); i++){
            if (s[0] == words[i][0]){
                int j = 0;
                while (j < words[i].size() && j < s.size() && words[i][j] == s[j]) j++;
                if (j == words[i].size()){
                    string temp = s;
                    temp.erase(0, j);
                    vector<string> temp_words = words;
                    temp_words.erase(temp_words.begin() + i);
                    return this->isSubstring_1(temp, temp_words);
                }
            }
        }

        return false;
    }

    vector<int> findSubstring_1(string s, vector<string>& words) {
        vector<int> result;
        if (words.size() == 0 || s.size() == 0) return result;

        for (int i = 0; i < s.size(); i++){
            string temp = s;
            temp.erase(0, i);
            if (this->isSubstring_1(temp, words)) result.push_back(i);
        }

        return result;
    }

方案2
我们使用两个指针leftright来表征窗口左右边界,用curr_map来保存left和right之间的单词,用temp_word表示向窗口种新添的元素,则有如下简化流程图这里写图片描述
这个流程图的作用主要是为了展示滑动窗法的思想,具体实现还是得看代码。
在程序种,判断新添加的temp_word是否属于words需要用到map,以减少查询时间,map是真的好。
方案2得代码如下:

    vector<int> findSubstring_2(string s, vector<string>& words) {
        vector<int> result;
        if (words.size() == 0 || s.size() == 0) return result;

        map<string, int> word_map;
        int word_len = words[0].size();
        for (int i = 0; i < words.size(); i++){
            if (word_map.find(words[i]) == word_map.end()) word_map.insert(make_pair(words[i], 1));
            else word_map[words[i]] += 1;
        }

        for (int i = 0; i < word_len; i++){
            int left = i, right = i+word_len;
            map<string, int> curr_map;
            while (right <= s.size()){
                string temp_word = s.substr(right - word_len, word_len);
                if (word_map.find(temp_word) != word_map.end()){
                    if (curr_map.find(temp_word) == curr_map.end()) curr_map.insert(make_pair(temp_word, 1));
                    else curr_map[temp_word] += 1;

                    if (curr_map[temp_word] <= word_map[temp_word]){
                        if (right - left == words.size()*word_len){
                            result.push_back(left);
                            left = left+word_len, right = left + word_len;
                            curr_map.clear();
                            continue;
                        }
                        right += word_len;
                    }
                    else left = left+word_len, right = left + word_len, curr_map.clear();
                }
                else left = right, right = left + word_len, curr_map.clear();
            }
        }

        return result;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值