【今日最佳leecode】無(wú)重復(fù)字符的最長(zhǎng)子串

img

相信看了這個(gè)標(biāo)題的同學(xué),對(duì)這道題以已經(jīng)非常不陌生了,就是leecode當(dāng)中的第三題,之所以要單獨(dú)的寫一寫主要對(duì)我來說,里面涉及到有一個(gè)滑動(dòng)窗口, 散列表, 字符編碼等知識(shí)點(diǎn)比較重要,也有幾個(gè)小技巧,這里我也權(quán)當(dāng)記憶鞏固了,這道題也曾被Micosoft, Amazon, Bloomberg, Airbnb, Adobe作為經(jīng)典面試題,包括限流, TCP擁塞都有使用到滑動(dòng)窗口思想。

題目

給給定一個(gè)字符串,請(qǐng)你找出其中不含有重復(fù)字符的 最長(zhǎng)子串 的長(zhǎng)度。示例 1: 輸入: "abcabcbb"

輸出: 3

解釋: 因?yàn)闊o(wú)重復(fù)字符的最長(zhǎng)子串是 "abc",所以其長(zhǎng)度為 3。

輸入: "pwwkew"

輸出: 3

解釋: 因?yàn)闊o(wú)重復(fù)字符的最長(zhǎng)子串是 "wke",所以其長(zhǎng)度為 3。

舉例:

img

作為大多數(shù)人,找出如圖的不相同字符的最大長(zhǎng)度,基本上判斷3次,ABC長(zhǎng)度為3,BCAD長(zhǎng)度為4,CADC長(zhǎng)度為3,判斷到這里直接就可以給出答案了,就是4,因?yàn)镃ADC已經(jīng)到字符串末尾了,不用再比較了。但是讓程序去實(shí)現(xiàn)這個(gè)功能就要設(shè)計(jì)一下了。

根據(jù)事例提出幾個(gè)問題:

①在第一輪判定了ABC都不重復(fù),我們?cè)趺磳?shí)現(xiàn)將BC作為一個(gè)整體第二輪就不需要要判斷BC是不重復(fù)的子串?

②如何選取數(shù)據(jù)結(jié)構(gòu)?

<font face="黑體">滑動(dòng)窗口:</font>

顧名思義,滑動(dòng)窗口通常指可以動(dòng)態(tài)擴(kuò)容和縮容的一個(gè)窗口,如"ABCADC“這個(gè)事例,在第二輪我們視BC為一個(gè)整體進(jìn)行擴(kuò)容,擴(kuò)容到BCAD。

img
img

如”pwwkew“,在第二輪當(dāng)PW遇到W,我們進(jìn)行縮容,直接從下一個(gè)W開始。如圖所示。通?;瑒?dòng)窗口的實(shí)現(xiàn)需要結(jié)合散列表來實(shí)現(xiàn)來維護(hù)一個(gè)不重復(fù)子串,當(dāng)獲取接下來的字符如果存在在散列表中,指針右移。

img
img
img

散列表:

通常一旦涉及到出現(xiàn)次數(shù),我們可以用散列表,在Java中我們常用的涉及到散列表的容器有HashMap, HashSet, HashTable等等。這里我們可以選用HashSet,其實(shí)其它幾種都可以實(shí)現(xiàn)。

Set<Character> occ = new HashSet<>(); // 創(chuàng)建一個(gè)散列表
occ.remove(s.charAt(i - 1));          // 指針右移(移除)
occ.add((s.charAt(rk + 1)));          // 指針右移(添加)
!occ.contains(s.charAt(rk + 1))       // 判斷接下來的字符是否出現(xiàn)在散列表

參考代碼

