https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
一 题目
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 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 由英文字母、数字、符号和空格组成
二 题解
这题的要求是,字符串的子串是一个没有重复字符的串。
假如:字符串为“acbdbeface”
从头开始找,a->ac->acb->acbd
第一次出现重复:acbdb,重复的字符是b,此时最长字符串长度为 4
因此,下一次查找为:dbe。
很明显了,这就是一个双指针的滑动窗口问题,利用双指针来控制滑动窗口大小,计算窗口的最大值。
没有重复字符的时候,那么子串的长度是在递增的
因此在无重复字符的时候,要计算此时字符串长度是否是当前的最大值。
出现重复字符的时候,那么子串的长度肯定是减小的
因此在出现重复字符的时候,只需要移动子串头部位置到新的位置(即子字符串中哪个位置是与比较的字符重复的)。
import java.util.HashMap;import java.util.Map;class Solution {public int lengthOfLongestSubstring(String s) {if(s.length()<2){return s.length();}char[] arrays = s.toCharArray();return doFind(arrays);}private int doFind(char[] arrays){int length = arrays.length;Map<Character,Integer> map = new HashMap<>();int start = 0;int end = 1;int longestLength = 1;map.put(arrays[start],start);while(end<length){// 判断map中是否存在相同的 字符,并且字符的位置位于两个指针之间if(map.containsKey(arrays[end])&&(map.get(arrays[end])>=start)){/*如果为真,则表示在start到end-1之间有字符与end位置的字符是相同的。*/// 获取到该字符的位置,然后该字符后一位为新的子字符串开始位置start = map.get(arrays[end])+1;}else{/* 如果为假,则表示end位置为非重复的字符因此 */longestLength = longestLength<(end-start+1)?(end-start+1):longestLength;}map.put(arrays[end],end);end++;}return longestLength;}public static void main(String[] args) {Solution solution = new Solution();String s1 = "abcabcbb";System.out.println("预期为3,实际为"+solution.lengthOfLongestSubstring(s1));String s2 = "bbbbb";System.out.println("预期为1,实际为"+solution.lengthOfLongestSubstring(s2));String s3 = "pwwkew";System.out.println("预期为3,实际为"+solution.lengthOfLongestSubstring(s3));String s4 = "";System.out.println("预期为0,实际为"+solution.lengthOfLongestSubstring(s4));}}

也可以使用数组来保存出现过的字符与其最后出现的位置
import java.util.HashMap;import java.util.Map;class Solution2 {public int lengthOfLongestSubstring(String s) {if(s.length()<2){return s.length();}char[] arrays = s.toCharArray();return doFind(arrays);}private int doFind(char[] arrays){int length = arrays.length;int[] last = new int[256];for(int i = 0; i < 256; i++) {last[i] = -1;}int start = 0;int end = 1;int longestLength = 1;last[arrays[start]] = start;while(end<length){// 判断该字符串是否出现过,并且出现的位置在start之后if(last[arrays[end]]>=start){/*如果为真,则表示在start到end-1之间有字符与end位置的字符是相同的。*/// 获取到该字符的位置,然后该字符后一位为新的子字符串开始位置start = last[arrays[end]]+1;}else{/* 如果为假,则表示end位置为非重复的字符因此 */longestLength = longestLength<(end-start+1)?(end-start+1):longestLength;}last[arrays[end]] = end;end++;}return longestLength;}public static void main(String[] args) {Solution2 solution = new Solution2();String s1 = "abcabcbb";System.out.println("预期为3,实际为"+solution.lengthOfLongestSubstring(s1));String s2 = "bbbbb";System.out.println("预期为1,实际为"+solution.lengthOfLongestSubstring(s2));String s3 = "pwwkew";System.out.println("预期为3,实际为"+solution.lengthOfLongestSubstring(s3));String s4 = "";System.out.println("预期为0,实际为"+solution.lengthOfLongestSubstring(s4));}}
