【滑动窗口】leetcode 3. 无重复字符的最长子串

3. 无重复字符的最长子串

题目描述

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例1:

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

示例2:

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

示例3:

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

提示

  • 0 < = s . l e n g t h < = 5 ∗ 1 0 4 0 <= s.length <= 5 * 10^4 0<=s.length<=5104
  • s 由英文字母、数字、符号和空格组成

方法:滑动窗口

解题思路

假设我们选择字符串中的第 k 个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为 r k r_k rk​ 。那么当我们选择第 k+1 个字符作为起始位置时,首先从 k+1 到 r k r_k rk 的字符显然是不重复的,并且由于少了原本的第 k 个字符,我们可以尝试继续增大 r k r_k rk,直到右侧出现了重复字符为止。
判断重复字符的方法
使用一种数据结构来判断 是否有重复的字符,常用的数据结构为哈希集合,即 C++ 中的 std::unordered_set,在左指针向右移动的时候,我们从哈希集合中移除一个字符,在右指针向右移动的时候,我们往哈希集合中添加一个字符。

代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        unordered_set<char> occ;
        // 右指针,初始值为 -1
        // 相当于在字符串的左边界的左侧,还没有开始移动
        int rk = -1;
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            if(i != 0)
            {
            	// 左指针向右移动一格,移除一个字符
                occ.erase(s[i - 1]);
            }
            while(rk + 1 < n && !occ.count(s[rk + 1]))
            {
            	// 不断地移动右指针
                occ.insert(s[rk + 1]);
                rk++;
            }
            ans = max(ans, rk - i + 1);   
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(| Σ \Sigma Σ|)。,其中 Σ \Sigma Σ 表示字符集(即字符串中可以出现的字符),| Σ \Sigma Σ| 表示字符集的大小。

你可能感兴趣的:(#,滑动窗口,算法之路,#,双指针,leetcode,算法)