# 3177. Find the Maximum Length of a Good Subsequence II

## Description

You are given an integer array nums and a non-negative integer k. A sequence of integers seq is called good if there are at most k indices i in the range [0, seq.length - 2] such that seq[i] != seq[i + 1].

Return the maximum possible length of a good subsequence of nums.

Example 1:

Input: nums = [1,2,1,1,3], k = 2

Output: 4

Explanation:

The maximum length subsequence is [1,2,1,1,3].

Example 2:

Input: nums = [1,2,3,4,5,1], k = 0

Output: 2

Explanation:

The maximum length subsequence is [1,2,3,4,5,1].

Constraints:

• 1 <= nums.length <= 5 * 103
• 1 <= nums[i] <= 109
• 0 <= k <= min(50, nums.length)

## Solutions

### Solution 1: Dynamic Programming

We define $f[i][h]$ as the length of the longest good subsequence ending with $nums[i]$ and having no more than $h$ indices satisfying the condition. Initially, $f[i][h] = 1$. The answer is $\max(f[i][k])$, where $0 \le i < n$.

We consider how to calculate $f[i][h]$. We can enumerate $0 \le j < i$, if $nums[i] = nums[j]$, then $f[i][h] = \max(f[i][h], f[j][h] + 1)$; otherwise, if $h > 0$, then $f[i][h] = \max(f[i][h], f[j][h - 1] + 1)$. That is:

$f[i][h]= \begin{cases} \max(f[i][h], f[j][h] + 1), & \text{if } nums[i] = nums[j], \\ \max(f[i][h], f[j][h - 1] + 1), & \text{if } h > 0. \end{cases}$

The final answer is $\max(f[i][k])$, where $0 \le i < n$.

The time complexity is $O(n^2 \times k)$, and the space complexity is $O(n \times k)$. Where $n$ is the length of the array nums.

Due to the large data range of this problem, the above solution will time out and needs to be optimized.

According to the state transition equation, if $nums[i] = nums[j]$, then we only need to get the maximum value of $f[j][h]$, we can maintain it with an array $mp$ of length $k + 1$. If $nums[i] \neq nums[j]$, we need to record the maximum value of $f[j][h - 1]$ corresponding to $nums[j]$, the maximum value and the second maximum value, we can maintain it with an array $g$ of length $k + 1$.

The time complexity is $O(n \times k)$, and the space complexity is $O(n \times k)$. Where $n$ is the length of the array nums.

• class Solution {
public int maximumLength(int[] nums, int k) {
int n = nums.length;
int[][] f = new int[n][k + 1];
Map<Integer, Integer>[] mp = new HashMap[k + 1];
Arrays.setAll(mp, i -> new HashMap<>());
int[][] g = new int[k + 1][3];
int ans = 0;
for (int i = 0; i < n; ++i) {
for (int h = 0; h <= k; ++h) {
f[i][h] = mp[h].getOrDefault(nums[i], 0);
if (h > 0) {
if (g[h - 1][0] != nums[i]) {
f[i][h] = Math.max(f[i][h], g[h - 1][1]);
} else {
f[i][h] = Math.max(f[i][h], g[h - 1][2]);
}
}
++f[i][h];
mp[h].merge(nums[i], f[i][h], Integer::max);
if (g[h][0] != nums[i]) {
if (f[i][h] >= g[h][1]) {
g[h][2] = g[h][1];
g[h][1] = f[i][h];
g[h][0] = nums[i];
} else {
g[h][2] = Math.max(g[h][2], f[i][h]);
}
} else {
g[h][1] = Math.max(g[h][1], f[i][h]);
}
ans = Math.max(ans, f[i][h]);
}
}
return ans;
}
}

