题目:
给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例 1:
输入: s = “barfoothefoobarman”, words = [“foo”,“bar”]
输出:[0,9]
解释:从索引 0 和 9 开始的子串分别是 “barfoo” 和 “foobar” 。 输出的顺序不重要, [9,0] 也是有效答案。
示例 2:
输入: s = “wordgoodgoodgoodbestword”, words = [“word”,“good”,“best”,“word”]
输出:[]
简单介绍:
题目:串联所有单词的子串
题目难度:困难
使用语言:JAVA。
这道题来自leetcode题库的哈希表标签。
解题思路:
首先看题、分析题意,我们可以明确1个关键点:
1.采用什么方式去比对子字符串和单词组会更加高效
既然,我们已经分析出来题目的关键任务了,下面我们就可以开始思考实现了。
我们采用算法与数据结构的思路来剖析一下这题,
数据结构:
要实现对数据的操作,我们要先明确存储数据的数据结构。
该题的数据结构的作用:
1.flagArray:保存单词组单词第i个的数值之和,作为特征。
2.bs:保存boolean结果,做数字压缩
算法:
既然明确了BitSet,int型数组作为解决该题的数据结构,我们就可以开始我们的算法分析了。
1.字符串或单词组为空的情况,返回空集
2.保存单词组单词的同一位置的数值,作为特征
3.对s进行截取,比对各部分单词是否符合特征
4.符合特征之后,再进行单词比对检验
5.bs中的true等于单词组的数目,则该单词符合条件
代码部分:
/*方案1*/
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
public 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;
}
int wLen=words[0].length();//单个单词的长度
int wTotalLen=wLen*words.length;//单词组的总长度
int sLen=s.length();//字符串的长度
int []flagArray=new int[wLen];//保存单词组单词的同一位置的数值,作为特征
for(int i=0;i<wLen;i++){
int flag=0;
for(String word:words){
flag+=word.charAt(i);//每个单词第i位的数值
}
flagArray[i]=flag;
}
BitSet bs=new BitSet(words.length);//方便保存boolean结果,做数字压缩
for(int i=0;i<=sLen-wTotalLen;i++){
int j;
for(j=0;j<wLen;j++){
int sumFlag=0;
for(int k=0;k<words.length;k++){
sumFlag+=s.charAt(i+j+k*wLen);//以i为起点的子字符串,每个单词的第j位的数值
}
if(sumFlag!=flagArray[j]) break;//不符合特征
}
if(j==wLen){//判断是否匹配
bs.clear();//使用前先清理上次保存的结果
for(int k=0;k<words.length;k++){
String w=s.substring(i+k*wLen,i+(k+1)*wLen);//以i为起点的子字符串,第k个单词
int n;
for(n=0;n<words.length;n++){
if(!bs.get(n)&&words[n].equals(w)) {
bs.set(n);//设置第n位为1
break;
}
}
if (n==words.length) break;//单词组所有单词都不能于w对应
}
if (bs.cardinality()==words.length) res.add(i);
}
}
return res;
}
}
结语:
晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!