LeetCode 030.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 sthat is a concatenation of each word in words exactly once and without any intervening characters.

Example 1:

Input:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are "barfoor" and "foobar" respectively.
The output order does not matter, returning [9,0] is fine too.

Example 2:

Input:
  s = "wordgoodstudentgoodword",
  words = ["word","student"]
Output: []

/*******************************************************/

一道比看起来要复杂的题目:

- 我是用最naive的方法实现的:遍历words数组,把每个word存到hashmap里去。然后遍历字符串s的时候,对每lw个字符(lw是每个word的字长)匹配一下,看hashmap当中是否存在。如果存在的话就尝试匹配完整的words数组。复杂之处在于words数组里的word可能有重复的,因此需要在匹配时考虑到重复的问题。显然这种方法效率很低,假设words数组有n个word,s字符串长l,lw是每个word的字长,那么时间复杂度是O(n*l),非常慢,但是万幸也能够通过测试。

- 一个进阶版的算法是引入时间窗的概念:例如从字符串0的位置开始,每lw个字符匹配一次——如果第一次匹配成功,那么在此处记录下pos1,作为时间窗的起点;如果不是第一次匹配成功,那么继续向后匹配,直到从pos1到此处的字符串可以完全匹配words时,说明pos1是一个可行的点,然后将pos1向下一个窗口滑动,继续匹配;如果匹配失败,说明pos1不是一个可行的点,依旧将pos1向下一个窗口滑动,然后重新匹配。这样的步骤只需要重复lw次,就可以完成对整个s串的匹配。这种方法的优势在于,时间窗口可以将从pos1开始到当前位置的所有匹配信息记录下来,有效地加快了速度,时间复杂度在O(l*lw),LeetCode里速度前50%的基本都是这种方法了。

- 似乎还有一种更快的方法,只需要O(n*ls+l)的时间复杂度,使用的是AC自动机的方法,我没有详细了解,在这里只做一个记录,将来有需要的时候可以了解一下。

最后记录一下我的代码,用的是最naive的方法,语言是java:

class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        ArrayList<Integer> result = new ArrayList<Integer>(0);
        HashMap<String,Integer> MapForString = new HashMap<>();
        int Statistic[] = new int [words.length];
        for(int t = 0 ;t<words.length;t++)
        {
        	if(MapForString.get(words[t])==null)
        	{	
        		MapForString.put(words[t], t);
        		Statistic[t]=1;
        	}
        	else
        		Statistic[MapForString.get(words[t])]++;
        }
        if(s.length()==0 || words.length == 0)
        	return result;
        int WordL= words[0].length();
        for(int i = 0;i+WordL-1<s.length();i++)
        {
        	String temp = s.substring(i, i+WordL);
        	if(MapForString.get(temp)!=null)
        	{
        		boolean flag = true;
        		int record[] = new int[words.length];
        		for(int k = 0;k<words.length;k++)
        		{
        			record[k] =Statistic[k];
        		}
        		record[MapForString.get(temp)]--;
        		int count = 1;
        		for(int j = 1;i+j*WordL+WordL-1<s.length() && j<words.length;j++)
        		{
        			temp = s.substring(i+j*WordL,i+j*WordL+WordL);
        			if(MapForString.get(temp)!=null 
        					&& record[MapForString.get(temp)]>0)
        			{
        				record[MapForString.get(temp)]--;
        				count++;
        			}
        			else 
        			{
        				flag = false;
        				break;
        			}
        		}
        		if(flag && count == words.length)
        		{
        			result.add(i);
        		}
        	}
        }
        return result;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值