【LeetCode】無重複字符串最長子串

題目描述

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

示例 1:bash

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

示例 2:測試

輸入: "bbbbb"
輸出: 1
解釋: 由於無重複字符的最長子串是 "b",因此其長度爲 1。

示例 3:優化

輸入: "pwwkew"
輸出: 3
解釋: 由於無重複字符的最長子串是 "wke",因此其長度爲 3。
     請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。

題目解析

這道題的目標是找出最長子串,而且該子串必須不包含重複字符,並且這個子串必須是原字符串中連續的一部分(見示例3中的解釋說明)。code

拿到題目時先不要心急想什麼騷操做,咱們先從最普通的操做開始把題目解出來,而後再來看如何優化。blog

接下來,咱們畫圖分析一下,先隨便弄一個長相普通的字符串:frankissohandsome,咱們要從中找出咱們想要的子串,那少不了須要遍歷,咱們設置兩個變量fromto,分別存儲尋找的目標子串在原字符串中的首尾位置。字符串

首先,fromto的初始值都爲0(String的序號從0開始),子串長度length = 1,最大子串長度maxLength = 1string

而後,咱們將to的指向日後移動,並判斷新遍歷的字符是否已經存在於子串中,若是不存在,則將其加入子串中,並將length進行自增。it

直到找到一個已存在於子串中的字符,或者to到達字符串的末尾。這裏,咱們找到了一個重複的s,序號爲7,此時的子串爲frankis,將此時的子串長度與最大子串長度相比較(目前爲0),若是比最大子串長度大,則將最大子串長度設置爲當前子串長度7io

接下來,咱們繼續尋找符合條件的子串,這裏比較關鍵的一點是下一個子串的起始位置,這裏咱們將from直接跳到了序號爲7的位置,由於包含ss的子串顯然都不能知足要求。

而後咱們依照以前的方法,找到第二個候選的子串sohand,長度爲6,比目前的最大子串長度小,因此不是目標子串。

接着繼續尋找,找到另外一個候選子串ohands,長度小於最大子串長度,不是咱們的目標子串。

繼續尋找。

to到達了字符串末尾,找到另外一個候選子串handsome,長度大於最大子串長度,這就是咱們的目標子串。

因而咱們的最大子串長度就輕鬆加愉快的找到了。接下來的事情就是把上面的思路轉化成代碼。

這裏只須要注意一下from的跳轉便可,每次跳轉的序號爲to指向的字符在子串中出現的位置 + 1。

常規解法

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) return 0;
        int from = 0, to = 1, length = 1, maxLength = 1;
        // to遍歷直到字符串末尾
        while (to < s.length()){
            int site = s.substring(from, to).indexOf(s.charAt(to));
            if (site != -1){
                // to指向的字符已存在
                length = to - from;
                if (length > maxLength) maxLength = length;
                // from 跳轉到site+1的位置
                from = from + site + 1;
            }
            to++;
        }
        // 處理最後一個子串
        if (to - from > maxLength) {
            maxLength = to - from;
        }
        return maxLength;
    }
}

這裏沒有什麼騷操做,考慮好邊界狀況就好了。有一個小細節須要注意,site表明的是子串中字符出現的位置,不是原字符串中的位置,所以from在跳轉時,須要加上自身原來的序號。還有最後一個子串的處理不要忘記,由於當to遍歷到字符串末尾時,會結束循環,最後一個子串將不會在循環內處理。

讓咱們提交一下:

擊敗了73%的用戶,還不錯。

常規解法優化

想一想看,還有沒有優化的空間呢?

那確定是有的,首先咱們想想,當咱們找到的最大子串長度已經比from所在位置到字符串末尾的位置還要長了,那就沒有必要再繼續下去了。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) return 0;
        int from = 0, to = 1, length = 1, maxLength = 0;
        // to遍歷直到字符串末尾
        while (to < s.length()){
            int site = s.substring(from, to).indexOf(s.charAt(to));
            if (site != -1){
                // to指向的字符已存在
                length = to - from;
                if (length > maxLength) {
                    maxLength = length;
                }
                // 判斷是否須要繼續遍歷
                if (maxLength > s.length() - from + 1) return maxLength;
                from = from + site + 1;
            }
            to++;
        }
        // 處理最後一個子串
        if (to - from > maxLength) {
            maxLength = to - from;
        }
        return maxLength;
    }
}

另外要處理相似bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb這樣的字符串,上面的方法仍是有很大優化空間的,咱們能夠用一個HashSet來存儲全部元素,利用其特性進行去重,若是找到的子串長度已經等於HashSet中的元素個數了,那就不用再繼續查找了。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) return 0;
        int from = 0, to = 1, length = 1, maxLength = 0;
        Set<Character> set = new HashSet<>();
        for (int i = 0; i < s.length(); i++){
            set.add(s.charAt(i));
        }
        // to遍歷直到字符串末尾
        while (to < s.length()){
            int site = s.substring(from, to).indexOf(s.charAt(to));
            if (site != -1){
                // to指向的字符已存在
                length = to - from;
                if (length > maxLength) {
                    maxLength = length;
                }
                if (maxLength > s.length() - from + 1) return maxLength;
                if (maxLength >= set.size()) return maxLength;
                from = from + site + 1;
            }
            to++;
        }
        // 處理最後一個子串
        if (to - from > maxLength) {
            maxLength = to - from;
        }
        return maxLength;
    }
}

再提交一下:

哈哈哈哈,翻車了,因此這裏引入一個HashSet用空間來換時間的方式不必定合適,看來測試用例裏像bbbbbbbbbbbbbb這樣的用例並很少啊。

那麼今天的翻車就到此爲止了,若是以爲對你有幫助的話記得點個關注哦。

相關文章
相關標籤/搜索