3202. Find the Maximum Length of Valid Subsequence II
Problem Description
You are given an integer array nums
and a positive integer k
. A subsequence sub
of nums
with length x
is considered valid if it satisfies the following condition:
(sub[0] + sub[1]) % k == (sub[1] + sub[2]) % k == ... == (sub[x - 2] + sub[x - 1]) % k
.
The task is to find the length of the longest valid subsequence of nums
.
Intuition
To solve this problem, we need to understand the core condition for a valid subsequence: For any two consecutive elements in the subsequence, the sum of those two elements mod k
should be the same across the entire subsequence. This translates to needing the modulo result of all odd-indexed elements to be the same, and similarly, all even-indexed elements to have the same result when taken modulo k
.
Here's the reasoning process:
- Each element in
nums
is considered asx % k
. - We define a 2D array
f[x][y]
that represents the length of the longest valid subsequence where the last element modulok
isx
and the one before last modulok
isy
. - Initially, set all
f[x][y]
to zero, as the subsequence begins empty. - As we iterate over each number in
nums
, computex = num % k
for the current number. - For each possible
j in [0, k)
, previously consecutive numbers that make(num[j] + num[next]) % k
consistent should be considered. The valuey
is calculated as(j - x + k) % k
, giving possible combinations. - Update the state with
f[x][y] = f[y][x] + 1
, increasing the length of the subsequence when a valid condition is met. - Maintain a variable
ans
to track and return the maximum value found inf[x][y]
, which represents the length of the longest valid subsequence.
This dynamic programming approach efficiently constructs subsequences satisfying the condition through matrix indexing, eventually leading us to the desired answer.
Learn more about Dynamic Programming patterns.
Solution Approach
The problem is addressed using a dynamic programming technique. Here's a detailed walkthrough of the solution:
-
Data Structure Initialization:
A 2D listf
with dimensions[k][k]
is initialized to zero. This structure holds information about the longest valid subsequence found, wheref[x][y]
corresponds to the subsequence ending with an element whose modulo result isx
, and the previous one wasy
.f = [[0] * k for _ in range(k)]
-
Iteration through
nums
:
For each elementx
innums
, computex = x % k
. This converts each number to its remainder when divided byk
, essentially mapping numbers onto the range[0, k)
.for x in nums: x %= k
-
Update the DP Table:
For each possiblej
in[0, k)
, findy
, the modulo value that would achieve the condition(prev_value + current_value) % k == j
. The formula fory
is computed as(j - x + k) % k
to ensure non-negative values. Update the DP state by incrementingf[x][y]
with the value off[y][x] + 1
, as a new valid subsequence can be formed by appendingx
.for j in range(k): y = (j - x + k) % k f[x][y] = f[y][x] + 1
-
Track the Maximum Subsequence Length:
Throughout the iteration, maintain a variableans
to store the length of the longest valid subsequence encountered, taking the maximum across allf[x][y]
.ans = max(ans, f[x][y])
-
Return the Result:
After processing all elements, returnans
, which now holds the length of the longest valid subsequence as per the problem's requirements.return ans
By organizing and utilizing the results from previously computed states in a structured manner, this dynamic programming approach achieves efficient enumeration and tracking of valid subsequences.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with a small example to illustrate the approach. Consider the array nums = [3, 8, 5, 7]
and k = 4
. We aim to find the longest valid subsequence where subsequence sums modulo 4 are consistent.
Step 1: Initialize Data Structure
- Create a 2D list
f
with dimensions[4][4]
initialized to zero:f = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
Step 2: Iteration through nums
-
Convert each number in
nums
to its respective modulo 4 value:- For 3:
3 % 4 = 3
- For 8:
8 % 4 = 0
- For 5:
5 % 4 = 1
- For 7:
7 % 4 = 3
Now,
nums = [3, 0, 1, 3]
(transformed with modulo operation). - For 3:
Step 3: Update the DP Table
Iterate over each number in the updated nums
:
-
For
x = 3
(from 3 innums
):- Iterate
j
from 0 to 3:-
When
j=0
:y = (0 - 3 + 4) % 4 = 1
. Update:f[3][1] = f[1][3] + 1 = 1
. -
When
j=1
:y = (1 - 3 + 4) % 4 = 2
. Update:f[3][2] = f[2][3] + 1 = 1
. -
When
j=2
:y = (2 - 3 + 4) % 4 = 3
. Update:f[3][3] = f[3][3] + 1 = 1
. -
When
j=3
:y = (3 - 3 + 4) % 4 = 0
. Update:f[3][0] = f[0][3] + 1 = 1
.
-
- Iterate
-
For
x = 0
(from 8 innums
):- Iterate
j
from 0 to 3:-
When
j=0
:y = (0 - 0 + 4) % 4 = 0
. Update:f[0][0] = f[0][0] + 1 = 1
. -
When
j=1
:y = (1 - 0 + 4) % 4 = 1
. Update:f[0][1] = f[1][0] + 1 = 1
. -
When
j=2
:y = (2 - 0 + 4) % 4 = 2
. Update:f[0][2] = f[2][0] + 1 = 1
. -
When
j=3
:y = (3 - 0 + 4) % 4 = 3
. Update:f[0][3] = f[3][0] + 1 = 2
.
-
- Iterate
-
For
x = 1
(from 5 innums
):- Iterate
j
from 0 to 3:-
When
j=0
:y = (0 - 1 + 4) % 4 = 3
. Update:f[1][3] = f[3][1] + 1 = 2
. -
When
j=1
:y = (1 - 1 + 4) % 4 = 0
. Update:f[1][0] = f[0][1] + 1 = 2
. -
When
j=2
:y = (2 - 1 + 4) % 4 = 1
. Update:f[1][1] = f[1][1] + 1 = 1
. -
When
j=3
:y = (3 - 1 + 4) % 4 = 2
. Update:f[1][2] = f[2][1] + 1 = 1
.
-
- Iterate
-
For
x = 3
(from 7 innums
):- Iterate
j
from 0 to 3:-
When
j=0
:y = (0 - 3 + 4) % 4 = 1
. Update:f[3][1] = f[1][3] + 1 = 3
. -
When
j=1
:y = (1 - 3 + 4) % 4 = 2
. Update:f[3][2] = f[2][3] + 1 = 2
. -
When
j=2
:y = (2 - 3 + 4) % 4 = 3
. Update:f[3][3] = f[3][3] + 1 = 2
. -
When
j=3
:y = (3 - 3 + 4) % 4 = 0
. Update:f[3][0] = f[0][3] + 1 = 3
.
-
- Iterate
Step 4: Track the Maximum Subsequence Length
- Calculate the maximum value of any
f[x][y]
after iterations.
ans = max(max(row) for row in f)
In this case, ans = 3
, representing the longest valid subsequence.
Step 5: Return the Result
- The length of the longest valid subsequence, satisfying the given condition, is
3
.
Solution Implementation
1from typing import List
2
3class Solution:
4 def maximumLength(self, nums: List[int], k: int) -> int:
5 # Initialize a 2D list (matrix) of size k x k with all values set to 0
6 count_matrix = [[0] * k for _ in range(k)]
7 max_length = 0
8
9 # Traverse through each number in the input list
10 for num in nums:
11 # Calculate the remainder of the current number with k
12 remainder = num % k
13
14 # Iterate over each possible remainder
15 for j in range(k):
16 # Calculate complementary remainder required to form a valid pair with `remainder`
17 complement_remainder = (j - remainder + k) % k
18
19 # Update the matrix with the new sequence length
20 count_matrix[remainder][complement_remainder] = count_matrix[complement_remainder][remainder] + 1
21
22 # Update the maximum sequence length found
23 max_length = max(max_length, count_matrix[remainder][complement_remainder])
24
25 # Return the maximum sequence length found
26 return max_length
27
1class Solution {
2 public int maximumLength(int[] nums, int k) {
3 // Initialize a 2D array to keep track of subarray lengths with modulo value
4 int[][] subarrayLengths = new int[k][k];
5 int maxLength = 0; // Variable to store the maximum length found
6
7 // Iterate over each element in nums
8 for (int num : nums) {
9 int modValue = num % k; // Compute the current number's modulo with k
10
11 // Iterate over all possible modulo values from 0 to k-1
12 for (int j = 0; j < k; ++j) {
13 int requiredMod = (j - modValue + k) % k; // Compute the required complement modulo
14
15 // Update the subarray length by 1 for the current modulo configuration
16 subarrayLengths[modValue][requiredMod] = subarrayLengths[requiredMod][modValue] + 1;
17
18 // Update the maximum length found so far
19 maxLength = Math.max(maxLength, subarrayLengths[modValue][requiredMod]);
20 }
21 }
22 return maxLength; // Return the maximum subarray length satisfying the condition
23 }
24}
25
1#include <vector>
2#include <cstring> // For memset
3#include <algorithm> // For max function
4
5class Solution {
6public:
7 // Function to find the maximum length of a subsequence with elements having a given modulus
8 int maximumLength(std::vector<int>& nums, int k) {
9 // Initialize a 2D array to store intermediate results
10 int remainderCount[k][k];
11
12 // Set all elements of the 2D array to 0
13 std::memset(remainderCount, 0, sizeof(remainderCount));
14
15 int maxLength = 0; // Variable to keep track of the maximum length
16
17 // Iterate through each number in the input vector
18 for (int num : nums) {
19 int modValue = num % k; // Calculate modulus of the number with respect to k
20
21 // Loop through possible remainder values
22 for (int remainder = 0; remainder < k; ++remainder) {
23 // Calculate the target remainder
24 int targetRemainder = (remainder - modValue + k) % k;
25
26 // Update the 2D array for the current modValue and targetRemainder
27 remainderCount[modValue][targetRemainder] = remainderCount[targetRemainder][modValue] + 1;
28
29 // Update maximum length if a longer subsequence is found
30 maxLength = std::max(maxLength, remainderCount[modValue][targetRemainder]);
31 }
32 }
33
34 // Return the maximum length of the subsequence found
35 return maxLength;
36 }
37};
38
1function maximumLength(nums: number[], k: number): number {
2 // Initialize a 2D array with dimensions k x k, filled with zeros
3 const f: number[][] = Array.from({ length: k }, () => Array(k).fill(0));
4 let ans: number = 0; // To keep track of the maximum length found
5
6 for (let x of nums) {
7 x %= k; // Reduce x mod k to be within the range 0 to k-1
8
9 // Iterate over each possible remainder j
10 for (let j = 0; j < k; ++j) {
11 // Compute the remainder y that when added to x is equivalent to j mod k
12 const y = (j - x + k) % k;
13 // Update the value in the f array to reflect the longest length ending in x, with sum mod k equal to y
14 f[x][y] = f[y][x] + 1;
15 // Update the maximum length found so far
16 ans = Math.max(ans, f[x][y]);
17 }
18 }
19
20 return ans; // Return the maximum length found
21}
22
Time and Space Complexity
The time complexity of the given code is O(n * k)
, where n
is the length of the array nums
, and k
is the given positive integer. This complexity arises because for each element in nums
, represented as x
, a nested loop iterates k
times to update the f
matrix.
The space complexity is O(k^2)
because the 2D list f
is initialized with dimensions k x k
, leading to the storage requirement of k * k
elements.
Learn more about how to find time and space complexity quickly.
A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".
What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?
Recommended Readings
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!