【今日最佳leecode】無重複字符的最長子串

img

相信看了這個標題的同窗,對這道題以已經很是不陌生了,就是leecode當中的第三題,之因此要單獨的寫一寫主要對我來講,裏面涉及到有一個滑動窗口, 散列表, 字符編碼等知識點比較重要,也有幾個小技巧,這裏我也權當記憶鞏固了,這道題也曾被Micosoft, Amazon, Bloomberg, Airbnb, Adobe做爲經典面試題,包括限流, TCP擁塞都有使用到滑動窗口思想。java

題目git

給給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。示例 1: 輸入: "abcabcbb"github

輸出: 3面試

解釋: 由於無重複字符的最長子串是 "abc",因此其長度爲 3。數據庫

輸入: "pwwkew"數組

輸出: 3緩存

解釋: 由於無重複字符的最長子串是 "wke",因此其長度爲 3。markdown

舉例:數據結構

img

做爲大多數人,找出如圖的不相同字符的最大長度,基本上判斷3次,ABC長度爲3,BCAD長度爲4,CADC長度爲3,判斷到這裏直接就能夠給出答案了,就是4,由於CADC已經到字符串末尾了,不用再比較了。可是讓程序去實現這個功能就要設計一下了。併發

根據事例提出幾個問題:

①在第一輪斷定了ABC都不重複,咱們怎麼實現將BC做爲一個總體第二輪就不須要要判斷BC是不重複的子串?

②如何選取數據結構?

滑動窗口:

顧名思義,滑動窗口一般指能夠動態擴容和縮容的一個窗口,如"ABCADC「這個事例,在第二輪咱們視BC爲一個總體進行擴容,擴容到BCAD。

img

img

如」pwwkew「,在第二輪當PW遇到W,咱們進行縮容,直接從下一個W開始。如圖所示。一般滑動窗口的實現須要結合散列表來實現來維護一個不重複子串,當獲取接下來的字符若是存在在散列表中,指針右移。

img

img

img

散列表:

一般一旦涉及到出現次數,咱們能夠用散列表,在Java中咱們經常使用的涉及到散列表的容器有HashMap, HashSet, HashTable等等。這裏咱們能夠選用HashSet,其實其它幾種均可以實現。

Set<Character> occ = new HashSet<>(); // 建立一個散列表
occ.remove(s.charAt(i - 1));          // 指針右移(移除)
occ.add((s.charAt(rk + 1)));          // 指針右移(添加)
!occ.contains(s.charAt(rk + 1))       // 判斷接下來的字符是否出如今散列表
複製代碼

參考代碼

public static int lengthOfLongestSubstring(String s) {
    // 哈希集合,記錄每一個字符是否出現過
    Set<Character> occ = new HashSet<>();
    int n = s.length();
    // 右指針,初始值爲 -1,至關於咱們在字符串的左邊界的左側,尚未開始移動
    int rk = -1, ans = 0;
    for (int i = 0; i < n; ++i) {
        if (i != 0) {
            // 左指針向右移動一格,移除一個字符
            occ.remove(s.charAt(i - 1));
        }
        if (ans >= n -i) {
            break;
        }
        while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
            // 不斷地移動右指針
            occ.add((s.charAt(rk + 1)));
            ++rk;
        }
        // 第 i 到 rk 個字符是一個極長的無重複字符子串
        ans = Math.max(ans, rk - i + 1);
    }
    return ans;
}
複製代碼

測試用例:

@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]); // 記錄上次比較出現過得最大值
            cur = i - pre; // 指針 - 最大值,當指針右移,i變大,他們的差值就越大;出現相同的值,pre變大
            len = Math.max(len,cur);
            map[x] = i;  // 對出現過的字符賦值爲字符串下標
        }
        return len;
    }
複製代碼

咱們知道,在計算機中,全部的數據在存儲和運算時都要使用二進制數表示,在英語中,用128個符號編碼即可以表示全部,其餘語言,128個符號是不夠的。一些歐洲國家決定,利用字節中閒置的最高位編入新的符號,這些歐洲國家使用的編碼體系,能夠表示最多256個符號。可是漢字多達10萬左右,漢字使用GB2312,理論上能夠表示 256 x 256 = 65536 個符號。

在本題中主要只涉及到字符串,徹底能夠使用一個數組,容量大小是256,初始長度都爲-1,出現過的值記錄一下,pre比較出現過的值,經過右移指針與pre的差來記錄最近一次最大值,len爲歷史最大值。

熱門推薦:

文末福利,最近整理一份面試資料《Java面試通關手冊》,覆蓋了Java核心技術、JVM、Java併發、SSM、微服務、數據庫、數據結構等等。獲取方式:GitHub github.com/Tingyu-Note…,更多內容關注個人掘金,陸續奉上。

相關文章
相關標籤/搜索