題目:
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.
解析:
面對(duì)此題逻杖,首先最容易想到的是使用暴力枚舉,然而這會(huì)很容易超時(shí)损晤,不可取。我們這里使用sliding window的思想,什么使sliding window呢漫萄,先這么分析碗誉。當(dāng)我們?cè)谌∽执臅r(shí)候姻报,需要兩個(gè)定位的變量i和j,i代表子串的開頭姨夹,j代表子串的結(jié)尾(j所指位置實(shí)際是子串最后字符的下一個(gè)字符,也就是j不在所取子串中)矾策。
當(dāng)我們?cè)谶M(jìn)行第一排搜尋的時(shí)候磷账,i指向字符串的第一個(gè)字符,j指向第二個(gè)字符贾虽,這時(shí)候所取的子串就是第一個(gè)字符逃糟,只有一個(gè)字符举户,然后每次將j往后移動(dòng)旁瘫,直到發(fā)現(xiàn)所取子串出現(xiàn)重復(fù)的字符,如何判斷是否有重復(fù)字符的方式也很簡(jiǎn)單拂玻,我們需要一個(gè)額外的HashSet地粪,每當(dāng)j后移取募,就將該字符添加進(jìn)HashSet,以此來(lái)判斷是否含有重復(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是不是很形象了呢。在上面的步驟中,只要是子串沒(méi)有重復(fù)字符的時(shí)候岳掐,我們都要記錄下從最開始到那個(gè)時(shí)候的無(wú)重復(fù)子串長(zhǎng)度的最大值凭疮,這很好辦,用到Math的max函數(shù)就行串述≈唇猓總體思路是這樣,下面來(lái)看代碼:
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> c = new HashSet<Character>();#用來(lái)判斷是否用重復(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))){#無(wú)重復(fù)字符
c.add(s.charAt(j++));
ans = Math.max(ans, j-i);#子串的最大值
}else {#遇到了重復(fù)的字符
c.remove(s.charAt(i++));
}
}
return ans;
}
}