LeetCode 3 Longest Substring Without Repeating Characters

Solution

1 Brute Force

  1. 注意:
    子串(substring)指的是字符串中几个连续 的字符组成的字符串。
    子序列(subsequence)指的是字符中几个顺序但不一定连续 的字符组成的字符串。
  2. Intuition:先考虑如何检查一个字符串中是否有重复字符。检查字符串的每个子串是否有重复字符,如果没有则记录其长度。
  3. Algorithm: 假设有个函数boolean allUnique(String substring) 用来判断一个字符串是否有重复字符。
    那么如何检查每个子串?只要确定了起始的indice和终止的indice就确定了一个子串。
    那么如何判断一个字符串是否有重复字符?可以用set,set中不能包含两个相同元素。
  4. Runtime BF算法会超时
  5. 时间复杂度: O(n3) O ( n 3 ) ,见题目solution分析
  6. 空间复杂度:需要对子串进行存储,需要的空间是 O(k) O ( k ) ,k就是Set 的尺寸,Set的尺寸取决于字符串长度n和字符集(chasrset)大小m(字符串中的字符取自多大的字符集,即最多有多少个无重复字符)。所以空间复杂度为 O(min(n,m)) O ( m i n ( n , m ) )

2 Sliding Window

  • Algorithm
    暴力很直接(我竟然也没思路。。。),但是太慢,所以如何去优化?
    用暴力方法时,我们重复的检查一个子串来看是否有重复子串。但是这是没必要的。如果子串 Sij S i j 中的第i个字符到第j-1个字符的组成的子串已经确认过没有重复字符,我们只需要确认字符 S[j] S [ j ] 是否已经在子串中。
    检查一个字符是否已经在子串中,需要扫描子串,时间复杂度为 O(n2) O ( n 2 ) 。如果使用HashSet 作为滑动窗口,复杂度为 O(1) O ( 1 )
    A sliding window 是一个经常在 数组/字符串(array/string) 问题中经常使用的抽象概念。一个窗口是由起始索引和结束索引定义的一系列元素(左闭右开)。一个滑动窗口是指窗口的两个边界向特定方向“滑动”。比如将窗口边界 [i,j) [ i , j ) 向右移动一个元素,边界就变成了 [i+1,j+1) [ i + 1 , j + 1 ) (左闭右开)。
    回到本题目,使用HashSet来储存当前窗口 [i,j) [ i , j ) 的字符。然后将j向右移动,如果新字符没有在HashSet中,则继续右移,直到 S[j] S [ j ] 已经在字符中了。此时,我们就找出了以i为为起始索引的最大无重复子串。对i进行遍历,即可得到结果。

    • 总结:思路是先考虑到暴力时,判断一个子串有无重复元素时,是直接对该子串进行判断,但该子串的子串可能已经是判断过的,所以就会做重复的工作。那么如何避免做重复的工作? 在滑动窗口的概念中,先固定起始索引,令结束索引右移,如果窗口中有了重复字符,则没有必要再右移结束索引。
    • 滑动窗口的思路适用于 数组/字符串 中的连续元素问题。
    • 时间复杂度:

3 Sliding Window Optimized

  • 对第二种方法进行优化,考虑到在第二步中对窗口进行检查时,固定起始索引,右移结束索引直到字符已经在窗口中重复出现,之后要右移起始索引,注意第二种方法中是将起始索引右移了1个元素,但是其实可以右移多个元素,直到出现重复字符。
    看solution的说明比较详细。
  • 虽然思路是这样,但是看给的代码还是没懂。代码中实现的方式是,用i,j 表示窗口的起始和结束,这个窗口是抽象的,并没有将元素加入map中。同时,j 不断加1,求 j 对应的无重复子串的起始索引 i 。如何求? 当j 右移时,判断元素s[j] 之前是否出现过(在迭代时,将每个元素(key)和对应索引(value)都加入了map中),使用count()find() 可以查到。当出现重复元素时,判断是否更新i 为该元素在之前最后出现时的索引(即该元素在map中对应的value),如果i要更新的值大于i (即起点如果不需要后移,则不更新起点),并且更新map中该元素对应的索引,使其保持为最大。此时i 则表示无重复子串的起点。

相关知识点

c++ set

  • count(const key_type &key ); 返回值为key 的元素的个数(0或1),set中没有重复元素,返回值为0或1。

感觉这么总结也太慢了,之后只总结知识点,思路还是直接去原地址看吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值