Leetcode——30.与所有单词相关联的字串【##】



@author: ZZQ

@software: PyCharm

@file: leetcode30_findSubstring.py

@time: 2018/11/20 19:14

题目要求:

给定一个字符串 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"]
 输出: []
这个案例有点迷,题目明明说words里面的单词都是等长的。。。

思路:

方法一:

拿到题目,我们需要做的是找出匹配words中所有单词的子串的下标。
首先,我们用一个hashmap_m1去记录words中出现的单词及其个数,
然后,开始遍历,依次比较从i,i+words_len的所有子串是否匹配words里单词的某种自由组合,当i的值>s_len-words_num*word_len时,剩余的子串也不够匹配的,i至此停止遍历。
在内层循环中, 我们设置一个新的hashmap_m2来存储当前子串中匹配到的单词及其个数。
          当该单词不在hashmap_m1中时,匹配失败,break
          当hashmap_m2中该单词的个数超出hashmap_m1中该单词的个数时,匹配失败,break
          当j刚好等于words_nums时,说明匹配成功,则将当前的下标i存入ans中。
AC代码如下:
class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        if s == "" or words == []:
            return []
        ans = []
        hash_m1 = {}
        words_num = len(words)
        word_len = len(words[0])
        s_len = len(s)
        if s_len < words_num:
            return []
        for word in words:  # 记录每个单词出现的次数
            if word not in hash_m1:
                hash_m1[word] = 1
            else:
                hash_m1[word] += 1
        for i in range(s_len-words_num*word_len+1):
            hash_m2 = {}
            j = 0
            while j < words_num:  # 需要匹配的单词的个数
                current_word = s[i+j*word_len:i+(j+1)*word_len]
                if current_word in hash_m1:
                    if current_word not in hash_m2:
                        hash_m2[current_word] = 1
                    else:
                        hash_m2[current_word] += 1
                    if hash_m2[current_word] > hash_m1[current_word]:
                        break
                else:
                    break
                j += 1
            if j == words_num:
                ans.append(i)
        return ans

方法二:

但是这种方法比较慢,看了网上大神的解法,于是有了方法二。
这是一个可以达到O(n)的方法。i不是一个字母一个字母的遍历,而是一个单词一个单词的遍历。
比如说:
  当前words中所有单词的长度都为3,则遍历的方法是先遍历0,3,6,9,12...,然后扫描1,4,7,10,13,...,再扫描2,5,8,11,14,...,也就是说外层循环i只需要遍历【0,3】即可。
  我们先设置一个hashmap_m1用于保存words中每个单词出现的个数,然后,对于某个i,设置left来记录某个字串的起始下标,设置count来记录匹配成功的单词个数,设置临时变量k遍历【i,len(s)】之后的所有字母,但此时不依次遍历,而是一个单词一个单词的遍历。设置临时字典hashmap_m2来存储在当下循环中匹配到的单词及其个数。
  内层循环中,判断当前的current_word是否在hashmap_m1:
  如果在,则将hashmap_m2中该单词的个数加1,同时判断hashmap_m2中current_word的个数是否超过hashmap_m1中current_word,如果没有超,则将count加1,否则,说明此时匹配到的单词个数不符合words里的单词个数,则从hashmap_m2中去掉最前面的一个单词,然后将count减1,同时将left后移word_len个单位,直至hashmap_m2【current_word】<=hashmap_m1【current_word】。 当count的值与words中单词的个数相同时,说明匹配成功,则将该起始下标left添加到ans中,然后将left后移word_len个单位,同时将count减1。
   如果current_word不在hashmap_m1则,则说明之前的所有匹配都失败,此时应该将hashmap_m2清零,同时将left后移到j+word_len的位置(重新开始匹配)。

AC代码如下:

class Solution(object):
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        if s == "" or words == []:
            return []
        ans = []
        hash_m1 = {}
        words_num = len(words)
        s_len = len(s)
        if s_len < words_num:
            return []
        for word in words:
            if word not in hash_m1:
                hash_m1[word] = 1
            else:
                hash_m1[word] += 1
        word_len = len(words[0])
        for i in range(word_len):
            left = i    # 记录起始下标
            count = 0     #记录匹配成功的个数
            hash_m2 = {}   # 记录匹配到的单词及其个数
            j = i   # 从i开始往后遍历
            while j <= s_len - word_len:   # 循环停止条件是遍历到最后一个单词所在位置
                current_word = copy.deepcopy(s[j:j + word_len])    # 当前单词
                if current_word in hash_m1:    # 如果单词在hash_m1 中
                    if current_word not in hash_m2:  # 将其加入hash_m2
                        hash_m2[current_word] = 1
                    else:
                        hash_m2[current_word] += 1

                    if hash_m2[current_word] <= hash_m1[current_word]:    # 如果该单词在hash_m2中的个数小于等于其在hash_m1中的个数,将count+1
                        count += 1
                    else:  # 否则将hash_m2中最先匹配到的单词剔除,直至hash_m2[current_word] <= hash_m1[current_word]
                        while hash_m2[current_word] > hash_m1[current_word]:
                            temp_word = s[left:left+word_len]
                            hash_m2[temp_word] -= 1
                            if hash_m2[temp_word] < hash_m1[temp_word]:
                                count -= 1
                            left += word_len
                    if count == words_num:  # 匹配成功
                        if left not in ans:
                            ans.append(left)
                        hash_m2[s[left:left + word_len]] -= 1   # left后移一个单词的长度,hash_m2中最先匹配到的单词移除一个
                        count -= 1
                        left += word_len
                else:  # 当前单词不在hash_m1中,匹配失败,重新开始匹配,count清零,left设置到当前位置
                    hash_m2.clear()
                    count = 0
                    left = j + word_len

                j += word_len
        return ans

