zoukankan      html  css  js  c++  java
  • [LeetCode] 30. 串联所有单词的子串

    题目链接: https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/

    题目描述:

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

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

    示例:

    示例 1:

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

    示例 2:

    输入:
      s = "wordgoodgoodgoodbestword",
      words = ["word","good","best","word"]
    输出:[]
    

    思路:

    一开始,我的想法是,每次从s截取一定长度(固定的)的字符串,看这段字符串出现单词个数是否和要匹配的单词个数相等!如下代码:

    class Solution:
        def findSubstring(self, s: str, words: List[str]) -> List[int]:
            from collections import Counter
            if not s or not words:return []
            all_len = sum(map(len, words))
            n = len(s)
            words = Counter(words)
            res = []
            for i in range(0, n - all_len + 1):
                tmp = s[i:i+all_len]
                flag = True
                for key in words:
                    if words[key] != tmp.count(key):
                        flag = False
                        break
                if flag:res.append(i)
            return res
    

    但是比如: s = "ababaab" ,words = ["ab","ba","ba"]就会报错!

    错误原因,因为计算时候我们会从字符串中间计算,也就是说会出现单词截断的问题.

    所以我想另一种方法,

    思路一:

    因为单词长度固定的,我们可以计算出截取字符串的单词个数是否和words里相等,所以我们可以借用哈希表.

    一个是哈希表是words,一个哈希表是截取的字符串,

    比较两个哈希是否相等!

    因为遍历和比较都是线性的,所以时间复杂度 :(O(n^2))


    上面思路每次都要反复遍历s;

    下面介绍滑动窗口.

    思路二:

    滑动窗口!

    我们一直在s维护着所有单词长度总和的一个长度队列!

    关于滑动窗口,可以看看这篇文章.

    时间复杂度:(O(n))

    还可以再优化,只是加一些判断,详细看代码吧!


    关注我的知乎专栏,了解更多的解题技巧,大家一起进步,加油!

    代码:

    思路一:

    python

    class Solution:
        def findSubstring(self, s: str, words: List[str]) -> List[int]:
            from collections import Counter
            if not s or not words:return []
            one_word = len(words[0])
            all_len = len(words) * one_word
            n = len(s)
            words = Counter(words)
            res = []
            for i in range(0, n - all_len + 1):
                tmp = s[i:i+all_len]
                c_tmp = []
                for j in range(0, all_len, one_word):
                    c_tmp.append(tmp[j:j+one_word])
                if Counter(c_tmp) == words:
                    res.append(i)
            return res
    

    java

    class Solution {
        public List<Integer> findSubstring(String s, String[] words) {
            List<Integer> res = new ArrayList<>();
            if (s == null || s.length() == 0 || words == null || words.length == 0) return res;
            HashMap<String, Integer> map = new HashMap<>();
            int one_word = words[0].length();
            int word_num = words.length;
            int all_len = one_word * word_num;
            for (String word : words) {
                map.put(word, map.getOrDefault(word, 0) + 1);
            }
            for (int i = 0; i < s.length() - all_len + 1; i++) {
                String tmp = s.substring(i, i + all_len);
                HashMap<String, Integer> tmp_map = new HashMap<>();
                for (int j = 0; j < all_len; j += one_word) {
                    String w = tmp.substring(j, j + one_word);
                    tmp_map.put(w, tmp_map.getOrDefault(w, 0) + 1);
                }
                if (map.equals(tmp_map)) res.add(i);
            }
            return res;
        }
    }
    

    思路二:

    python

    class Solution:
        def findSubstring(self, s: str, words: List[str]) -> List[int]:
            from collections import Counter
            if not s or not words:return []
            one_word = len(words[0])
            word_num = len(words)
            n = len(s)
            words = Counter(words)
            res = []
            for i in range(0, one_word):
                cur_cnt = 0
                left = i
                right = i
                cur_Counter = Counter()
                while right + one_word <= n:
                    w = s[right:right + one_word]
                    right += one_word
                    cur_Counter[w] += 1
                    cur_cnt += 1
                    while cur_Counter[w] > words[w]:
                        left_w = s[left:left+one_word]
                        left += one_word
                        cur_Counter[left_w] -= 1
                        cur_cnt -= 1
                    if cur_cnt == word_num :
                        res.append(left)
            return res
    

    java

    class Solution {
        public List<Integer> findSubstring(String s, String[] words) {
            List<Integer> res = new ArrayList<>();
            if (s == null || s.length() == 0 || words == null || words.length == 0) return res;
            HashMap<String, Integer> map = new HashMap<>();
            int one_word = words[0].length();
            int word_num = words.length;
            int all_len = one_word * word_num;
            for (String word : words) {
                map.put(word, map.getOrDefault(word, 0) + 1);
            }
            for (int i = 0; i < one_word; i++) {
                int left = i, right = i, count = 0;
                HashMap<String, Integer> tmp_map = new HashMap<>();
                while (right + one_word <= s.length()) {
                    String w = s.substring(right, right + one_word);
                    tmp_map.put(w, tmp_map.getOrDefault(w, 0) + 1);
                    right += one_word;
                    count++;
                    while (tmp_map.getOrDefault(w, 0) > map.getOrDefault(w, 0)) {
                        String t_w = s.substring(left, left + one_word);
                        count--;
                        tmp_map.put(t_w, tmp_map.getOrDefault(t_w, 0) - 1);
                        left += one_word;
                    }
                    if (count == word_num) res.add(left);
    
                }
            }
    
            return res;
        }
    }
    

    再优化:

    python

    class Solution:
        def findSubstring(self, s: str, words: List[str]) -> List[int]:
            from collections import Counter
            if not s or not words:return []
            one_word = len(words[0])
            word_num = len(words)
            n = len(s)
            if n < one_word:return []
            words = Counter(words)
            res = []
            for i in range(0, one_word):
                cur_cnt = 0
                left = i
                right = i
                cur_Counter = Counter()
                while right + one_word <= n:
                    w = s[right:right + one_word]
                    right += one_word
                    if w not in words:
                        left = right
                        cur_Counter.clear()
                        cur_cnt = 0
                    else:
                        cur_Counter[w] += 1
                        cur_cnt += 1
                        while cur_Counter[w] > words[w]:
                            left_w = s[left:left+one_word]
                            left += one_word
                            cur_Counter[left_w] -= 1
                            cur_cnt -= 1
                        if cur_cnt == word_num :
                            res.append(left)
            return res
    

    java

    class Solution {
        public List<Integer> findSubstring(String s, String[] words) {
            List<Integer> res = new ArrayList<>();
            if (s == null || s.length() == 0 || words == null || words.length == 0) return res;
            HashMap<String, Integer> map = new HashMap<>();
            int one_word = words[0].length();
            int word_num = words.length;
            int all_len = one_word * word_num;
            for (String word : words) {
                map.put(word, map.getOrDefault(word, 0) + 1);
            }
            for (int i = 0; i < one_word; i++) {
                int left = i, right = i, count = 0;
                HashMap<String, Integer> tmp_map = new HashMap<>();
                while (right + one_word <= s.length()) {
                    String w = s.substring(right, right + one_word);
                    right += one_word;
                    if (!map.containsKey(w)) {
                        count = 0;
                        left = right;
                        tmp_map.clear();
                    } else {
                        tmp_map.put(w, tmp_map.getOrDefault(w, 0) + 1);
                        count++;
                        while (tmp_map.getOrDefault(w, 0) > map.getOrDefault(w, 0)) {
                            String t_w = s.substring(left, left + one_word);
                            count--;
                            tmp_map.put(t_w, tmp_map.getOrDefault(t_w, 0) - 1);
                            left += one_word;
                        }
                        if (count == word_num) res.add(left);
                    }
                }
            }
            return res;
        }
    }
    
  • 相关阅读:
    js的元素对象
    js实现在末尾添加节点
    js实现点击增加文本输入框
    js的DOM对象
    js其它
    js实现99乘法表
    js
    http的六种请求方法
    11.进制
    10.Debug
  • 原文地址:https://www.cnblogs.com/powercai/p/10805879.html
Copyright © 2011-2022 走看看