【Leetcode】無重複字符的最長子串

 

 

暴力解法,枚舉全部子字符串組合html

輸入:長度[0,n]的字符串數組

耗時過長---優化

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.size();
        int ans = 1;
        
        if(s.empty()){
            return 0;
        }
        
        for(int i = 0; i < len-1; i++){
            for(int j = i+1; j < len; j++){
                if(allUnique(s, i, j)){
                    ans = max(ans, j-i+1);
                }
            }
        }
        return ans;
    }
    
    bool allUnique(string ss, int start, int end){
        std::set<char> ss_set;
        for(int i = start; i <= end; i++){
            char ch = ss[i];
            if(ss_set.count(ch)){
                return false;
            }
            ss_set.insert(ss[i]);
            
        }
        return true;
    }
};

 

第二種方法:改進暴力解法spa

子字符串爲[i,j),左閉右開。一旦檢測到新加入字符已存在於已有子字符串中,則返回當前子字符串長度,清空子字符串,左邊界右移(i+1),從新生成新的子字符串。code

依然耗時過長htm

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.size();
        std::cout << "len is : " << len << std::endl;
        int ans = 1;
        std::set<char> ss_set;
        int begin = 0;
        
        if(s.empty()){
            return 0;
        }
        else{
            
            while(begin < len-1) {
                //std::cout << "begin is : " << begin << std::endl;
                int tmp = 0;
                ss_set.clear();
                for(int j = begin; j < len; j++){
                    if(ss_set.count(s[j])){
                        break;
                    }
                    ss_set.insert(s[j]); 
                    tmp++;
                }
                begin = begin + 1;
                ans = max(ans, tmp);
            }
            
        }
        return ans;
    }

};

 

第三種:滑窗法blog

改進第二種方法。子字符串爲[i,j),左閉右開。一旦檢測到新加入字符已存在於已有子字符串中,則返回當前子字符串長度,刪除begin位置的字符,窗口右移(i+1,count-1),新加入字符與窗口中的元素進行對比。索引

耗時94ms,消耗內存21.3MB內存

TIP字符串

1. 經過使用 HashSet 做爲滑動窗口,咱們能夠用 O(1) 的時間來完成對字符是否在當前的子字符串中的檢查;

2. 滑動窗口是數組/字符串問題中經常使用的抽象概念。 窗口一般是在數組/字符串中由開始和結束索引定義的一系列元素的集合,即 [ij)(左閉,右開)。而滑動窗口是能夠將兩個邊界向某一方向「滑動」的窗口。例如,咱們將 [ij) 向右滑動 11 個元素,則它將變爲 [i+1,j+1)(左閉,右開)。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.size();
        std::set<char> ss_set;
        int ans = 1, begin = 0, count = 0, index = 0;
        set<char>::const_iterator iter;
        
        if(s.empty()){
            return 0;
        }
        else{
            
            while(begin < len-1) {
                
                for(int j = index; j < len; j++){
                    if(ss_set.count(s[j])){
                        index = begin + count;
                        break;
                    }
                    ss_set.insert(s[j]); 
                    count++;
                }
                
               // for(iter = ss_set.begin(); iter != ss_set.end(); iter++){
               //     std::cout << *iter << " " ;
               // }
               // std::cout << std::endl;
                
                ss_set.erase(s[begin]);
                begin = begin + 1;
                ans = max(ans, count);
                count = count - 1;
            }
        }
        return ans;
    }

};

 

滑窗法比較清晰的表達,引入變量i,j表示窗口的範圍。

注意 i++ 和 ++i 的區別

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.size();
        std::set<char> ss_set;
        int ans = 1, i = 0, j = 0;if(s.empty()){
            return 0;
        }
        else{
            while(i < len && j < len){
                if(!ss_set.count(s[j])){
                    ss_set.insert(s[j++]);
                    ans = max(ans, j-i);
                }
                else{
                    ss_set.erase(s[i++]);
                }
            }
        }
        return ans;
    }

};

 

優化滑窗法

咱們能夠定義字符到索引的映射,而不是使用集合來判斷一個字符是否存在。 當咱們找到重複的字符時,咱們能夠當即跳過該窗口。

也就是說,若是 s[j] 在 [i,j) 範圍內有與 j′ 重複的字符,咱們不須要逐漸增長 i 。 咱們能夠直接跳過 [ij] 範圍內的全部元素,並將 ii 變爲 j' + 1j+1。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = s.size();
        int ans = 0, i = 0, j = 0;
        map<char, int> str_map;
        
        for(j; j < len; j++){
            if(str_map.count(s[j])){
                i = max(i, str_map.find(s[j])->second);
            }
            
            ans = max(ans, j - i + 1);
            str_map[s[j]] = j+1;  //窗口右邊界右移
            
        }
        return ans;
    }

};
相關文章
相關標籤/搜索