利用字符指针将字符串s中从第n个字符开始的内容复制到字符串t中_【每周算法】无重复字符的最长子串...

写在前面: 又到周一了,上周借助 最短子数组,我们一起学习了算法面试频率非常高的 “双指针法”,今天我们同样借助一个高频面试题 最长子串问题,来学习另一个非常重要的经典算法 “滑动窗口”。新的一周,新的开始,让我们开始本周的算法养成。
小晶:【每周算法】长度最小的子数组​zhuanlan.zhihu.com
e987be0b3420f8ab4f8fa39b4f65cb7f.png

题目描述

给定一个字符串,请你出其中不含有重复字符的最长子串的长度。难度:mid示例 1:

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

示例 2:

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

示例 3:

输入: "pwwkew"
输出: 3   
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。

题解

滑动窗口

首先解释下什么是滑动窗口。滑动窗口,顾名思义就是一个窗口从一侧滑动到另外一侧,并且绝不来回震动。也就是只遍历一此,每个元素最多访问两次(左右边均滑动过去),即时间复杂度为O(n)
了解了什么是滑动窗口,我们再来看本题。时间复杂度O(n)空间复杂度O(∣Σ∣)
假设我们选择字符串中的第 k 个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为 r_k。那么当我们选择第 k+1 个字符作为起始位置时,首先从 k+1r_k 的字符显然是不重复的,并且由于少了原本的第 k 个字符,我们可以尝试继续增大 r_k,直到右侧出现了重复字符为止。

class Solution:
    # 我们使用两个变量表示字符串中的某个子串(左右边界)。
    # 遍历字符串s,在每一步的迭代中,我们会将左指针向右移动一格,
    # 表示 我们开始枚举下一个字符作为起始位置,然后我们可以不断地向右移动右指针,但需要保证这两个指针对应的子串中没有重复的字符。
    # 在移动结束后,这个子串就对应着 以左指针开始的,不包含重复字符的最长子串。我们记录下这个子串的长度;
    # 在枚举结束后,我们找到的最长的子串的长度即为答案。
    def len_of_longest_sub_str_1(self, s: str) -> int:
        # 哈希集合,记录每个字符是否出现过
        right, max_sub_str_len = 0, 0
        sub_s_set = set()
        len_s = len(s)

        for left in range(len_s):
            if left != 0:
                # 左指针向右移动一格,移除一个字符
                sub_s_set.remove(s[left - 1])
            while right < len_s and s[right] not in sub_s_set:
                # 不断地移动右指针
                sub_s_set.add(s[right])
                right += 1
            # 第 left 到 right 个字符是一个极长的无重复字符子串
            max_sub_str_len = max(max_sub_str_len, right - left)
        return max_sub_str_len

时间复杂度很好解释,我们来理解下空间复杂度O(∣Σ∣)。其中 Σ 表示字符集(即字符串中可以出现的字符),∣Σ∣ 表示字符集的大小。因为我们要用set来存储出现过的字符,而字符最多有∣Σ∣ 个,因此空间复杂度为 (∣Σ∣)

HashMap 优化

看到len_of_longest_sub_str_1这个函数名你们一定能够猜到,这么经典的题,一定不止探究一种解法。没错,其实本题完全可以不用set,我只是想借本题让大家掌握滑动窗口
学会滑动窗口,您可以高兴的离开了,但如果恰好您也了解C++/Java中的hashmap,这里我们以hashmap思想用Python实现(python没有hashmap,但知识是相通的,再一次感叹Python的易用程度),我们会看到Python不仅简化了代码,就连空间复杂度也降低了。时间复杂度O(n)空间复杂度O(1)

def len_of_longest_sub_str_2(self, s: str) -> int:
        left, sub_str_len, max_sub_str_len = 0, 0, 0
        len_s = len(s)

        for right in range(len_s):
            # 仅当s[left, right) 中存在s[right]时更新left
            temp_char_index = s.index(s[right], left, right + 1)
            if temp_char_index != right:
                left = temp_char_index + 1
                sub_str_len = right - left

            sub_str_len += 1
            max_sub_str_len = max(max_sub_str_len, sub_str_len)
        return

太棒了,本周还没开始,我们的每周算法任务就完成了!最后分享一个坚持的动力:

无志之人常立志,有志之人立长志

欢迎大家关注我,和我一起坚持学习【每周算法】,直到将坚持养成像吃饭喝水一样的习惯。另外有问题大家评论区讨论,积极沟通。如果本文对你有帮助,不要忘记点赞收藏,克服拖延,拒绝伸手党!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值