• class Solution {
public:
int maximumLength(vector<int>& nums, int k) {
int n = nums.size();
vector<vector<int>> f(n, vector<int>(k + 1));
vector<unordered_map<int, int>> mp(k + 1);
vector<vector<int>> g(k + 1, vector<int>(3));
int ans = 0;
for (int i = 0; i < n; ++i) {
for (int h = 0; h <= k; ++h) {
f[i][h] = mp[h][nums[i]];
if (h > 0) {
if (g[h - 1][0] != nums[i]) {
f[i][h] = max(f[i][h], g[h - 1][1]);
} else {
f[i][h] = max(f[i][h], g[h - 1][2]);
}
}
++f[i][h];
mp[h][nums[i]] = max(mp[h][nums[i]], f[i][h]);
if (g[h][0] != nums[i]) {
if (f[i][h] >= g[h][1]) {
g[h][2] = g[h][1];
g[h][1] = f[i][h];
g[h][0] = nums[i];
} else {
g[h][2] = max(g[h][2], f[i][h]);
}
} else {
g[h][1] = max(g[h][1], f[i][h]);
}
ans = max(ans, f[i][h]);
}
}

return ans;
}
};

• class Solution:
def maximumLength(self, nums: List[int], k: int) -> int:
n = len(nums)
f = [[0] * (k + 1) for _ in range(n)]
mp = [defaultdict(int) for _ in range(k + 1)]
g = [[0] * 3 for _ in range(k + 1)]
ans = 0
for i, x in enumerate(nums):
for h in range(k + 1):
f[i][h] = mp[h][x]
if h:
if g[h - 1][0] != nums[i]:
f[i][h] = max(f[i][h], g[h - 1][1])
else:
f[i][h] = max(f[i][h], g[h - 1][2])
f[i][h] += 1
mp[h][nums[i]] = max(mp[h][nums[i]], f[i][h])
if g[h][0] != x:
if f[i][h] >= g[h][1]:
g[h][2] = g[h][1]
g[h][1] = f[i][h]
g[h][0] = x
else:
g[h][2] = max(g[h][2], f[i][h])
else:
g[h][1] = max(g[h][1], f[i][h])
ans = max(ans, f[i][h])
return ans


• func maximumLength(nums []int, k int) int {
n := len(nums)
f := make([][]int, n)
for i := range f {
f[i] = make([]int, k+1)
}
mp := make([]map[int]int, k+1)
for i := range mp {
mp[i] = make(map[int]int)
}
g := make([][3]int, k+1)
ans := 0

for i := 0; i < n; i++ {
for h := 0; h <= k; h++ {
f[i][h] = mp[h][nums[i]]
if h > 0 {
if g[h-1][0] != nums[i] {
if g[h-1][1] > f[i][h] {
f[i][h] = g[h-1][1]
}
} else {
if g[h-1][2] > f[i][h] {
f[i][h] = g[h-1][2]
}
}
}
f[i][h]++
if f[i][h] > mp[h][nums[i]] {
mp[h][nums[i]] = f[i][h]
}
if g[h][0] != nums[i] {
if f[i][h] >= g[h][1] {
g[h][2] = g[h][1]
g[h][1] = f[i][h]
g[h][0] = nums[i]
} else if f[i][h] > g[h][2] {
g[h][2] = f[i][h]
}
} else {
if f[i][h] > g[h][1] {
g[h][1] = f[i][h]
}
}
if f[i][h] > ans {
ans = f[i][h]
}
}
}

return ans
}

• function maximumLength(nums: number[], k: number): number {
const n = nums.length;
const f: number[][] = Array.from({ length: n }, () => Array(k + 1).fill(0));
const mp: Map<number, number>[] = Array.from({ length: k + 1 }, () => new Map());
const g: number[][] = Array.from({ length: k + 1 }, () => Array(3).fill(0));
let ans = 0;

for (let i = 0; i < n; i++) {
for (let h = 0; h <= k; h++) {
f[i][h] = mp[h].get(nums[i]) || 0;
if (h > 0) {
if (g[h - 1][0] !== nums[i]) {
f[i][h] = Math.max(f[i][h], g[h - 1][1]);
} else {
f[i][h] = Math.max(f[i][h], g[h - 1][2]);
}
}
f[i][h]++;
mp[h].set(nums[i], Math.max(mp[h].get(nums[i]) || 0, f[i][h]));
if (g[h][0] !== nums[i]) {
if (f[i][h] >= g[h][1]) {
g[h][2] = g[h][1];
g[h][1] = f[i][h];
g[h][0] = nums[i];
} else {
g[h][2] = Math.max(g[h][2], f[i][h]);
}
} else {
g[h][1] = Math.max(g[h][1], f[i][h]);
}
ans = Math.max(ans, f[i][h]);
}
}

return ans;
}