题目
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例 4:
输入: s = ""
输出: 0
提示:0 <= s.length <= 5 * 104
,s由英文字母、数字、符号和空格组成
来源:力扣(LeetCode),链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
找出最长无重复字符子串:从这里体现我们想要找到答案必然面临着全局遍历。
确定最长子串的区间位置,最直接想法是通过两个指针left
和right
遍历整个子串计算区间最长跨度。
从起始位置开始,right
指针不断往前推进,并每前进一步都判断当前right
指向的字符,是否在之前[left,right)
区间内的字符集合内部。若不存在,证明最长无重复字符还未到right
指针继续前进;若存在,当前区间[left,right)
已到达最长无重复字符。
这里产生几个问题,如何快速判断right
指向的字符是否已存在在区间[left,right)
中?left
指针指向在出现重复字符时如何推进?
如何快速判断
right
指向的字符是否已存在在区间[left,right)
中?
快速判断根源在于快速查找,在我们众多查找算法中,只有hash集合和数组能够在一定条件下做到O(1)
时间复杂度,而且数组结构必须知道坐标位置方能作为快速选择。因此,这里选着hash作为承载数据结构。
left
指针指向在出现重复字符时如何推进?
出现重复字符时,证明当前区间[left,right-1)
为无重复字符(right
指向第一个重复字符),left往前推进到重复字符位置。
查找动态演示
待续。。。
编码实现
public int lengthOfLongestSubstring(String s) {
if(s == null || s.length() <= 0){
return 0;
}
// 采用双指针法进行遍历字符串,找出最长无重复子串
int left = 0;
int right = 0;
// 承载非重复字符下标位置,用于判重
HashMap<Character, Integer> map = new HashMap<>();
char[] charArray = s.toCharArray();
int res = 0;
while(right < charArray.length){
if(map.get(charArray[right]) != null){
// 当出现重复时,需要往前推移左标坐标
// 比较最大值,是因为随着坐标往前移动,若后面出现字符在前方出现过了,坐标也不应该往前移动
left = Math.max(map.get(charArray[right]), left);
}
// 比较最长字符串长度
res = Math.max(res, right - left + 1);
// 这里存在该字符下一位置,表明该字符之前都未出现重复字符;
// 若出现重复字符应该在该字符下个字符位置重新计算
map.put(charArray[right], right + 1);
right++;
}
return res;
}