LeetCode 30与所有单词相关联的字串

给定一个字符串 s 和一些长度相同的单词 words。在 s 中找出可以恰好串联 words 中所有单词的子串的起始位置。

注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。

示例 1:

输入:
s = "barfoothefoobarman",
words = ["foo","bar"]
输出: [0,9]

解释: 从索引 0 和 9 开始的子串分别是 "barfoor" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。

示例 2:

输入:
s = "wordgoodstudentgoodword",
words = ["word","student"]
输出: []

解法

这道题有一个很关键的条件长度相同的单词,单词长度一致这个题可以退化为单词长度为1来考虑。问题变成:给定一个字符串,寻找由字母集words组成的字串。这种字符串问题就可以考虑使用一个滑窗来解决,扫描源字符串,如果新增单词是单词集words中的单词,并且该单词未在滑窗中出现滑窗增涨(滑窗right增加),否则滑窗缩小(滑窗left增加)。当滑窗满足需求时,记录滑窗左侧(left)的位置,继续扫描,直至无法在生成满足需求的滑窗为止。

代码

class Solution {

   public List<Integer> findSubstring(String s, String[] words) {
       List<Integer> result = new ArrayList<>();
       if (s == null || s.length() == 0 || words == null || words.length == 0) {
           return result;
       }
       Map<String, Integer> wordsCount = generateCount(words);
       int length = words[0].length();

       for (int i = 0; i < length; ++i) {
           Map<String, Integer> window = new HashMap<>();
           int left = i;
           int right = i;
           while (right <= s.length() - length && left <= s.length() - length * words.length) {
               String sub = s.substring(right, right + length);
               incr(window, sub);
               if (!wordsCount.containsKey(sub)) {
                   window.clear();
                   right += length;
                   left = right;
                   continue;
               }
               while (window.get(sub) > wordsCount.get(sub)) {
                   decr(window, s.substring(left, left + length));
                   left += length;
               }
               right += length;
               if (right - left == length * words.length) {
                   result.add(left);
               }
           }
       }
       return result;
   }

   private Map<String, Integer> generateCount(String[] words) {
       Map<String, Integer> wordsCount = new HashMap<>();
       for (String word : words) {
           incr(wordsCount, word);
       }
       return wordsCount;
   }

   private void incr(Map<String, Integer> map, String key) {
       if (map.containsKey(key)) {
           map.put(key, map.get(key) + 1);
       } else {
           map.put(key, 1);
       }
   }

   private void decr(Map<String, Integer> map, String key) {
       if (map.containsKey(key)) {
           Integer value = map.get(key);
           if (value <= 1) {
               map.remove(key);
           } else {
               map.put(key, value - 1);
           }
       }
   }
}
原文地址:https://www.cnblogs.com/migoo/p/9454684.html