1. 程式人生 > >LeetCode 無重復字符的最長子串

LeetCode 無重復字符的最長子串

第一次 auto 編寫 class 記錄表 一次 alt sta 開始

題目

給定一個字符串,找出不含有重復字符的最長子串的長度。
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 無重復字符的最長子串是 "abc",其長度為 3。
示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 無重復字符的最長子串是 "b",其長度為 1。
示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 無重復字符的最長子串是 "wke",其長度為 3。
請註意,答案必須是一個子串,"pwke" 是一個子序列 而不是子串。

分析

暴力算法

/*
    C++代碼
*/
public class Solution {
    public int lengthOfLongestSubstring(string s) {
        int n = s.length();
        int ans = 0;
        for (int i = 0; i < n; i++){
            for (int j = i + 1; j <= n; j++){
                if (allUnique(s, i, j)) {
                    ans = std::max(ans, j - i);
                }
            }
        }
        return ans;
    }

    public bool allUnique(string s, int start, int end) {
            set<char> m_set;      
            for (int i = start; i < end; i++) {
                if (m_set.find(s[i]) == m_set.end()){
                    return false;
                }
                m_set.insert(s[i]);
        }
        return true;
    }
}

我們可以很輕易地編寫一個暴力求解的算法,逐個地檢查所有的字串是否存在重復的字母,枚舉出所有字串的索引範圍(下標範圍)的時間復雜度O(n^2),遍歷一遍字串的時間復雜的為O(n)。算法總時間復雜度為O(n^3)。這種復雜度是不被接受的。我們需要更快的方法.

暴力算法慢在哪裏?

我們設想有這麽一個字符串abcdeafagh,使用暴力算法的求解過程見下圖
技術分享圖片
從圖中可以看出算法多次掃描bcdeafa這一範圍內的子串,但是除了第一次的掃描,但是真正有用的掃描只有一次,也就是第一次,確定了長度為6的子串bcdeaf。肉眼可以輕易地發現後續就沒有必要重復掃描了,應該在第二次掃描的時候直接從f開始掃描是最好的。暴力算法把大量的時間浪費在無意義的掃描上。我們需要重點解決這個問題。

如何解決

我們需要知道當匹配到一個重復字符的時候下次掃描從哪裏開始。這樣可以省下大量的時間。我們可以每掃描到一個字符就記錄這個字符的位置,當匹配到一個相同的字符的時候,通過查詢這個字符之前出現的位置,我們把下次掃描的開始位置定位到該重復字符上次出現的位置的下一個位置,過程見下圖
技術分享圖片

代碼實現

/*
    C++代碼
*/
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> map;
        auto itor = map.end();
        int max = 0, length = 1;
        if (s.length() <= 1){
            return s.length();
        }
        map.insert(pair<char,char>(s[0],0));
        
        for (int i = 1; i < s.length();){
            itor = map.find(s[i]);
            //如果該字符之前出現過
            if(itor != map.end()){
                //跳轉到該字符上次出現的位置的下一個位置
                i = itor->second + 1;
                //清空字符位置記錄表
                map.clear();
                map.insert(pair<char,char>(s[i],i));
                max = std::max(max, length);
                length = 1;
                i++;

            }
            else{
                map.insert(pair<char,char>(s[i],i));
                length++;
                i++;
            }
        }
        
        max = std::max(max, length);
        return max;
    }
};

LeetCode 無重復字符的最長子串