LeetCode OJ 3 Longest Substring Without Repeating Characters 小结

来源:互联网 发布:红蜘蛛多媒体软件 编辑:程序博客网 时间:2024/06/06 07:46

Longest Substring Without Repeating Characters

Question

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.

解题思路

这道题目, 一开始我们想简单了, 于是死活各种WA, 本来我们想, 使用一个hashmap, 存储到现在为止的所有字符, 在遍历字符串的过程中, 如果发现该字符在hashmap中已经出现过了, 就更新一下, 字串的开始位置, 同时清空hashmap, 并且将新的起始位置处的字符重新压入, 这样时间复杂度 O(n2)
但是, 这种方法太慢了, 超时了。 后来, 看了大神们的代码, 发现这其实是一个DP问题, 具体可见大神的代码部分

自己的代码

AC 代码

算法复杂度 O(n2)

class Solution {public:    int lengthOfLongestSubstring(string s) {        vector<int> mymap(255, -1);        int len = 0;        int sublen = 0;        int begin = 0;        int cur = 0;        for (; cur != s.size(); cur++)        {            // 遇到已有字符的处理, 更新长度, 清空相应到新起始位置的所有记录, 更新 新的起始位置, 当然,我们后来发现, 起始可以用 mymap[s[cur]] > begin, 来判断新的读取字符是否在当前处理的字串范围内!!!            if (mymap[s[cur]] != -1)            {                len = sublen > len ? sublen : len;                for (int i = begin; i != mymap[s[cur]]; i++)                {                    mymap[s[i]] = -1;                }                               begin = mymap[s[cur]] + 1;                sublen = cur - begin;               }            mymap[s[cur]] = cur;            sublen++;        }        len = sublen > len ? sublen : len;        return len;    }};

TLE code

这段代码在最后一组测试数据的时候超时了, 虽然还是能够算出结果, 不过就是AC不了!!!

class Solution {public:    int lengthOfLongestSubstring(string s) {        unordered_map<char, string::iterator> mymap;        int len = 0;        int sublen = 0;        string::iterator pbegin = s.begin();        string::iterator pCur = s.begin();        for (; pCur != s.end(); pCur++)        {            auto item = mymap.find(*pCur);            if ( item != mymap.end())            {                mymap.clear();                len = sublen > len ? sublen : len;                for (; *pbegin != *pCur; pbegin++);                pbegin++;                for (string::iterator iter = pbegin; iter != pCur; iter++)                {                    mymap[*iter] = iter;                }                sublen = mymap.size();            }            mymap[*pCur] = pCur;            sublen++;        }        len = sublen > len ? sublen : len;        return len;    }};

大神们的代码

demo1

基于 DP 思想

class Solution {public:    int lengthOfLongestSubstring(std::string s) {        std::vector<int> flag(256, -1);        int start = 0, longest = 0;        for (int i = 0; i != s.size(); ++i) {            start = std::max(start, flag[s[i]] + 1);            flag[s[i]] = i;            longest = std::max(longest, i - start + 1);        }        return longest;    }};

demo2

这段代码没有demo1 精炼, 但是思路清晰

class Solution {public:    int lengthOfLongestSubstring(string s) {        int last[256];        int maxSize = 0;        memset(last, -1, sizeof(last));        int beginPos = 0;        for (int lastPos = 0; lastPos < s.size(); lastPos++) {           if (last[s[lastPos]] < beginPos) {               maxSize = max(maxSize, lastPos-beginPos+1);           } else {               beginPos = last[s[lastPos]] + 1;           }           last[s[lastPos]] = lastPos;        }        return maxSize;    }};

demo3

这段代码和 demo1 类似, 不过给出了 DP的思路分析

/** * Solution (DP, O(n)): *  * Assume L[i] = s[m...i], denotes the longest substring without repeating * characters that ends up at s[i], and we keep a hashmap for every * characters between m ... i, while storing <character, index> in the * hashmap. * We know that each character will appear only once. * Then to find s[i+1]: * 1) if s[i+1] does not appear in hashmap *    we can just add s[i+1] to hash map. and L[i+1] = s[m...i+1] * 2) if s[i+1] exists in hashmap, and the hashmap value (the index) is k *    let m = max(m, k), then L[i+1] = s[m...i+1], we also need to update *    entry in hashmap to mark the latest occurency of s[i+1]. *  * Since we scan the string for only once, and the 'm' will also move from * beginning to end for at most once. Overall complexity is O(n). * * If characters are all in ASCII, we could use array to mimic hashmap. */int lengthOfLongestSubstring(string s) {    // for ASCII char sequence, use this as a hashmap    vector<int> charIndex(256, -1);    int longest = 0, m = 0;    for (int i = 0; i < s.length(); i++) {        m = max(charIndex[s[i]] + 1, m);    // automatically takes care of -1 case        charIndex[s[i]] = i;        longest = max(longest, i - m + 1);    }    return longest;}

demo 4

这位大神, 没有使用vector, 而是使用了boost库中的 hash_map, 同样达到了效果

class Solution {    public:        int lengthOfLongestSubstring(string s) {            if(s.size()<2) return s.size();            int d=1, maxLen=1;            unordered_map<char,int> map;            map[s[0]]=0;            for(int i=1;i<s.size();i++)            {                if(map.count(s[i])==0 || map[s[i]]<i-d)                    d++;                else                    d= i- map[s[i]];                map[s[i]]=i;                if(d>maxLen)                    maxLen = d;            }            return maxLen;        }    };
0 0
原创粉丝点击