题目描述
- 子串:各字符间必须要相邻,而非子序列
- 使用滑动窗口来做就行
思路 && 代码
1. 之前的版本
- 思路:维护一个滑动窗口,滑动窗口中容纳一个无重复字符的子串。
- 滑动窗口左边界移动的情况:
- 【abc】 a => a【bca】
- 【abcd】 c => abc【dc】
- 其实以上两种情况殊途同归,都是把左边界换成当前判断字符在HashMap中对应的下标的位置的后一个。
然后把前面的字符全都丢弃即可(在HashMap中remove())。 - 左边界移动的情况,需要进行长度的判断:当前滑动窗口长度可能会改变,如果比当前存储的最大长度要大,那么就需要更新。
- 为什么可以这样子:特别记录一下,这道题其实老早就通过了。。但是之后考虑情况多了,出现了觉得自己写的代码其实考虑不周,但是就是过了的情况= =。
主要是有这个注意点:在上面的左边界移动情况2,考虑到abc都被丢弃,但是有没有可能a、b实际上可能可以创造最长子串呢? 答案是没有,因为实际上最多的长度【abcd】已经被记录下来了,b最多就是【bcd】c的情况,a也同理,因此已经可以直接丢弃掉了。
class Solution {public int lengthOfLongestSubstring(String s) {int len=0, lenNow=0;HashMap<Character,Integer> hashMap = new HashMap<>();for(int i=0;i<s.length();i++){if(hashMap.containsKey(s.charAt(i))){if(hashMap.get(s.charAt(i))==i-lenNow){hashMap.put(s.charAt(i),i);continue;}len = Math.max(len,lenNow);int temp = hashMap.get(s.charAt(i));for(int j = i-lenNow;j<=temp;j++){hashMap.remove(s.charAt(j),j);}lenNow = i - temp;hashMap.put(s.charAt(i),i);}else{hashMap.put(s.charAt(i),i);lenNow++;}}return Math.max(len,lenNow);}
}
- 时间复杂度:O(N),实际上整个流程本质上就是对字符串的每一个元素都必然访问一次,可能删除一次。
- 空间复杂度:O(字符集的大小),因为我们需要简历哈希表,而表最大的情况下会容纳整个字符集(及对应下标)。
更新 2.0
class Solution {public int lengthOfLongestSubstring(String s) {int len = s.length();int max = 0;char[] arr = s.toCharArray();Map<Character, Integer> hashmap = new HashMap<>();int windowLeft = 0;for(int i = 0; i < len; i++) {if(hashmap.containsKey(arr[i])) {int index = hashmap.get(arr[i]);for(int j = windowLeft; j <= index; j++) {hashmap.remove(arr[j]);}windowLeft = index + 1;hashmap.put(arr[i], i);}else {hashmap.put(arr[i], i);max = Math.max(max, hashmap.size());}}return max;}
}