算法:找到字符串中所有字母异位词
题目:给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
我认为此题与 “查找无重复子串的最长子串” 的思考方向类似(我的随笔里写了这道算法,里面的讲解也很详细),但是这道题目更复杂。都使用哈希表来检查当前字符是不是目标字符,然后滑动左右指针来查找新的子串。
准备工具:左、右指针做滑动窗口;两个哈希表,pmap 存储 p 字符串的字符和频率,smap 存储每个滑动窗口中匹配到的目标字符和频率。
我在代码注释里写了非常清晰的解题步骤和解释!!请查看代码注释 ~
我的 Java 代码:
public List<Integer> findAnagrams(String s, String p) {
Map<Character,Integer> pmap = new HashMap<>();
Map<Character,Integer> smap = new HashMap<>();
List<Integer> result = new ArrayList<>();
int left = 0, right = 0;
int currentLength = 0;
// 设置pmap的元素及各自频率
for(char c : p.toCharArray()){
pmap.put(c,pmap.getOrDefault(c,0)+1);
}
// 右指针 “ 逐步 ” 往右遍历字符串
while(right < s.length()){
char c = s.charAt(right);
//如果是目标元素,更新smap,并判断窗口长度有没有达到目标长度
if(pmap.containsKey(c)){
// 更新smap
smap.put(c, smap.getOrDefault(c,0)+1);
//子串长度相等后,检查smap是否异位词,完全匹配就添加left到结果列表(因为left是子串起始索引)
currentLength = right - left + 1;
if(currentLength==p.length()){
if(smap.equals(pmap)){
result.add(left);
}
//如果窗口长度已经达到目标值,无论是不是异位词,都要移动左指针,删除左元素:把left元素数量在smap中减一(数量为0则移除该元素,否则影响长度匹配)。为了保证:每个窗口长度不能超过目标长度。
char cleft = s.charAt(left);
smap.put(cleft, smap.getOrDefault(cleft,0)-1);
if(smap.get(cleft)==0) smap.remove(cleft);
left ++ ;
}
}
// 如果不是目标字符,则把left移到当前字符的下一个字符,开启新窗口。为什么要这样移动左指针?因为当前left到right的这段区间都不是目标子串,所以要直接跳到right后面查找新子串。
else{
left = right+1;
smap.clear();
}
right ++ ;
}
return result;
}
所有正文内容皆为本人原创,禁止搬运

浙公网安备 33010602011771号