【LeetCode-滑动窗口】最长不含重复字符的子字符串

题目描述

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

说明:

  • s.length <= 40000;
  • 这题是《剑指Offer》的第 28 题;

题目链接: https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/

思路1

使用滑动窗口来做。窗口的范围为 [left, right],left,right 初始化为0。设置一个查找表 lookup,lookup 存储了当前窗口中的元素。right 先移动,如果 s[right] 不在 lookup 中,则 right++,maxLen++,将 right 加入 lookup 中;否则,将 s[left] 从 lookup 中移除(注意这里不是先移除重复的元素 s[right],因为先移除 s[right] 的话就不满足连续子串这个要求了),将 left++,直至 s[right] 不在 lookup 中出现。代码如下:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.empty()) return 0;

        unordered_set<char> lookup;
        int left = 0;
        int right = 0;
        int maxLen = 1; // 初始化为 1
        while(right<s.size()){
            if(lookup.count(s[right])==0){ // s[right]不在lookup中出现
                lookup.insert(s[right]);  // 先 insert,再将 right++
                right++;
                maxLen = max(maxLen, right-left);
            }else{
                if(!lookup.empty()){
                    lookup.erase(s[left]);
                    left++;                    
                }   
            }
        }
        return maxLen;
    }
};

思路2

在思路 1 中,当遇到了重复字符,我们一步一步地移动 left 指针。为了加快速度,我们可以直接将 left 移动到当前 right 的位置上。
代码如下:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.empty()) return 0;

        vector<int> v(128, -1);
        int left = -1;
        int maxLen = 1;
        for(int right=0; right<s.size(); right++){
            char c = s[right];
            if(v[c]!=-1) left = max(left, v[c]);   // c 出现在了窗口中
            v[c] = right;
            maxLen = max(maxLen, right-left);
        }
        return maxLen;
    }
};
posted @ 2020-06-28 23:28  Flix  阅读(215)  评论(0编辑  收藏  举报