原文地址:https://www.cnblogs.com/zzq-123456/p/10000437.html

时间: 2024-11-25 08:17:43

Leetcode——30.与所有单词相关联的字串【##】的相关文章

[leetcode] 30. 与所有单词相关联的字串(cn第653位做出此题的人~)

30. 与所有单词相关联的字串 这个题做了大概两个小时左右把...严重怀疑leetcode的judge机器有问题.同样的代码交出来不同的运行时长,能不能A题还得看运气? 大致思路是,给words生成一关于s的字典,用来记录每个word在s中出现的所有位置,注意可能会出现相同的word.然后递归枚举words的排列情况,一一校验是否符合条件(即连在一起).用到了递归+记忆化搜索+kmp+几个剪枝 一直最后几个测试用例上TLE,囧啊,甚至一度怀疑是不是还有更优的做法. 然后开始考虑剪枝: 记忆化搜索

30. 与所有单词相关联的字串、java实现

题目描述: 给定一个字符串 s 和一些长度相同的单词 words.在 s 中找出可以恰好串联 words 中所有单词的子串的起始位置. 注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序. 示例 1: 输入: s = "barfoothefoobarman", words = ["foo","bar"] 输出: [0,9] 解释: 从索引 0 和 9 开始的子串分别是 "barfo

[Swift]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

leetcode——30. 串联所有单词的子串

class Solution: def findSubstring(self, s: str, words): if s=='' or words==[]:return [] n=len(words) m=len(words[0]) r=[] i=0 while i<len(s)-m*n+1: for j in words: p=s[i:i+m*n] t=list(p[m*i:m*(i+1)] for i in range(n)) if t.count(j)!=words.count(j): i

[leetcode]3无重复字符的最长字串

本题思路较清楚,通过一个数组记录各个位置所能够引导的最长字符串的长度即可. 稍微有一点难度在于如何向前寻找时判断已经出现了重复字符串,我采用的思路为只有当前项的长度等于当前长度时,认为尚未出现重复字符串,并更新前项长度++. 1 int max=0; 2 int st[100000]={0};//表示以它为开头的最长不重复字串长度 3 int i=0; 4 char p; 5 while(s[i]!='\0') 6 { 7 p=s[i]; 8 st[i]=1; 9 max=st[i]; 10 f

创建Hive/hbase相关联的表异常

hive> CREATE TABLE hperson(id string, name string,email string) STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":id,cf1:name,cf2:email") TBLPROPERTIES ("hbase.table.

表单标签&lt;label&gt;----------------------用for属性 和radio 的id相关联 可以让鼠标点字就相当于点击radio

定义和用法 <label> 标签为 input 元素定义标注(标记). label 元素不会向用户呈现任何特殊效果.不过,它为鼠标用户改进了可用性.如果您在 label 元素内点击文本,就会触发此控件.就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上. <label> 标签的 for 属性应当与相关元素的 id 属性相同. <form><label for="male">Male</label><

Entity Framework 6 Recipes 2nd Edition(12-5)译 -&gt; 自动删除相关联实体

12-5. 自动删除相关联实体 问题 当一个实体被删除时,你想自动删除它相关联的实体 解决方案 假设你有一个表结构由一个course (科目), course 的classes (课程),以及enrollment (登记学生选课),如 Figure 12-5所示:. Figure 12-5. The Course, Class, and Enrollment tables in our database 由上述表生成一个模型,如下图Figure 12-6所示:. Figure 12-6. A m

已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭。

多次用到SqlDataReader 要先关闭,再执行ExecuteNonQuery操作 每用一次需要先进行关闭,再执行新的一次,要不然就会报错“已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭.” 那么如何解决呢? 方法有两种1,在ConnectionString加上MultipleActiveResultSets=true,但只适用于SQL 2005以后的版本2.选择读出SqlDataReader 中的数据给List或者arraylist之类的,之后进行关闭返回