LintCode 384: Longest Substring Without Repeating Characters (字符串处理经典题)

本文探讨了多种解决最长无重复子串问题的算法,包括使用哈希表、双指针技巧等,提供了详细的代码实现及优化过程,适用于挑战级O(n)时间复杂度要求。

LintCode 384. Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters.

Example
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.

Challenge
O(n) time

解法1:
思路:

  1. 用table[s[i]] = i记录每个字符上次出现的位置。
  2. 当table[s[i]] >= 0时说明s[i]重复出现。
  3. 用指针pos表示当前segment开始位置。
  4. 当table[s[i]] > pos时说明需要考虑从pos到i的这段新segment。

代码如下:

class Solution {
public:
    /**
     * @param s: a string
     * @return: an integer
     */
    int lengthOfLongestSubstring(string &s) {
        int len = s.size();
        if (len == 0) return 0;
        
        vector<int> table(255, -1);
        int pos = 0;
        int maxSegLen = 0;
        
        for (int i = 0; i < len; ++i) {
            if (table[s[i]] >= pos) { //it shows a repetitive char appears and it should be after pos! 
                pos = table[s[i]] + 1;    
            }
            table[s[i]] = i;
            maxSegLen = max(maxSegLen, i - pos + 1); //for both cases: repetitive and non-repetitive
        }
        
        return maxSegLen;
    }
};

解法2:双指针
count[256]存储每个字符在p1…p2窗口内重复次数。一开始p1=0,p2=0。
p2先跑,一直跑到出现某个字符重复次数>1,然后p1再跑,一直跑到p2的那个重复元素为止。每次更新maxLen。

class Solution {
public:
    /**
     * @param s: a string
     * @return: an integer
     */
    int lengthOfLongestSubstring(string &s) {
        int n = s.size();
        vector<int> count(256, 0);
        int p1 = 0, p2 = 0;
        
        int maxLen = 0;
        while(p2 < n) {
            count[s[p2]]++;
            if (count[s[p2]] > 1) {
                while(p1 < p2) {
                    count[s[p1]]--;
                    p1++;
                    if (s[p1-1] == s[p2]) break;   
                }
            }
            maxLen = max(maxLen, p2 - p1 + 1);
            p2++;
        }
        
        return maxLen;
    }
}; 

解法3:
类似解法1和解法2的混合。感觉搞得更复杂了。

class Solution {
public:
    /**
     * @param s: a string
     * @return: an integer
     */
    int lengthOfLongestSubstring(string &s) {
        int n = s.size();
        if (n <= 1) return n;
        vector<int> positions(256, -1);
        
        int p1 = 0, p2 = 0;
        int maxLen = 0;
        while(p2 < n) {
            while (p2 < n && positions[s[p2]] < 0) {
                positions[s[p2]] = p2;
                p2++;
            }
            
            if (p2 < n && positions[s[p2]] >= 0) {
               // maxLen = max(maxLen, p2 - positions[s[p2]]);
                maxLen = max(maxLen, p2 - p1);
                p1 = max(p1, positions[s[p2]] + 1);
                
                positions[s[p2]] = p2;
                p2++;
            }
        }
        maxLen = max(maxLen, p2 - p1);
        return maxLen;
    }
};

代码同步在:
https://github.com/luqian2017/Algorithm

四刷:用一个freqs数组表示某字母存过没有。

class Solution {
public:
    /**
     * @param s: a string
     * @return: an integer
     */
    int lengthOfLongestSubstring(string &s) {
        int len = s.size();
        vector<int> freq(256, 0);
        int right = 0;
        int maxLen = 0;
        for (int i = 0; i < len; i++) {
            while (right < len && freq[s[right]] == 0) {
                freq[s[right]]++;
                right++;
            }

            if (right >= len) {
                maxLen = max(maxLen, right - i);
                break;
            }
            if (freq[s[right]] > 0) {
                maxLen = max(maxLen, right - i);
            }
            freq[s[i]]--;
        }
        return maxLen;
    }
};
简化后为:

```cpp
int lengthOfLongestSubstring(string &s) {
        int len = s.size();
        vector<int> freq(256, 0);
        int right = 0;
        int maxLen = 0;
        for (int i = 0; i < len; i++) {
            while (right < len && freq[s[right]] == 0) {
                freq[s[right]]++;
                right++;
            }
            maxLen = max(maxLen, right - i);
            if (right >= len) {
                break;
            }
            freq[s[i]]--;
        }
        return maxLen;
    }

也可以用一个pos数组

class Solution {
public:
    /**
     * @param s: a string
     * @return: an integer
     */
    int lengthOfLongestSubstring(string &s) {
        int len = s.size();
        vector<int> pos(256, -1);
        int right = 0;
        int maxLen = 0;
        for (int i = 0; i < len; i++) {
            while (right < len && pos[s[right]] == -1) {
                pos[s[right]] = right;
                right++;
            }
            maxLen = max(maxLen, right - i);
            if (right >= len) {
                break;
            }
            pos[s[i]] = -1;
        }
        return maxLen;
    }
};

五刷-套用同向双指针模板

```cpp
class Solution {
public:
    /**
     * @param s: a string
     * @return: an integer
     */
    int lengthOfLongestSubstring(string &s) {
        int len = s.size();
        int i, j = 0;
        vector<int> freq(256);
        int res = 0;
        for (i = 0; i < len; i++) {
            j = max(i, j);
            while (j < len && freq[s[j]] == 0) {
                freq[s[j]]++;
                j++;
            }
            res = max(res, j - i);
            freq[s[i]]--;
        }
        return res;
    }
};

六刷: 还是滑动窗口。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        vector<int> count(128, 0);
        int dupCount = 0;
        int p1 = 0, p2 = 0, res = 0;
        while (p2 < n) {
            char c = s[p2];
            if (count[c] > 0) {
                dupCount++;
            }
            count[c]++;
            p2++;
            while (dupCount > 0) {
                c = s[p1];
                count[c]--;
                if (count[c] == 1) dupCount--;
                p1++;                
            }
            res = max(res, p2 - p1);
        }
        return res;
    }
};

上面的可以简化,不需要dupCount,实际上根据 while (count[c] > 1) 来决定收缩左指针就可以了。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        vector<int> count(128, 0);
        int p1 = 0, p2 = 0, res = 0;
        while (p2 < n) {
            char c = s[p2];
            count[c]++;
            p2++;
            while (count[c] > 1) {
                char c2 = s[p1];
                count[c2]--;
                p1++;                
            }
            res = max(res, p2 - p1);
        }
        return res;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值