点击获取AI摘要

2900. 最长相邻不相等子序列 I E

给你一个下标从 0 开始的字符串数组 words ,和一个下标从 0 开始的 二进制 数组 groups ,两个数组长度都是 n

你需要从 words 中选出 最长子序列。如果对于序列中的任何两个连续串,二进制数组 groups 中它们的对应元素不同,则 words 的子序列是不同的。

正式来说,你需要从下标 [0, 1, ..., n - 1] 中选出一个 最长子序列 ,将这个子序列记作长度为 k[i₀, i₁, ..., iₖ ₋ ₁] ,对于所有满足 0 <= j < k - 1j 都有 groups[iⱼ] != groups[iⱼ ₊ ₁]

请你返回一个字符串数组,它是下标子序列 依次 对应 words 数组中的字符串连接形成的字符串数组。如果有多个答案,返回 任意 一个。

注意:words 中的元素是不同的 。

示例 1:

输入:words = [“e”,“a”,“b”], groups = [0,0,1]
输出:[“e”,“b”]
解释:一个可行的子序列是 [0,2] ,因为 groups[0] != groups[2] 。
所以一个可行的答案是 [words[0],words[2]] = [“e”,“b”] 。
另一个可行的子序列是 [1,2] ,因为 groups[1] != groups[2] 。
得到答案为 [words[1],words[2]] = [“a”,“b”] 。
这也是一个可行的答案。
符合题意的最长子序列的长度为 2 。

示例 2:

输入:words = [“a”,“b”,“c”,“d”], groups = [1,0,1,1]
输出:[“a”,“b”,“c”]
解释:一个可行的子序列为 [0,1,2] 因为 groups[0] != groups[1] 且 groups[1] != groups[2] 。
所以一个可行的答案是 [words[0],words[1],words[2]] = [“a”,“b”,“c”] 。
另一个可行的子序列为 [0,1,3] 因为 groups[0] != groups[1] 且 groups[1] != groups[3] 。
得到答案为 [words[0],words[1],words[3]] = [“a”,“b”,“d”] 。
这也是一个可行的答案。
符合题意的最长子序列的长度为 3 。

提示:

  • 1 <= n == words.length == groups.length <= 100
  • 1 <= words[i].length <= 10
  • groups[i]01
  • words 中的字符串 互不相同
  • words[i] 只包含小写英文字母。

问题分析

给定长度为 nnn 的字符串数组 words 和对应的二进制数组 groups(取值 0 或 1),在下标序列 [0,1,,n1][0,1,\dots,n-1] 中选出一个最长子序列 [i0,i1,,ik1][i_0,i_1,\dots,i_{k-1}],要求对于所有相邻的 jj,有

groups[ij]groups[ij+1].groups[i_j] \neq groups[i_{j+1}].

返回对应的字符串序列 [  words[i0],words[i1],  ]\bigl[\;words[i_0],words[i_1],\dots\;\bigr]

算法思路

贪心(Greedy)策略

  • 只要当前元素与上一次选中的元素所属组不同,就立刻将其加入子序列。
  • 这样做不会影响后续可选集的多样性,且能保证选到尽可能多的元素。

详细步骤

  • 初始化结果列表 res,以及记录上一次选中字母所属组 last_group = -1(-1 表示尚未选过)。
  • 遍历索引 i0n-1
    • groups[i] != last_group,则:
      • words[i] 添加到 res
      • 更新 last_group = groups[i]
  • 返回 res

正确性证明

  • 若你跳过了一个满足条件的元素,那么相当于放弃了一次“切换组”的机会,后续可选空间只会更少,因此贪心选的方式能保证长度最大。

时间复杂度

时间复杂度 :一次线性扫描,O(n)O(n),其中 n=len(words)n = \text{len(words)}

空间复杂度 :最坏情况下结果列表与输入等长,O(n)O(n)

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from typing import List

class Solution:
def getLongestSubsequence(self, words: List[str], groups: List[int]) -> List[str]:
res: List[str] = []
last_group: int = -1 # 上一次选中元素的组号,初始为 -1

for w, g in zip(words, groups):
if g != last_group:
res.append(w)
last_group = g

return res