统计只出现一次的最长连续子序列的长度
字数 1514 2025-12-03 20:11:04
统计只出现一次的最长连续子序列的长度
题目描述
给定一个整数数组,我们需要找到最长的连续子序列,要求这个子序列中的所有元素都只出现一次。换句话说,在这个连续子序列中,不能有重复的元素。
例如:
- 输入:[1,2,3,2,1]
- 输出:3
- 解释:最长连续子序列是[1,2,3]或[2,3,2]但[2,3,2]中有重复的2,不符合要求。因此答案是[1,2,3],长度为3。
解题过程
这个问题可以使用线性动态规划结合哈希表(或数组)来高效解决。核心思路是维护一个滑动窗口,窗口内的元素都是唯一的,同时记录每个元素最后一次出现的位置。
步骤1:定义状态
我们定义以下变量:
dp[i]:表示以第i个元素结尾的最长无重复连续子序列的长度。- 或者,我们可以使用双指针(滑动窗口)来避免显式定义dp数组,但为了体现动态规划思想,我们先从状态定义开始。
实际上,更高效的方法是使用滑动窗口,但我们可以用动态规划的思想来理解窗口的移动。
步骤2:状态转移
关键点:当我们遍历到位置i时,我们需要知道当前元素nums[i]上一次出现的位置lastOccurrence。
- 如果
nums[i]之前没出现过,或者上次出现的位置在当前考虑的子序列之前,那么当前子序列可以扩展。 - 如果
nums[i]上次出现的位置在当前子序列内,那么我们需要从上次出现位置的下一个位置开始新的子序列。
更精确的状态转移:
设start表示当前无重复子序列的起始位置(初始为0)。
当我们遍历到i时:
- 查找
nums[i]在start到i-1之间是否出现过(即上次出现位置lastPos是否大于等于start) - 如果出现过,我们需要将
start更新为lastPos + 1 - 当前子序列长度就是
i - start + 1
步骤3:记录元素最后出现位置
我们需要一个哈希表来记录每个元素最后一次出现的位置索引,这样可以在O(1)时间内找到上次出现位置。
步骤4:算法流程
- 初始化哈希表
lastIndex,记录每个数字最后出现的位置 - 初始化
start = 0,表示当前窗口的起始位置 - 初始化
maxLength = 0,记录最大长度 - 遍历数组中的每个元素
nums[i]:- 如果
nums[i]在lastIndex中存在,且其最后出现位置lastPos >= start:- 说明当前元素在窗口内重复了,将
start更新为lastPos + 1
- 说明当前元素在窗口内重复了,将
- 更新
lastIndex[nums[i]] = i - 计算当前子序列长度
currentLength = i - start + 1 - 更新
maxLength = max(maxLength, currentLength)
- 如果
举例验证
以[1,2,3,2,1]为例:
- i=0: num=1, start=0, 长度=1, maxLength=1
- i=1: num=2, start=0, 长度=2, maxLength=2
- i=2: num=3, start=0, 长度=3, maxLength=3
- i=3: num=2, 上次出现在位置1≥start=0, 所以start=2, 长度=2, maxLength=3
- i=4: num=1, 上次出现在位置0<start=2, 所以start不变, 长度=3, maxLength=3
复杂度分析
- 时间复杂度:O(n),只需要遍历一次数组
- 空间复杂度:O(n),用于存储元素最后出现位置的哈希表
这种方法巧妙地结合了动态规划的思想和滑动窗口的技巧,高效地解决了最长无重复连续子序列问题。