问题描述:
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb"
, the answer is "abc"
, which the length is 3.
Given "bbbbb"
, the answer is "b"
, with the length of 1.
Given "pwwkew"
, the answer is "wke"
, with the length of 3. Note that the answer must be a substring,"pwke"
is asubsequence and not a substring
我想的是用两层for来遍历,求出每一个位置上的最长子串,太复杂了。而且复杂度是O(n*n)
解决方案:
现在有一个复杂度为O(n)的算法——滑动窗口。滑动窗口是处理字符串和数组问题的经典方案。
1 滑动窗口的思想:
顾名思义,滑动窗口就是滑动的窗口,在字符串上从左往右滑动,直到串尾。滑动窗口的窗口长度是动态变化的,所以用两个指针(见到指针不要惶恐,java里的指针都封装好了,在java里指针就是一个变量而已)来维护,一个是指针指向窗口的右边界姑且命名为j,一个指针指向窗口的左边界姑且命名为i。
2 滑动窗口怎么滑?
串首——>串尾
3 滑动窗口的大小怎么控制?即,何时改变左边界,何时改变右边界?
当前窗口里的子串s[i]...s[j]不包含字符s[j+1]时,窗口右边界右移一位。
否则,即当前窗口里的子串s[i]...s[j]包含字符s[j+1]时,窗口左边界右移一位。
也就是说,j记录的是窗口滑过(包括在当前窗口里的,和不在当前窗口里的)的字符序列中不重复的字符个数,
i记录的是窗口滑过(包括在当前窗口里的,和不在当前窗口里的)的字符序列中重复的字符个数,则j-i的最大值就是不重复的最长子串长度。
4 滑动窗口用什么数据结构实现的?
因为里面不包含重复的字符,所以用的set,为了高效查找,用的HashSet。
java版
public class Solution {
int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> set = new HashSet<Character>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
if (!set.contains(s.charAt(j))) {
set.add(s.charAt(j++));//如果不包含,j就自增
ans = Math.max(ans, j - i);//j - i = 最大的不重复的长度。
} else {
set.remove(s.charAt(i++));//如果包含,i就增,并把窗口后滑
}
}
return ans;
}
public static void main(String[] args) {
String s = "jkklmmds";
System.out.println(new Solution().lengthOfLongestSubstring(s));
}
}