一 - 前言
介绍:大家好啊,我是hitzaki辰。
社区:(完全免费、欢迎加入)日常打卡、学习交流、资源共享的知识星球。
自媒体:我会在b站/抖音更新视频讲解 或 一些纯技术外的分享,账号同名:hitzaki辰。
正文开始,抓紧上车!
二 - 异位词问题概述
1 - 异位词是什么
1)比如 abc 和 bca就是一个异构词
2)异构词的简单判断:
(1)长度相等
(2)每个字母的数量都相等
2 - 判断异位词
对于需要比较的字符串s和t,使用哈希表可以很方便的判断异位词,维护1个count和一个哈希表。
1)关键代码1解读 - 迭代s串:
对字符串s的所有字符都进行哈希,此时map对应每个字符的数量,count代表字符的种类。
Map<Character, Integer> map = new HashMap<>(); int count = 0; for(int i=0; i<p.length(); i++){ Integer temp = map.get(p.charAt(i)); map.put(p.charAt(i), temp==null? 1: temp+1); if(temp==null) count++; }
比如aabc对应的map和count迭代过程为:
2)关键代码2解读 - 迭代t串:(不同的题,我们迭代的方式不同。)
获取当前t.charAt(i),
(1)若map中没有对应key,说明不是异位词
(2)若有key,将对应value-1,若减为0,则将count-1。
(3)若有key,且对应value已经等于0,说明不是异位词。
最后判断count是否为0,若为0说明是异位词。
以aaba为例:
3 - 根据题干优化
如果题干说只有小写或大写字母这种情况,即固定了出现可能的集合,则我们可以使用一个数组代替哈希表
s串每次迭代只需要这样:++count[s.charAt(i) - 'a'];
三 - 例题1:找到字符串所有字母异位词
题目索引:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
给定两个字符串
s
和p
,找到s
中所有p
的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
1 - 使用哈希表题解:详细注解
class Solution {
public List<Integer> findAnagrams(String s, String p) {
Map<Character, Integer> map = new HashMap<>();
int count = 0;
List<Integer> result = new ArrayList<>();
for(int i=0; i<p.length(); i++){
Integer temp = map.get(p.charAt(i));
map.put(p.charAt(i), temp==null? 1: temp+1);
if(temp==null) count++;
}
int p1=0, p2=0;
boolean flag;
while(p2<s.length()){
// 迭代p2
Integer temp2 = map.get(s.charAt(p2));
if(temp2==null){ // 包含p2的都不可能,因此结束
flag = false;
}else{
flag = true;
map.put(s.charAt(p2), temp2-1);
if(temp2==1)count--;
}
p2++;
// 迭代p1, 根据p2情况进行迭代
// 1.若p2存在, 则当p2-p1==p.length()时才进入
// 若p2不存在, 则迭代至p1==p2
while(flag? p2-p1==p.length(): p1<p2-1){ // 只有p2-1时有null判断
if(count==0)result.add(p1);
// 将p1位置给去除
Integer temp1 = map.get(s.charAt(p1));
if(temp1==0)count++;
map.put(s.charAt(p1), temp1+1);
p1++;
}
if(!flag)p1++; // p1=p2-1时候一定为null, 跳过
} // 主迭代结束
return result;
}
}
2 - 使用数组题解:注解
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int sLen = s.length(), pLen = p.length();
if (sLen < pLen) {
return new ArrayList<Integer>();
}
List<Integer> ans = new ArrayList<Integer>();
int[] count = new int[26];
for (int i = 0; i < pLen; ++i) {
++count[s.charAt(i) - 'a'];
--count[p.charAt(i) - 'a'];
}
int differ = 0;
for (int j = 0; j < 26; ++j) {
if (count[j] != 0) {
++differ;
}
}
if (differ == 0) {
ans.add(0);
}
for (int i = 0; i < sLen - pLen; ++i) {
if (count[s.charAt(i) - 'a'] == 1) { // 窗口中字母 s[i] 的数量与字符串 p 中的数量从不同变得相同
--differ;
} else if (count[s.charAt(i) - 'a'] == 0) { // 窗口中字母 s[i] 的数量与字符串 p 中的数量从相同变得不同
++differ;
}
--count[s.charAt(i) - 'a'];
if (count[s.charAt(i + pLen) - 'a'] == -1) { // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从不同变得相同
--differ;
} else if (count[s.charAt(i + pLen) - 'a'] == 0) { // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从相同变得不同
++differ;
}
++count[s.charAt(i + pLen) - 'a'];
if (differ == 0) {
ans.add(i + 1);
}
}
return ans;
}
}
四 - 例题2:最小覆盖子串
题目索引:https://leetcode.cn/problems/minimum-window-substring/description/
给你一个字符串
s
、一个字符串t
。返回s
中涵盖t
所有字符的最小子串。如果s
中不存在涵盖t
所有字符的子串,则返回空字符串""
。
1 - 思路
例子:s = "ADOBECODEBANC", t = "ABC"
使用双指针:
(1)左指针用来将map和count恢复
(2)右指针用来将map对应的value减一,并改变count
当count=0时,说明此时符合条件,则将此时的子串记录下来。
2 - 题解:详细注解
维护一个数量count和map, 先迭代t将map填充,然后让count = map.size
(1)p2遍历到的如果在map里就将map里对应元素-1, 如果刚好减到0就count-1
(2)如果count==0, 则开始遍历p1,
每次让p1对应到map的元素+1, 每次迭代判断长度, 若小于min则更新
class Solution {
public static String minWindow(String s, String t) {
Map<Character, Integer> map = new HashMap<>();
int min=Integer.MAX_VALUE, index=0, count;
Integer temp;
for(int i=0; i<t.length(); i++){
temp = map.get(t.charAt(i));
map.put(t.charAt(i), temp==null? 1: temp+1);
}
count = map.size();
int p1=0, p2=0;
for(;p2<s.length();p2++){
// 添加p2位置
temp = map.get(s.charAt(p2));
if(temp==null)continue;
// 如果为1说明减完p2元素会归0, 则count变化
map.put(s.charAt(p2), temp-1);
if(temp==1) count--;
// 迭代p1
while(count==0){
if(p2-p1+1<min) {
min = p2-p1+1;
index = p1;
}
// 去掉当前p1的元素
temp = map.get(s.charAt(p1));
p1++;
if(temp==null)continue;
map.put(s.charAt(p1-1), temp+1);
if(temp==0) count++;
}
}
if(min == Integer.MAX_VALUE)return "";
return s.substring(index, index+min);
}
}
五 - 结尾
感谢你看到这里,如果感觉内容不错的话请点赞支持一下!
如果小伙伴对我的讲解有疑问,欢迎评论区讨论。