【LeetCode难题解题思路(Java版)】30. 与所有单词相关联的字串

题目:

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

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

示例 1:

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

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

然后是输入输出:

class Solution {
   
   
    public List<Integer> findSubstring(String s, String[] words) {
   
   
        
    }
}

注意到的关键点:

1.在模式串words里所有的字符串长度是相等的。
2.若是s的长度小于所有word加在一起的长度,则不可能匹配成功。
3.因为返回值是list,所以要持续查找,而不是找到就立即return。

方案初步设计

首先,将各个单词排列组合,拼接得出字符串tmp,再去拿tmp和匹配串s去做匹配的方法肯定是不行的,因为光是组合这一步,复杂度就是Sita(n!)了,这太可怕了。
1.首先可以找到所有单词在s的开始位置的list,然后将所有的开始位置排序。
2.第二步,进行字符组的匹配,匹配方法是:
假如输入是:

  s = "barfoothefoobarman",
  words = ["foo","bar"]

那么对foo查找,搜索结果是[3,9],对bar查找,搜索结果是[0,12]。然后将list排序,得出[0,3,9,12]。而现在知道word的长度是3,那么0和3可以拼一个结果,9和12可以拼一个结果。那么结果就是[0,9]。

方案进一步研究

我在提交的时候,发现了这样的测试用例:

 s = "aaaaaaaaa",
 words = ["aaa","aaa"]

就是words里可能有重复的字符串,这时候,除了list之外,还应该设计一个HashMap<String,Integer> wordMap,其key是相应的字符串,其value是在words里有多少个重复,比如现在的结果就是wordMap={‘aaa’:2}。
在这个基础上对第一个’aaa’进行查找,结果是list=[0,1,2,3,4,5,6],然后在这里会发现,第二个是不用再找的,在写程序的时候可以用containsKey()来判定一下即可。
然后再对这个list判断,在这里会再需要另一个HashMap,其结构是HashMap<Integer,String> intMap,其key是s的字符的位置,其value值是以这个位置开始,存在着哪个word。比如{0:‘aaa’},表示在s的第0位上存在者’aaa’这个word。
这样就判断,从list的0开始,从intMap发现0存在着‘aaa’,则wordMap变成[‘aaa’:1],然后list往后走3位,list里存在3,而在intMap里发现3是’aaa’的开始,则wordMap变成[‘aaa’:0]。然后发现所有的word都用上了,则匹配成功了,然后以此类推做其他操作即可。
到此为止,方案的通用性全面得到解决。
代码如下:

class Solution {
   
   
    public List<Integer> findSubstring(String s, String[] words) {
   
   
        List<Integer> list=new ArrayList<Integer>();//保存有单词的位置
        Map<String, Integer> wordMap = new HashMap<>();// 存储 word中各个单词的个数
        Map<Integer,String> intMap = new HashMap<>();// 存储 位置上保存了什么单词
        if(words.length<=0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值