import java.util.*;


public class Solution {
    // 找到字符串中最长的不包含重复字符的子字符串,返回最长子字符串的长度
    // 思路:双指针遍历字符串,最后返回两个指针的差值就是最长字符串的长度
    // 关键词:最长,不含重复字符
    // 最长要靠双指针,重复字符要靠哈希表
  	// 在这段代码中,没有用到双指针,只用了一个指针回溯来遍历整个字符串,通过哈希表本身不含重复元素的性质,key为字符,value为该字符对应的index;当遇到重复的字符,就找到对应字符在当前记录的子字符串的位置,之后将该位置之前的所有字符remove。之后有一个关键点在于,当把重复位置(含重复位置)之前的字符remove后,之后的几个字符可能也已经添加到哈希表中了,我们需要通过改变right的值来将其定位到没有被遍历过的新字符的位置上,通过right = index + hashMap.size()实现。
    public int lengthOfLongestSubstring (String s) {
        if(s.length() == 1) return 1;
        // write code here
        // 指针需要回溯
        int right = 0;
        HashMap<Character,Integer> hashmap = new HashMap<>();
        // 每次比较max和当前遍历到的字符串的长度
        int max = Integer.MIN_VALUE;
        while(right < s.length()){
            if(!hashmap.containsKey(s.charAt(right))){
                // 这里记录每次加进来的字符的key和对应位置的value
                hashmap.put(s.charAt(right),right);
                max = Math.max(max,hashmap.size());
                right++;
            }else{
                // 遇到重复的字符,就找到对应字符在当前记录的子字符串的位置,之后将该位置之前的所有字符remove
                max = Math.max(max,hashmap.size());
                int index = hashmap.get(s.charAt(right));
                for(int i = index;i>=0;i--){
                    hashmap.remove(s.charAt(i));
                }
                right = index + 1 + hashmap.size();

            }
        }
        return max;
    }
}