Substring with Concatenation of All Words 找到连接所有单词的子串(加解决找出xx子串的通用模板)

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

在这里,我会对这道题目进行分析,并给出处理这类问题的通用模板。

根据题目的意思,我们要找到子串开始的下标,这个子串满足它是words中,所有单词的连接。(单词出现的顺序是无关的)

一个很自然而然的想法是这样的:每次我从一个begin index开始,向后看,如果当前的单词在words中出现且没有被标记,那么我就可以继续往后找,标记了所有的words后,当前的begin index就是我需要的了。如果中途发现单词不合法,我就是继续从下一个begin index开始找。

以题目中的例子为例,一开始,begin index = 0, substring(0, 0 + 3) 为bar,在words中出现了,且被没有被标记,继续往下找,foo,foo也没有被标记,

此时,bar, foo都找到了, begin index = 0就是我想要的结果。

之后,begin index = 1,substring(0 , 0 + 3) 为 arf, 没在words中出现,继续下一个begin index...

在这道题目中:要特别注意的是:words中单词可能会重复,会出现[ "foo", "bar", "foo"]这样的。

代码的运行时间:

Substring with Concatenation of All Words 找到连接所有单词的子串(加解决找出xx子串的通用模板)_第1张图片

代码:

public class SubstringwithConcatenationofAllWords {
    private void setCounterOrigin(int[] count, int[] originCount) {
        for (int i = 0; i < count.length; i++) {
            count[i] = originCount[i];
        }
    }

    public List findSubstring(String s, String[] words) {
        //prepare counter and indexMap
        List startList = new ArrayList<>();
        Map countMap = new HashMap<>();
        Map indexMap = new HashMap<>();
        for (String str : words) {
            int num = 1;
            if (countMap.containsKey(str)) {
                num += countMap.get(str);
            }
            countMap.put(str, num);
        }
        int[] count = new int[countMap.keySet().size()];
        int[] originCount = new int[count.length];
        int i = 0, start = 0, len = words[0].length();
        for (String str : countMap.keySet()) {
            indexMap.put(str, i);
            originCount[i] = countMap.get(str);
            i++;
        }
        setCounterOrigin(count, originCount);
        i = 0;
        int countNum = words.length;// check if words are all found
        //begin exploring
        while (i < s.length() - len + 1) {
            String str = s.substring(i, i + len);
            if (countMap.containsKey(str)) {
                int index = indexMap.get(str);
                if (count[index] > 0) { // this if a valid cases
                    count[index]--;
                    countNum--;
                    i = i + len;
                } else { // not valid, current start can not form a concatenation, explore from a new start
                    start++;
                    i = start;
                    countNum = words.length;
                    setCounterOrigin(count, originCount);
                }
            } else { // not valid, explore from a new start
                start++;
                i = start;
                countNum = words.length;
                setCounterOrigin(count, originCount);
            }
            // check if find all the words
            while (countNum == 0) {
                startList.add(start); // find one, explore from a new start
                start++;
                i = start;
                countNum = words.length;
                setCounterOrigin(count, originCount);
            }
        }
        return startList;
    }
}

一个通用的模板参考自:https://discuss.leetcode.com/topic/30941/here-is-a-10-line-template-that-can-solve-most-substring-problems

这个模板利用hashmap和双指针(begin指针标记开始substring的开始, end 指针标记substring的结束),适合来解决所有找出符合某种要求的substring的问题。

int findSubstring(string s){
        vector map(128,0);
        int counter; // check whether the substring is valid
        int begin=0, end=0; //two pointers, one point to tail and one  head
        int d; //the length of substring

        for() { /* initialize the hash map here */ }

        while(end

你可能感兴趣的:(leetcode)