给定一个子串s和一些长度相同的单词组成的字符串数组words.注意: 在s中找出恰好串联words中所有单词的子串的起始位置,中间不能有其他字符,但不要考虑words中单词串联的顺序. 上篇我们讨论了本题的一种暴力求解法,本篇接着讨论另外两种优化的解法.
解法二: 本方法遍历子串时,同解法一不同之处在于,子串与给定单词字符串数组words的匹配规则不同.解法一是利用子串组成的数组和给定words的排序结果的内容相同来判断子串是否满足要求;而解法二利用了map,首先将words中单词与单词频次转化为key-value的形式,遍历s时得到的子串按同理存于另一个map里面,判断这两个map是否相等,以此决定该子串是否满足要求。
java源程序: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public List<Integer> findSubstring (String s, String[] words) { int sLen = s.length(); int unit = words.length; List<Integer> res = new LinkedList<>(); if (unit==0 || sLen==0 ) return res; int wLen = words[0 ].length(); int wordsLen = unit*wLen; Map<String,Integer> map = new HashMap<>(); for (String word:words){ map.put(word,map.getOrDefault(word,0 )+1 ); } for (int i=0 ;i<sLen-wordsLen+1 ;i++){ Map<String,Integer> temp = new HashMap<>(map); int j=0 ; for (;j<unit;j++){ String sub = s.substring(i+j*wLen,i+(j+1 )*wLen); if (!temp.containsKey(sub)||temp.get(sub)==0 ) break ; temp.put(sub,temp.get(sub)-1 ); } if (j==unit) res.add(i); } } }
运行时间和空间如下图:
解法三: 解法三与解法二判断子串和words是否匹配的方法一样,但是遍历子串的方式有所不同.在第一层循环中,以一个字符为单位,遍历次数为wLen,在第二层循环中,以wLen为一单位,比较当前子串第一个长度为wLen的单词与其后长度为wLen的单词是否相同,相同就维持未来字符串不变,这样,如果匹配成功的话,索引位置就对应于子串首次出现的位置;如果不同,删除子串第一个单词,加入子串后的一个单词,形成一个新的子串.两层循环下,可以将所有的情况遍历完,重要的是,第二层循环的处理减少了map的频繁操作,从而降低了时间的复杂度。
java源程序: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution { public List<Integer> findSubstring (String s, String[] words) { int sLen = s.length(); int unit = words.length; List<Integer> res = new LinkedList<>(); if (unit==0 || sLen==0 ) return res; int wLen = words[0 ].length(); int wordsLen = unit*wLen; Map<String,Integer> map = new HashMap<>(); for (String word:words){ map.put(word,map.getOrDefault(word,0 )+1 ); } for (int i=0 ;i<wLen;i++){ Map<String,Integer> temp = new HashMap<>(); for (int k=0 ;k<unit&&i+(k+1 )*wLen<=sLen;k++){ String sub = s.substring(i+k*wLen,i+(k+1 )*wLen); temp.put(sub,temp.getOrDefault(sub,0 )+1 ); } if (map.equals(temp)) res.add(i); for (int j=i+wordsLen;j+wLen<=sLen;j+=wLen){ String start = s.substring(i,i+wLen); String end = s.substring(j,j+wLen); temp.put(end,temp.getOrDefault(end,0 )+1 ); if (temp.get(start)==1 ) temp.remove(start); else temp.put(start,temp.get(start)-1 ); i += wLen; if (map.equals(temp)) res.add(i); } i%=wLen; } return res; } }
运行时间和空间如下图: