[LeetCode刷题笔记]3 - 无重复字符的最长子串(哈希表 + 双指针)

一、题目描述

  • 给定一个字符串,输出连续的不包含重复字符的子串的最长长度。
  • 请注意子串和子序列的区别:
    • 子串一定是连续的一段;
    • 子序列不一定是连续的一段,但下标要求是递增的;

示例:

输入输出
s = " a b c a b c b b " s = "abcabcbb" s="abcabcbb" 3 3 3
s = " b b b b b " s = "bbbbb" s="bbbbb" 1 1 1
s = " p w w k e w " s = "pwwkew" s="pwwkew" 3 3 3

提示:

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

二、求解思路:哈希表 + 双指针

思路

  • 定义两个指针 i , j ( j < = i ) i,j(j<=i) i,j(j<=i),表示当前扫描到的子串是 [ j , i ] [j,i] [j,i] (闭区间)。
  • 扫描过程中维护一个哈希表 unordered_map<char,int> h ,表示 [ j , i ] [j,i] [j,i]中每个字符出现的次数。
  • 线性扫描的流程:
    • 指针 i i i 向后不断移位遍历字符串每一位字符,同时将哈希表中 s [ i ] s[i] s[i] 的计数加一;
    • 假设 i i i 移动前的区间 [ j , i ] [j,i] [j,i] 中没有重复字符,则 i i i 移动后,只有 s [ i ] s[i] s[i] 可能出现 2 次;
    • 此时,我们不断向后移动 j j j,直至区间 [ j , i ] [j,i] [j,i] s [ i ] s[i] s[i] 的个数等于 1 为止,这样的区间才回再次满足题意;
    • 更新最长的子串长度;

C++代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
         // 哈希表存储每个字符出现的次数
        unordered_map<char, int> h; 
        
        int ans = 0;  // 最长无重复字符子串的长度,即存储输出结果
        for (int i = 0, j = 0; i < s.size(); ++i) {
            ++h[s[i]];  // 把s[i]字符出现的次数加一
            // 当s[i]字符出现次数大于1时,说明加入上一循环[j,i]区间达到最大,需要更新j
            // 更新j:直到s[i]字符次数=1为止,此时的新区间会再次满足题意
            while (j < i && h[s[i]] > 1) --h[s[j++]];
            ans = max(ans, i - j + 1);  // 更新ans为最大值
        }

        return ans;
    }
};

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PanyCG_pc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值