你須要的LeeCode題No.03——「無重複字符的最長子串」_一點課堂(多岸學院)

無重複字符的最長子串

題目:無重複字符的最長子串java

描述:給定一個字符串,請你找出其中不含有重複字符的最長子串的長度。算法

示例:數組

  • 輸入: "abcabcbb"
  • 輸出: 3
  • 解釋: 由於無重複字符的最長子串是 "abc",因此其長度爲 3。

解析

有了題目001的經驗,咱們應該不會再使用暴力搜索方式來解此題。若使用暴力搜索,要獲得全部的子字符串,須要雙重for循環,時間複雜度爲O(n<sup>2</sup>),獲得的每一個字符串還須要判斷它是否包含重複字符,這一操做也須要O(n)的耗時,從而使得總時間複雜度達到O(n<sup>3</sup>)。這是沒法接受的,因此咱們應該尋求更好的解題方式。學習

此題有一個特定條件:無重複字符。若是使用哈希表來存儲每一個字符,咱們就能夠在構建子串時得知它是否包含重複字符。下面,咱們以示例中的輸入"abcabcbb"爲例,來講明哈希表是如何在此問題中發揮做用的。3d

首先,咱們建一個空的哈希表,key值是每一個字符,value是字符的下標。每當遇到一個哈希表中不存在的字符,咱們就把它存入表中,因此咱們能夠依次存入'a'->'b'->'c'三個字符,哈希表中的數據以下圖:code

file

當咱們要存入第四個字符時,哈希表中已經存在了該字符 'a',也就是說"abca"這個子串中包含了重複字符。如今,咱們能夠肯定,以第一個字符 'a' 爲起點的最長無重複字符子串就是"abc",且它的長度是 ( 字符 'b' 的下標 - 字符 'a' 的下標 + 1),這個值和哈希表的value正好對應。可是以第二個字符 'b' 爲起點的子串有可能比"bca"更長,咱們還須要看下一個字符是否重複,爲了保證哈希表中的value值和子串中字符的下標值一致,咱們須要把 'a' 的value更新成 3,也就是後一個 'a' 的下標。以下所示:blog

file

下一個字符是 'b',和上一步狀況一致,咱們確認了以第二個字符 'b' 爲起點的最長無重複字符子串是"bca",且它的長度是 ( 字符 'a' 的下標 - 字符 'b' 的下標 + 1),可是以第三個字符 'c' 爲起點的子串有可能比"cab"更長。重複這個過程,咱們就能夠找到以每一個字符爲起點的最長無重複字符子串。圖片

除了示例的狀況,咱們還要考慮第二種狀況,好比把輸入換成"abcbcad",一開始的結構是一致的,依然是依次存入'a'->'b'->'c'三個字符。當咱們要存入第四個字符時,哈希表中已經存在了該字符'b',可是 'b' 倒是處於中間的字符,這樣一來以第一個字符 'a' 爲起點的最長無重複字符子串是"abc",以第二個字符 'b' 爲起點的最長無重複字符子串是"bc"。而以第三個字符 'c' 爲起點的子串,在當前只包含 'c' 和 'b' 兩個字符,也就是說字符 'a' 是多餘的,以下所示:資源

file

能夠考慮把 'a' 從表中刪除,但更優雅的方式是使用標記,由於無用字符必定在當前被當作起點的字符以前,因此只要標記好這個字符的位置,就能夠忽略無用字符的存在,以下所示:字符串

file

之因此不選擇刪除字符,是由於沒法肯定後續是否還會再次出現這個字符,例如本例中字符 'a' 就會在第6位再次出現,這樣咱們以前的刪除操做就毫無心義了。

上述過程,咱們只須要對字符串進行一次遍歷就能獲得結果,時間複雜度僅爲O(n),這比暴力搜索好得多。參考代碼以下:

public int lengthOfLongestSubstring(String s){
    Map<Character,Integer> map = new HashMap<>();
    int maxLen = 0;
    int startIndex = 0;
    int tempMaxLen = 0;
    for (int i = 0, len = s.length(); i < len; i++) {
        if (map.containsKey(s.charAt(i)) && map.get(s.charAt(i)) >= startIndex) {
            startIndex = map.get(s.charAt(i)) + 1;
        }

        map.put(s.charAt(i), i);
        tempMaxLen = i - startIndex + 1;
        maxLen = maxLen < tempMaxLen ? tempMaxLen : maxLen;
    }
    return maxLen;
}

總結

以上思路也被稱做滑動窗口法,這個比喻還挺形象,但願你們能記住這個思路,當遇到此類問題時可以多往這方面想想,極大可能想到比暴力搜索好得多的算法。

下題預告

題目:尋找兩個有序數組的中位數

描述:給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2。請你找出這兩個有序數組的中位數,而且要求算法的時間複雜度爲 O(log(m + n))。你能夠假設 nums1 和 nums2 不會同時爲空。

示例 1:

  • nums1 = [1, 3]
  • nums2 = [2]
  • 則中位數是 2.0

示例 2:

  • nums1 = [1, 2]
  • nums2 = [3, 4]
  • 則中位數是 (2 + 3)/2 = 2.5

相關源碼請加QQ獲取。


【感謝您能看完,若是可以幫到您,麻煩點個贊~】

更多經驗技術歡迎前來共同窗習交流: 一點課堂-爲夢想而奮鬥的在線學習平臺 http://www.yidiankt.com/

![關注公衆號,回覆「1」免費領取-【java核心知識點】] file

QQ討論羣:616683098

QQ:3184402434

想要深刻學習的同窗們能夠加我QQ一塊兒學習討論~還有全套資源分享,經驗探討,等你哦! 在這裏插入圖片描述

相關文章
相關標籤/搜索