LeetCoed 無重複字符的最長子串(java)

一、題目分析

 

分析:

最長子串,而不是最長子序列。子串是字符串連續的一段,子序列是可以不連續的

所以有一種方法叫做滑動窗口法,我記得左程雲老師講過,那個題是計算窗口內最大或者最小值的

在本題中,窗口一直向右移動,左邊緣也可以向右滑動,右邊緣也可以,窗口內的字符是不重複的,每一次加入新的值之後都要記錄當前窗口的長度。

左右邊緣都從begin出發,如果end位置的數已經在窗口中存在,那麼左側邊緣向右收縮,直到窗口中無重複

如果沒有重複,右側邊緣擴展,並記錄窗口大小

 每次在[start,end]中如果有重複的,我們的做法是更新窗口從end重新開始,這種方法要求定義一個hashmap保存字符到索引的映射,並且每次都會更新map的值

下面是一個例子(來自博主 https://www.cnblogs.com/ariel-dreamland/p/8668286.html)

如果給一個例子"abcabcbb",讓你手動找無重複字符的子串,該怎麼找?一個字符一個字符的遍歷,比如a,b,c,然後又出現了一個a,那麼此時就應該去掉第一次出現的a,然後繼續往後,又出現了一個b,則應該去掉一次出現的b,以此類推,最終發現最長的長度爲3。所以說,我們需要記錄之前出現過的字符,記錄的方式有很多,最常見的是統計字符出現的個數,但是這道題字符出現的位置很重要,所以我們可以使用HashMap來建立字符和其出現位置之間的映射。進一步考慮,由於字符會重複出現,到底是保存所有出現的位置呢,還是隻記錄一個位置?我們之前手動推導的方法實際上是維護了一個滑動窗口,窗口內的都是沒有重複的字符,我們需要儘可能的擴大窗口的大小。由於窗口在不停向右滑動,所以我們只關心每個字符最後出現的位置,並建立映射。窗口的右邊界就是當前遍歷到的字符的位置,爲了求出窗口的大小,我們需要一個變量left來指向滑動窗口的左邊界,這樣,如果當前遍歷到的字符從未出現過,那麼直接擴大右邊界,如果之前出現過,那麼就分兩種情況,在或不在滑動窗口內,如果不在滑動窗口內,那麼就沒事,當前字符可以加進來,如果在的話,就需要先在滑動窗口內去掉這個已經出現過的字符了,去掉的方法並不需要將左邊界left一位一位向右遍歷查找,由於我們的HashMap已經保存了該重複字符最後出現的位置,所以直接移動left指針就可以了。我們維護一個結果res,每次用出現過的窗口大小來更新結果res,就可以得到最終結果了。

二、java代碼

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int res = 0;//記錄最長子串的長度
        int end=0,start=0;//記錄開始和結尾的下標
        Set<Character> set=new HashSet<>();//使用set容器不重複
        while(start<n && end<n){
           if(set.contains(s.charAt(end))){//如果窗口右側的字符已經存在
               set.remove(s.charAt(start++));//左側窗口邊界向右
           }else{
               set.add(s.charAt(end++));//如果窗口中無重複,窗口右側向右滑動
               res=Math.max(res,end-start);//同時記錄當前最大長度
           }           
        }
        return res;
 }
}

理解hashset和使用 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章