1.问题描述
给定一个字符串 s
,请你找出其中不含有重复字符的 最长 子串的长度
示例1
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2
输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3
输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke"是一个子序列,不是子串
提示
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成
难度等级
中等
题目链接
无重复字符的最长子串
2.解题思路
这道题让我们找出s字符串中不重复的最长子串的长度,我们只需要找到每一个不重复子串,将它们之中长度最长的那个记录下来即可。
在这里,我选择了用hashMap用存储每一个字符的索引位置,用来判断是否发生重复,加上用滑动窗口的想法来寻找子串来解决这道题。
首先,如果s字符串长度为0,那我们根本就不用找,直接返回0就可以了。
if(s.length() == 0){return 0;}
接着,我们定义左右两个指针来充当滑动窗口的两个边界,定义一个hashMap来存储字符索引,定义一个result来存储找到的子串的最大长度。将s字符串的第一个字符和它的索引存入map中初始化map。
//左指针int left = 0;//右指针int right = 1;//存储窗口内的字符串(字符-->索引)Map<Character,Integer> map = new HashMap<>();//存储结果int result = 0;map.put(s.charAt(0),0);
然后,我们就可以遍历s字符串,让窗口开始滑动了。移动右指针,查询map中是否已经有该字符之前的索引,如果没有,则返回-1作为该字符之前的索引;如果有,则返回该字符之前的索引。如果该字符之前的索引为-1,则说明该字符不会重复,可以加入子串中,更新它在map中的索引,并让右指针移动,窗口扩大;如果该字符之前的索引不为-1,则与窗口的左边界左指针比较,如果之前的索引小于左边界,说明该字符没有在我们当前的子串中重复,它的索引是上一个子串的了,可以将该字符加入子串并更新它在map中的索引。
Integer index = map.getOrDefault(s.charAt(right),-1);//没有重复出现过if(index == -1 || index < left){//添加并继续往右map.put(s.charAt(right),right);right++;continue;}
如果该字符不满足上述两个条件,说明它在当前子串中已经出现过了,重复了。那么当前窗口滑动结束,将当前子串的长度与result中存储的最长长度比较,两者取最大存入result中。然后更新窗口的左的指针,让窗口从被重复字符之前索引的下一个位置开始重新滑动。更新当前字符的索引,窗口继续向右扩大。
//出现重复的//先记录当前最大的长度result = (right - left)>result?(right - left):result;//左指针直接移动到重复索引的下一位left = index+1;//更新重复的索引map.put(s.charAt(right),right);right++;
重复上述操作,知道窗口右边界到达字符串的末尾,最后再更新一次最长子串的长度,即可返回结果了。
result = (right - left)>result?(right - left):result;return result;
3.代码展示
class Solution {public int lengthOfLongestSubstring(String s) {if(s.length() == 0){return 0;}//左指针int left = 0;//右指针int right = 1;//存储窗口内的字符串(字符-->索引)Map<Character,Integer> map = new HashMap<>();//存储结果int result = 0;map.put(s.charAt(0),0);//右指针移动while(right < s.length()){Integer index = map.getOrDefault(s.charAt(right),-1);//没有重复出现过if(index == -1 || index < left){//添加并继续往右map.put(s.charAt(right),right);right++;continue;}//出现重复的//先记录当前最大的长度result = (right - left)>result?(right - left):result;//左指针直接移动到重复索引的下一位left = index+1;//更新重复的索引map.put(s.charAt(right),right);right++;}result = (right - left)>result?(right - left):result;return result;}
}
4.总结
这道题我觉得唯一难的地方,就是如何识别字符是否重复,我们通过设置map的默认值和比较索引是否在窗口之外来解决这个问题。其他的就是简单的记录和移动指针操作了。这道题就简单的讲到这里,拜拜~