【LeetCode 3. 无重复字符的最长子串】 哈希 区间维护 O(n)算法

在这里插入图片描述
这道题刚拿过来,可能一开始想就会掉坑里,或者是有情况漏了没有考虑。
下面说一下思路和一般人可能会遇到的问题。
1.题目问的是“子串”,而不是子序列
子串必须是连续的,而子序列只要满足在原串先后关系就行了。
比如pwwke的子串wke,而pke就只能算是子序列了。

2.明白了这个,那就要解决区间连续的问题了。这里采用哈希表,key存储当前遍历到字符,而value来存储对应下标,这样的好处就是如果我们遍历到一个已经出现过的字符,它肯定已经被存到哈希表中了,那只需要拿当前下标i-len(当前区间长度)就知道区间的开始位置,从而判断之前出现过的那个字符对应value(即下标)在不在我这个区间里面就行了。这样就不需要双指针来维护区间左右端点了。

3.如果之前出现过的字符位置在区间里面,比如abcbd,遍历到第二个b的时候,发现对应Map[b]=1,即出现在下标为1的位置,而当前len(区间长度)为3(abc),当前遍历的下标i=3,i - len=0,即是从下标为0的地方开始到i-1的区间所以前一个b出现的位置是在这个区间内的。那么这个区间便要重新更新,因为不可能越过当前遍历到的这个b,所以我们就用一个max来对比每次区间不能再往前时的len,比max大的话就存进max中,然后进行下一次区间维护。拿这个例子来说,len需要从上一个b出现的位置后面开始,当做一次新的区间左端点,即是c的位置,而长度就是上一个字符后面一个元素,到当前的位置的长度,就是c到后面的b,即是len=2。然后继续下面的遍历,不过要记得把b出现的位置也更新一下,更新成Map[b] = 3。为的是下面遇到b的时候也能有同样的处理。

4.若之前出现过的字符位置不在区间里面,那就并不影响我们的区间,比如taxxabcdt,因为遍历到最后一个t的时候,按上面步骤3的逻辑,在出现两个x的地方已经重新更新了区间,新的区间是从第二个x开始的,而上一个t不在这个区间内,所以可以大胆地把第二个t放进区间内,len++

5 .如果当前遍历到的字符没有出现过,那么直接放进区间即可,你可能会问这样会不会导致不连续?答案是不会,因为只要是重复过的字符,区间会立即更新成以它为右端点的,所以当未出现的字符出现的时候,只会补充区间,而不会重新更新区间

说了很多,其实代码实现起来也就十几二十行的事情,重要的是想的过程。

代码如下

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        std::map<char,int> mymap;
        int length = s.size();
        if(length==0)  return 0;
        int max1 = 1;
        int len=0;
        for(int i=0;i<length;i++)
        {
             std::map<char,int>::iterator it = mymap.find(s[i]); //看看是不是出现过
             if(it!=mymap.end()&&it->second>=i-len) //若出现过
             {
                    max1 = max(len,max1);    //存一下len,如果比max大的话
                    len = i - (it->second);   //更新一下新的区间
                    mymap[s[i]] = i;    //更新一下当前map的value值,即是字符下标位置
             }
             else   //如果当前字符没出现过
             {
                       mymap[s[i]] = i;  //只管存就完事了
                       len++;
             }
        }
        max1 = max(max1,len);   //最后将最后一步得到的len对比一下

        return max1;   //返回
    }
};
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值