Find the Maximum Length of a Good Subsequence II
HARDDescription
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 * 1031 <= nums[i] <= 1090 <= k <= min(50, nums.length)
Approaches
Checkout 2 different approaches to solve Find the Maximum Length of a Good Subsequence II. Click on different approaches to view the approach and algorithm in detail.
Naive Dynamic Programming
This approach uses a straightforward dynamic programming solution. We define a 2D DP table, dp[i][j], to store the maximum length of a good subsequence ending at index i with exactly j "breaks" (where adjacent elements are different). To compute the value for dp[i][j], we iterate through all previous elements nums[p] (where p < i) and consider extending the subsequences ending at p.
Algorithm
- Create a 2D DP table
dp[n][k+1], wheredp[i][j]stores the maximum length of a good subsequence ending at indexiwith exactlyjbreaks. - Initialize a variable
maxLengthto 1, as any single element is a valid subsequence of length 1. - Iterate through each element
nums[i]fromi = 0ton-1. - For each
nums[i], initializedp[i][0] = 1(a subsequence with justnums[i]has length 1 and 0 breaks). - Iterate through all previous elements
nums[p]wherep < i. - If
nums[p] == nums[i], we can extend a subsequence ending atpwithout adding a break. For eachjfrom0tok, updatedp[i][j] = max(dp[i][j], dp[p][j] + 1). - If
nums[p] != nums[i], we introduce a new break. For eachjfrom1tok, we can extend a subsequence that ended atpwithj-1breaks. Updatedp[i][j] = max(dp[i][j], dp[p][j-1] + 1). - After filling the
dptable, the answer is the maximum value found in the entiredptable, as the subsequence can end at any index with any number of breaks up tok.
In this method, we define dp[i][j] as the maximum length of a good subsequence of nums[0...i] that ends with nums[i] and has exactly j breaks. A break occurs when an element is different from the previous one in the subsequence.
To compute dp[i][j], we look at all possible preceding elements nums[p] (where p < i) in the subsequence. Two cases arise:
nums[p] == nums[i]: If we appendnums[i]to a subsequence ending innums[p], the number of breaks does not change. Thus, we can extend any subsequence that ended atpwithjbreaks. The new length would bedp[p][j] + 1.nums[p] != nums[i]: If we appendnums[i]to a subsequence ending innums[p], a new break is introduced. This means the subsequence ending atpmust have hadj-1breaks. The new length would bedp[p][j-1] + 1.
The base case is that any single element nums[i] forms a subsequence of length 1 with 0 breaks. The final answer is the maximum value across the entire dp table, since the optimal subsequence can end at any index i and use any number of breaks j from 0 to k.
class Solution {
public int maximumLength(int[] nums, int k) {
int n = nums.length;
if (n == 0) return 0;
// dp[i][j]: max length of a good subsequence ending at index i with j breaks.
int[][] dp = new int[n][k + 1];
int maxLength = 0;
for (int i = 0; i < n; i++) {
// A subsequence with only nums[i] has length 1 and 0 breaks.
dp[i][0] = 1;
for (int p = 0; p < i; p++) {
if (nums[p] == nums[i]) {
// Same element, no new break.
for (int j = 0; j <= k; j++) {
if (dp[p][j] > 0) {
dp[i][j] = Math.max(dp[i][j], dp[p][j] + 1);
}
}
} else {
// Different element, one new break.
for (int j = 1; j <= k; j++) {
if (dp[p][j - 1] > 0) {
dp[i][j] = Math.max(dp[i][j], dp[p][j - 1] + 1);
}
}
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j <= k; j++) {
maxLength = Math.max(maxLength, dp[i][j]);
}
}
return maxLength;
}
}
Complexity Analysis
Pros and Cons
- The logic is a direct translation of the problem definition into a DP state, making it relatively easy to understand.
- The time complexity of O(N² * K) is too high for the given constraints, leading to a Time Limit Exceeded (TLE) error.
Code Solutions
Checking out 3 solutions in different languages for Find the Maximum Length of a Good Subsequence II. Click on different languages to view the code.
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;
}
}
Video Solution
Watch the video walkthrough for Find the Maximum Length of a Good Subsequence II
Similar Questions
5 related questions you might find useful
Patterns:
Data Structures:
Companies:
Subscribe to Scale Engineer newsletter
Learn about System Design, Software Engineering, and interview experiences every week.
No spam, unsubscribe at any time.