题目描述:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
暴力法:
i从0到n-2
j从i+1到n-1
逐个检查s[i]到s[j]组成的字符串是否为无重复字符的最长子串。
滑动窗口法:
滑动窗口是数组/字符串问题中常用的抽象概念。 窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i, j)[i,j)(左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将 [i, j)[i,j) 向右滑动 11 个元素,则它将变为 [i+1, j+1)[i+1,j+1)(左闭,右开)。
使用map作为一个“窗口”,这个map中key存储的就是无重复字符的子串,value存储的是该字符在字符串中对应的位置。。
如果从索引 i 到 j之间的子字符串 s{i,j}已经被检查为没有重复字符。我们只需要检查 **s[j+1]**对应的字符是否已经存在于字符串 s{i,j}中。如果不存在,则将s[j+1]归入窗口中。否则,将窗口左边界定位到上次s[j+1]字符出现的位置。
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>();
for (int j = 0, i = 0; j < n; j++) {//i窗口左边界,j窗口又边界
if (map.containsKey(s.charAt(j))) {//s[j]已存在
i = Math.max(map.get(s.charAt(j)), i);//上次s[j]字符出现的位置的 后一位。
}//保证i到j之间为无重复字符子串
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1);//+1,记录后一位
}
return ans;
}
}