Find the Maximum Length of a Good Subsequence II
HardUpdated: Aug 2, 2025
Practice on:
Problem
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.
Examples
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 * 10^31 <= nums[i] <= 10^90 <= k <= min(50, nums.length)
Solution
Method 1 – Dynamic Programming with State Compression
Intuition
We want the longest subsequence with at most k transitions (places where adjacent elements differ). For this hard version, the constraints are larger, so we need to optimize the DP by compressing the state and using hash maps for only relevant states.
Approach
- Use a dictionary to store the best result for each (last value, transitions) pair.
- For each number in
nums, for each existing state, try to extend the subsequence:- If the value changes, increment the transition count.
- Only keep the best length for each (value, transitions) pair.
- Always allow starting a new subsequence with the current number and 0 transitions.
- The answer is the maximum length for any state with at most
ktransitions.
Code
C++
class Solution {
public:
int maximumLength(vector<int>& nums, int k) {
unordered_map<long long, int> dp; // key: (val<<5)|t, value: max len
int ans = 0;
for(int x : nums) {
unordered_map<long long, int> ndp;
ndp[(long long(x)<<5)] = 1;
for(auto& [key, l] : dp) {
int v = key>>5, t = key&31;
int nt = t + (v!=x);
if(nt<=k) {
long long nk = (long long(x)<<5)|nt;
ndp[nk] = max(ndp[nk], l+1);
}
}
for(auto& [key, l] : ndp) ans = max(ans, l);
dp = move(ndp);
}
return ans;
}
};
Go
func maximumLength(nums []int, k int) int {
dp := map[[2]int]int{} // [val, t] -> max len
ans := 0
for _, x := range nums {
ndp := map[[2]int]int{}
ndp[[2]int{x, 0}] = 1
for key, l := range dp {
v, t := key[0], key[1]
nt := t
if v != x { nt++ }
if nt <= k {
nk := [2]int{x, nt}
if ndp[nk] < l+1 { ndp[nk] = l+1 }
}
}
for _, l := range ndp {
if l > ans { ans = l }
}
dp = ndp
}
return ans
}
Java
class Solution {
public int maximumLength(int[] nums, int k) {
Map<Long, Integer> dp = new HashMap<>();
int ans = 0;
for(int x : nums) {
Map<Long, Integer> ndp = new HashMap<>();
ndp.put(((long)x<<5), 1);
for(var e : dp.entrySet()) {
int v = (int)(e.getKey()>>5), t = (int)(e.getKey()&31);
int nt = t + (v!=x?1:0);
if(nt<=k) {
long nk = ((long)x<<5)|nt;
ndp.put(nk, Math.max(ndp.getOrDefault(nk, 0), e.getValue()+1));
}
}
for(int l : ndp.values()) ans = Math.max(ans, l);
dp = ndp;
}
return ans;
}
}
Kotlin
class Solution {
fun maximumLength(nums: IntArray, k: Int): Int {
var dp = mutableMapOf<Pair<Int,Int>,Int>()
var ans = 0
for (x in nums) {
val ndp = mutableMapOf<Pair<Int,Int>,Int>()
ndp[x to 0] = 1
for ((key, l) in dp) {
val (v, t) = key
val nt = t + if (v != x) 1 else 0
if (nt <= k) {
val nk = x to nt
ndp[nk] = maxOf(ndp.getOrDefault(nk,0), l+1)
}
}
for (l in ndp.values) ans = maxOf(ans, l)
dp = ndp
}
return ans
}
}
Python
class Solution:
def maximumLength(self, nums: list[int], k: int) -> int:
dp = dict() # (val, t) -> max len
ans = 0
for x in nums:
ndp = dict()
ndp[(x, 0)] = 1
for (v, t), l in dp.items():
nt = t + (v != x)
if nt <= k:
nk = (x, nt)
ndp[nk] = max(ndp.get(nk, 0), l+1)
for l in ndp.values():
ans = max(ans, l)
dp = ndp
return ans
Rust
use std::collections::HashMap;
impl Solution {
pub fn maximum_length(nums: Vec<i32>, k: i32) -> i32 {
let mut dp = HashMap::new(); // (val, t) -> max len
let mut ans = 0;
for &x in &nums {
let mut ndp = HashMap::new();
ndp.insert((x, 0), 1);
for (&(v, t), &l) in &dp {
let nt = t + if v != x { 1 } else { 0 };
if nt <= k {
let nk = (x, nt);
ndp.insert(nk, ndp.get(&nk).copied().unwrap_or(0).max(l+1));
}
}
for &l in ndp.values() { ans = ans.max(l); }
dp = ndp;
}
ans
}
}
TypeScript
class Solution {
maximumLength(nums: number[], k: number): number {
let dp = new Map<string, number>();
let ans = 0;
for(const x of nums) {
const ndp = new Map<string, number>();
ndp.set(`${x},0`, 1);
for(const [key, l] of dp.entries()) {
const [v, t] = key.split(',').map(Number);
const nt = t + (v!==x?1:0);
if(nt<=k) {
const nk = `${x},${nt}`;
ndp.set(nk, Math.max(ndp.get(nk)||0, l+1));
}
}
for(const l of ndp.values()) ans = Math.max(ans, l);
dp = ndp;
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n*k*U), where n is the length of nums and U is the number of unique values in nums. - 🧺 Space complexity:
O(k*U), for the DP table