題目:
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 a subsequence and not a substring.
解析:
面對此題,首先最容易想到的是使用暴力枚舉,然而這會(huì)很容易超時(shí),不可取。我們這里使用sliding window的思想,什么使sliding window呢,先這么分析。當(dāng)我們在取字串的時(shí)候,需要兩個(gè)定位的變量i和j,i代表子串的開頭,j代表子串的結(jié)尾(j所指位置實(shí)際是子串最后字符的下一個(gè)字符,也就是j不在所取子串中)。
當(dāng)我們在進(jìn)行第一排搜尋的時(shí)候,i指向字符串的第一個(gè)字符,j指向第二個(gè)字符,這時(shí)候所取的子串就是第一個(gè)字符,只有一個(gè)字符,然后每次將j往后移動(dòng),直到發(fā)現(xiàn)所取子串出現(xiàn)重復(fù)的字符,如何判斷是否有重復(fù)字符的方式也很簡單,我們需要一個(gè)額外的HashSet,每當(dāng)j后移,就將該字符添加進(jìn)HashSet,以此來判斷是否含有重復(fù)字符。當(dāng)我們一發(fā)現(xiàn)出現(xiàn)重復(fù)的字符后,我們采取的措施就在這里與暴力枚舉不同了,我們將i往后移,j保持不動(dòng),這之后再次檢查是否重復(fù),若還重復(fù),重復(fù)上一步驟,直到i在j前面,這下一定不會(huì)重復(fù),因?yàn)橹挥幸粋€(gè)字符了。不重復(fù)之后,繼續(xù)將j往后移,重復(fù)之前的步驟,重復(fù)了將i后移,不重復(fù)繼續(xù)移動(dòng)j。這將向一面窗戶的兩邊,只會(huì)往一個(gè)方向移動(dòng),這個(gè)sliding window是不是很形象了呢。在上面的步驟中,只要是子串沒有重復(fù)字符的時(shí)候,我們都要記錄下從最開始到那個(gè)時(shí)候的無重復(fù)子串長度的最大值,這很好辦,用到Math的max函數(shù)就行。總體思路是這樣,下面來看代碼:
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> c = new HashSet<Character>();#用來判斷是否用重復(fù)字符的哈希集
int ans = 0;
int n = s.length();
int i = 0;
int j = 0;
while(i < n && j < n) {
if(!c.contains(s.charAt(j))){#無重復(fù)字符
c.add(s.charAt(j++));
ans = Math.max(ans, j-i);#子串的最大值
}else {#遇到了重復(fù)的字符
c.remove(s.charAt(i++));
}
}
return ans;
}
}