3. 无重复字符的最长子串
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 由英文字母、数字、符号和空格组成
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters
2. 解题思路
2.1 双指针(滑动窗口)
n:字符串长度
left:标记字符串起始位置,初始为0
right:标记字符串结束位置,初始为0
使得 left~right 之间的字符串为无重复字符的子串
right指针从0开始遍历到n,记录字符及下标
- 若right下标的字符 在left~right区间内的x位置出现过
- 则将left指针设为x+1,使得left-right区间没有重复字符
class Solution {
public int lengthOfLongestSubstring(String s) {
/**
* max记录最大子串长度
* left标识字符串起始位置
* right标识字符串结束位置
**/
int max=0,left=0,right=0,n=s.length();
// 通过map记录出现过的字符及最后一次出现的下标
HashMap<Character,Integer> map=new HashMap<>();
while(right<n){
char c=s.charAt(right);
if(map.containsKey(c) && map.get(c)>=left){ // 判断字符c是否在区间内出现过
left=map.get(c)+1; // 更新字符串起始位置,使得区间内无重复字符
}
map.put(c,right); // 更新字符下标
max=Math.max(max,right-left+1);
right++;
}
return max;
}
}
2.2 优化
由于2.1通过HashMap来存储字符位置,HashMap计算hash值有一定的耗时,优化为数组形式,可以提高效率。
优化结果:
- 优化前执行用时:5ms
- 优化后执行用时:1ms
class Solution {
public int lengthOfLongestSubstring(String s) {
int max=0,left=0,right=0,n=s.length();
int[] cs=new int[128];
for(int i=0;i<128;i++) cs[i]=-1;
while(right<n){
char c=s.charAt(right);
if(cs[c]!=-1 && cs[c]>=left){
left=cs[c]+1;
}
cs[c]=right;
max=Math.max(max,right-left+1);
right++;
}
return max;
}
}