[M双指针] lc3. 无重复字符的最长子串(双指针+哈希)

本文介绍使用双指针算法解决LeetCode上无重复字符最长子串问题的方法。通过优化传统暴力算法,达到O(n)的时间复杂度。文章详细解释了如何通过维护一个滑动窗口并利用哈希表来跟踪字符的出现频率。

1. 题目来源

链接:lc3. 无重复字符的最长子串

2. 题目解析

方法一:双指针

很经典的一个双指针算法。如何将一个暴力算法优化成双指针算法呢?主要是需要找到单调性。简单聊一下从暴力到双指针的这个过程:

  • 暴力算法: 两层循环,枚举第 i 个位置的字母,再枚举 [0, i] 位置,这样就能枚举得到以 i 位置结尾的所有子串。将合法的子串记录下来,长度取个 max 即可。时间复杂度是 O ( n 2 ) O(n^2) O(n2) 的。
  • 双指针算法: 假设子串终点位置为 i,那么一定有一个最靠左的子串起点 j 与当前这个 i 位置一一对应。当 i 向后移动时,j 就不可能再向前移动了,因为若 j - 1i + 1 构成了合法情况。那么,j - 1 也一定能和 i 构成合法情况。这个违反了 j 的定义。故 j 实际上是不可能再向前移动的,它最多只能保持不动或者发生重复情况向后移动。故 j 具有单调性。那么当我们顺序枚举 i 时,起初 ij 都在首字符,即起点 0 的位置,当 i ++ 时,若不发生重复,则 j 不需要向后移动。若发生重复,则只可能是 s[i] 这个字符和 s[j~i - 1] 这个区间中的某个字符发生重复,因为 j 不能向前移动!所以,就一直向后移动 j,直至找到当前 i 位置的最靠左的 j 位置,即对于 i 的最佳且合法的子串起点位置。

这个是很经典很经典的双指针算法。十分有利于理解双指针算法的本质,且思路并不是那么好想。很值得学习~

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

代码:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> hash;
        int res = 0;
        for (int i = 0, j = 0; i < s.size(); ++i) {
            // 将当前字符添加进哈希表中
            hash[s[i]]++; 
            // 双指针如果哈希表中字符重复出现了,只可能是s[i]重复
            // 就将j指针一直向前删除,直到删了这个重复字符
            // 并将该重复字符在哈希表的数量减1
            // 精髓在于 hash[s[j++]]--;  哈希表维护[j,i]区间内的所有字符的出现次数,实现O(1)的查找
            while (um[s[i]] > 1) hash[s[j++]]--;
            res = max(res, i - j + 1);
        }
        return res;
    }
};

2024年08月23日03:07:17
更新:这个时候,这题的思路已经是如此自然。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        int res = 0;
        unordered_map<char, int> um;

        for (int l = 0, r = 0; r < n; r ++ ) {
            um[s[r]] ++ ;
            // 这里写不写这个 l<=r,取不取等号也无所谓的
            // 因为当 l==r 时,um[s[r]] 必然为 1,就是它自身
            // 必然不会再次进入 while,造成 l++ 的越界行为 
            while (l <= r && um[s[r]] > 1) um[s[l ++ ]] -- ; 
            res = max(res, r - l + 1);
        }

        return res;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

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

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

打赏作者

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

抵扣说明:

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

余额充值