public static int lengthOfLongestSubstring(String s) {
    // 哈希集合,記錄每個(gè)字符是否出現(xiàn)過
    Set<Character> occ = new HashSet<>();
    int n = s.length();
    // 右指針,初始值為 -1,相當(dāng)于我們?cè)谧址淖筮吔绲淖髠?cè),還沒有開始移動(dòng)
    int rk = -1, ans = 0;
    for (int i = 0; i < n; ++i) {
        if (i != 0) {
            // 左指針向右移動(dòng)一格,移除一個(gè)字符
            occ.remove(s.charAt(i - 1));
        }
        if (ans >= n -i) {
            break;
        }
        while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
            // 不斷地移動(dòng)右指針
            occ.add((s.charAt(rk + 1)));
            ++rk;
        }
        // 第 i 到 rk 個(gè)字符是一個(gè)極長(zhǎng)的無(wú)重復(fù)字符子串
        ans = Math.max(ans, rk - i + 1);
    }
    return ans;
}

測(cè)試用例:

@Test
public void islengthOfLongestSubstring() {
//  int i = lengthOfLongestSubstring("abcadc");
    int i = lengthOfLongestSubstring("pwwkew");
    Assert.assertNotNull(i);
}

拓展

public int lengthOfLongestSubstring1(String s) {
        if(s==null||s.equals(""))
            return 0;
        int []map = new int[256];
        for(int i=0;i<256;i++)
            map[i]=-1;
        int len = 0, cur = 0, pre = -1;
        for(int i=0;i<s.length();i++){
            int x = s.charAt(i);
            pre = Math.max(pre,map[x]); // 記錄上次比較出現(xiàn)過得最大值
            cur = i - pre; // 指針 - 最大值,當(dāng)指針右移,i變大,他們的差值就越大;出現(xiàn)相同的值,pre變大
            len = Math.max(len,cur);
            map[x] = i;  // 對(duì)出現(xiàn)過的字符賦值為字符串下標(biāo)
        }
        return len;
    }

我們知道,在計(jì)算機(jī)中,所有的數(shù)據(jù)在存儲(chǔ)和運(yùn)算時(shí)都要使用二進(jìn)制數(shù)表示,在英語(yǔ)中,用128個(gè)符號(hào)編碼便可以表示所有,其他語(yǔ)言,128個(gè)符號(hào)是不夠的。一些歐洲國(guó)家決定,利用字節(jié)中閑置的最高位編入新的符號(hào),這些歐洲國(guó)家使用的編碼體系,可以表示最多256個(gè)符號(hào)。但是漢字多達(dá)10萬(wàn)左右,漢字使用GB2312,理論上可以表示 256 x 256 = 65536 個(gè)符號(hào)。

在本題中主要只涉及到字符串,完全可以使用一個(gè)數(shù)組,容量大小是256,初始長(zhǎng)度都為-1,出現(xiàn)過的值記錄一下,pre比較出現(xiàn)過的值,通過右移指針與pre的差來記錄最近一次最大值,len為歷史最大值。

熱門推薦:

文末福利,最近整理一份面試資料《Java面試通關(guān)手冊(cè)》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。獲取方式:GitHub github.com/Tingyu-Notes,更多內(nèi)容關(guān)注我的簡(jiǎn)書,陸續(xù)奉上。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 3. 無(wú)重復(fù)字符的最長(zhǎng)子串 給定一個(gè)字符串,請(qǐng)你找出其中不含有重復(fù)字符的 最長(zhǎng)子串 的長(zhǎng)度。 示例 1:輸入: "...
    pao哥閱讀 172評(píng)論 0 2
  • 本文為個(gè)人解題思路整理,水平有限,有問題歡迎交流 概覽 第一次解出來沒花多長(zhǎng)時(shí)間,但是提交后發(fā)現(xiàn)擊敗了30%的人,...
    Echo_YeZ閱讀 245評(píng)論 0 0
  • 久違的晴天,家長(zhǎng)會(huì)。 家長(zhǎng)大會(huì)開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,826評(píng)論 16 22
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    余生動(dòng)聽閱讀 10,871評(píng)論 0 11
  • 可愛進(jìn)取,孤獨(dú)成精。努力飛翔,天堂翱翔。戰(zhàn)爭(zhēng)美好,孤獨(dú)進(jìn)取。膽大飛翔,成就輝煌。努力進(jìn)取,遙望,和諧家園。可愛游走...
    趙原野閱讀 3,509評(píng)論 1 1

友情鏈接更多精彩內(nèi)容