题目描述:请从字符串中找出一个最长的不含重复字符的子字符串,计算该字符串的长度。
示例:输入:“abcabcbb” 输出:3
分析:此题属于变种动态规划(个人理解)
首先找到初始值,对于第一个字符,只要s不为空,字符最大长度max为1
随后寻找dp[n]和dp[n-1]的关系:
分为以下种情况:
1.如果该字符没有出现过,那么temp=temp+1,并需要记录一下该字符出现的索引
2.如果该字符出现过再分为两种情况:
(1)一般情况,即该字符两次出现的中间,没有出现重复字符的情况下,此时的最大长度为该字符当前位置-该字符上次出现位置。并且更新该字符出现的位置。
(2)像“abba”这种情况,在a两次出现的中间,有重复字符,temp=temp+1,因为此时temp计算的长度已经不是从上一次出现a字符开始算了,而是上一次没有出现重复字符开始算,也就是第二个b的位置开始计算。
ps:temp只记录从当前字符往前的不重复字符串的长度。
如何判断某个字符两次出现的中间部分有没有重复的数字呢?如果出现重复字符,temp的长度不再是这两个重复字符两次出现的位置差,而是从不重复字符开始到当前字符的长度,所以,
temp<该字符两次出现的位置差,可以用来判断是否出现过重复字符。
我们用HashMap<Character,Integer>来记录每个字符上一次出现的位置,用temp和max分别记录临时的最大值和全局的最大。
class Solution{
public int lengthOfLongestSubstring(String s){
Map<Character,Integer> dic = new HashMap<>();
int temp=0,max=0;
for(int j=0;j<s.length();j++){
if(dic.containsKey(s.charAt(j))){
int i = dic.get(s.charAt(j));
dic.put(s.charAt(j),j);
if(temp<j-i){
temp+=1;
}else{
temp=j-i;
}
}
else{
dic.put(s.charAt(j),j);
temp=temp+1;
}
max=Math.max(temp,max);
}
return max;
}
}
后面再想想,只要把get()换成getOrDefault()方法,若第一次出现则返回-1,就可以合并第一种情况和第2.2种情况。再用上正则表达式,可以使代码精简不少 (虽然是抄大佬的解法)
Class Solution{
public int lengthOfLongestSubstring(String s){
Map<Character,Interger> dic=new HashMap<>();
int temp=0,max=0;
for(int j=0;i<=s.length.j++){
int i=dic.getOrDefault(s.charAt(j),-1);
dic.put(s.charAt(j),j);
temp=temp<j-i?temp+1:j-1;
max=Math.max(temp,max);
}
return max;
}
}