统计只出现一次的最长连续子序列的长度
字数 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]starti-1之间是否出现过(即上次出现位置lastPos是否大于等于start
  • 如果出现过,我们需要将start更新为lastPos + 1
  • 当前子序列长度就是i - start + 1

步骤3:记录元素最后出现位置
我们需要一个哈希表来记录每个元素最后一次出现的位置索引,这样可以在O(1)时间内找到上次出现位置。

步骤4:算法流程

  1. 初始化哈希表lastIndex,记录每个数字最后出现的位置
  2. 初始化start = 0,表示当前窗口的起始位置
  3. 初始化maxLength = 0,记录最大长度
  4. 遍历数组中的每个元素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),用于存储元素最后出现位置的哈希表

这种方法巧妙地结合了动态规划的思想和滑动窗口的技巧,高效地解决了最长无重复连续子序列问题。

统计只出现一次的最长连续子序列的长度 题目描述 给定一个整数数组,我们需要找到最长的连续子序列,要求这个子序列中的所有元素都只出现一次。换句话说,在这个连续子序列中,不能有重复的元素。 例如: 输入:[ 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),用于存储元素最后出现位置的哈希表 这种方法巧妙地结合了动态规划的思想和滑动窗口的技巧,高效地解决了最长无重复连续子序列问题。