题目描述:
给定一个字符串 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
由英文字母、数字、符号和空格组成
题解1:
从左到右遍历每一个位置的字符,temp中保存的是当前计算出来的最长无重复字符的子串,count中保存的是无重复元素的最长字串长度。
初始时,在temp字符串中保存第一个字符,假设现在从第二个字符位置开始遍历,如果当前位置的字符 x 在temp中已有记录,那么说明现在以第一个字符开头的子串已经是最长的无重复元素的子串了,那么就更新count,然后从temp中找出字符 x 出现的位置,然后从该位置之后截取字符串,重新更新字符串temp,接着将下一个要添加进来的字符拼接在字符串末尾,继续向后遍历下一个字符。
说明:相当于是一个无脑版本,能过测试但是没有用到滑动窗口的知识,题解2实现滑动窗口求解过程。
代码实现:
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length()==0){
return 0;
}
if(s.length()==1){
return 1;
}
char[] a = s.toCharArray();
int count = 0;
int len = s.length();
StringBuffer temp = new StringBuffer(String.valueOf(a[0]));
for (int i = 1; i < len; i++) {
int index = temp.indexOf(String.valueOf(a[i]));
if(index!=-1) {
count = Math.max(count, temp.length());
temp.delete(0, index + 1);
}
temp.append(a[i]);
count = Math.max(count,temp.length());
}
return count;
}
}
知识点:
StringBuffer可以delete、append、indexOf但是不可以contains
题解2:
根据438.找到字符串中所有字母异位词的中给出的求解滑动窗口问题的思路,考虑这道题。
同样还是要设置windows来存储当前窗口每种元素的个数,窗口右移一个的时候就需要更新window中的数据,将右移之后新圈入的元素的value值加一;
判断是否要收缩窗口的条件是,当前元素添加进来之后,窗口中该元素的value>1,那么为了能够让当前元素能够添加进来,就需要从左边不断缩小窗口,采用while循环,直到将窗口中其他的当前和当前元素相同的值剔除出去;
缩小窗口的时候进行的数据更新是将现在从窗口中删除的元素值对应的value--,同时left++;
当缩小窗口的while循环退出的时候,就说明当前圈入新的元素之后,通过不断缩小窗口又将窗口更新成了一个满足要求的窗口,此时就可以更新答案,计算当前窗口大小是否比之前计算出来的大。
代码实现:
public static int lengthOfLongestSubstring(String s) {
HashMap<Character, Integer> window= new HashMap<>();
int left = 0, right = 0;
int res = 0; // 记录结果
while (right < s.length()) {
char c = s.charAt(right);
right++;
// 进行窗口内数据的一系列更新
window.put(c, window.getOrDefault(c,0)+1);
// 判断左侧窗口是否要收缩
while (window.get(c)> 1) {
char d = s.charAt(left);
left++;
// 进行窗口内数据的一系列更新
window.put(d,window.get(d)-1);
}
// 在这里更新答案
res = Math.max(res, right - left);
}
return res;
}