最长无重复子数组

1,231 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

本文同时参与 「掘力星计划」  ,赢取创作大礼包,挑战创作激励金

最长无重复子数组

问题描述

给定一个数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组。

示例

输入:[2,2,3,4,8,99,3]

返回值:5

说明:[2,3,4,8,99]是最长子数组

分析问题

在开始之前,我们首先介绍一下什么是滑动窗口。顾名思义,所谓的滑动窗口就是可以在一个序列上进行滑动的窗口。如图所示,假设,我们的序列为abcabcbb,我们这里定义了一个固定大小为3的窗口在序列上滑来滑去。

![image-20210930111730950](/Users/hanlulu/Library/Application Support/typora-user-images/image-20210930111730950.png)

在实际的使用中,我们使用的滑动窗口都是可变长度的。

我们可以使用双指针来维护窗口的开始和结束,通过移动左、右指针来实现窗口大小的改变和窗口的滑动。

我们来看一下题目,题目是求最长无重复元素子数组,如果我们可以求出所有的无重复元素的子数组,那取出最长的不就好了。下面我们来看一下如何求解。我们只需要维护一个在数组中进行滑动的窗口就好。

  1. 开始时2不在窗口中,所以扩大窗口。
  2. 下一个元素2在窗口中出现,所以我们要将出现过的元素及其左边的元素统统移出窗口,即2。
  3. 接下来的元素3、4、8、99都没在窗口中出现过,所有我们把它们都加入到窗口中。
  4. 下一个元素3在窗口出现过,所以我们要移除出现过的元素及其左边的元素,即2,3。

下面我们来看一下代码如何实现。

    if not s:
        return 0
    left = 0
    # 记录每个字符是否出现过
    window = set()
    n = len(s)
    max_len = 0
    for i in range(n):
        #如果出现过,移除重复元素及其左边的元素
        while s[i] in window:
            window.remove(s[left])
            left += 1
        #没出现过,加入window
        window.add(s[i])

        max_len = max(len(window),max_len)
        
    return max_len

时间复杂度是O(n)。