Problem#
You are given an integer array nums
.
A subsequence sub
of nums
with length x
is called valid if it satisfies:
(sub[0] + sub[1]) % 2 == (sub[1] + sub[2]) % 2 == ... == (sub[x - 2] + sub[x - 1]) % 2.
Return the length of the longest valid subsequence of nums
.
A subsequence is an array that can be derived from another array by deleting some or no elements without changing the order of the remaining elements.
Examples#
Example 1#
1
2
3
4
5
6
7
8
Input: nums = [ 1 , 2 , 3 , 4 ]
Output: 4
Explanation:
The longest valid subsequence is `[1, 2, 3, 4]` .
Example 2#
1
2
3
4
5
6
7
8
Input: nums = [ 1 , 2 , 1 , 1 , 2 , 1 , 2 ]
Output: 6
Explanation:
The longest valid subsequence is `[1, 2, 1, 2, 1, 2]` .
Example 3#
1
2
3
4
5
6
7
8
Input: nums = [ 1 , 3 ]
Output: 2
Explanation:
The longest valid subsequence is `[1, 3]` .
Constraints#
2 <= nums.length <= 2 * 10^5
1 <= nums[i] <= 10^7
Solution#
Method 1 – Dynamic Programming by Parity#
Intuition#
A valid subsequence requires that the parity (even/odd) of the sum of every two consecutive elements is the same throughout. This means, for any valid subsequence, the parity of sub[i] + sub[i+1]
is constant. We can use dynamic programming to track the longest subsequence for each possible parity.
Approach#
For each number, try to extend the longest subsequence ending with each possible parity (0 or 1).
Use a DP array where dp[p]
is the length of the longest subsequence ending with parity p
.
For each number, update the DP for both parities by considering all previous parities.
The answer is the maximum value in the DP array.
Code#
Cpp
Go
Java
Kotlin
Python
Rust
Typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public :
int longestValidSubsequence(vector< int >& nums) {
int n = nums.size(), ans = 1 ;
vector< int > dp(2 , 0 );
for (int x : nums) {
vector< int > ndp = dp;
for (int p= 0 ;p< 2 ;++ p) {
int cur = 1 ;
if (dp[p]) {
int parity = (p + x) % 2 ;
cur = dp[p] + 1 ;
ndp[parity] = max(ndp[parity], cur);
}
ndp[x% 2 ] = max(ndp[x% 2 ], 1 );
}
dp = ndp;
ans = max(ans, max(dp[0 ], dp[1 ]));
}
return ans;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func longestValidSubsequence (nums []int ) int {
dp := [2 ]int {}
ans := 1
for _ , x := range nums {
ndp := dp
for p := 0 ; p < 2 ; p ++ {
cur := 1
if dp [p ] > 0 {
parity := (p + x ) % 2
cur = dp [p ] + 1
if ndp [parity ] < cur {
ndp [parity ] = cur
}
}
if ndp [x % 2 ] < 1 {
ndp [x % 2 ] = 1
}
}
dp = ndp
if ans < dp [0 ] { ans = dp [0 ] }
if ans < dp [1 ] { ans = dp [1 ] }
}
return ans
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int longestValidSubsequence (int [] nums) {
int [] dp = new int [ 2] ;
int ans = 1;
for (int x : nums) {
int [] ndp = dp.clone ();
for (int p= 0;p< 2;++ p) {
int cur = 1;
if (dp[ p]> 0) {
int parity = (p + x) % 2;
cur = dp[ p] + 1;
ndp[ parity] = Math.max (ndp[ parity] , cur);
}
ndp[ x% 2] = Math.max (ndp[ x% 2] , 1);
}
dp = ndp;
ans = Math.max (ans, Math.max (dp[ 0] , dp[ 1] ));
}
return ans;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
fun longestValidSubsequence (nums: IntArray): Int {
var dp = IntArray(2 )
var ans = 1
for (x in nums) {
val ndp = dp.copyOf()
for (p in 0. .1 ) {
var cur = 1
if (dp[p] > 0 ) {
val parity = (p + x) % 2
cur = dp[p] + 1
ndp[parity] = maxOf(ndp[parity], cur)
}
ndp[x%2 ] = maxOf(ndp[x%2 ], 1 )
}
dp = ndp
ans = maxOf(ans, dp[0 ], dp[1 ])
}
return ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution :
def longestValidSubsequence (self, nums: list[int]) -> int:
dp = [0 , 0 ]
ans = 1
for x in nums:
ndp = dp[:]
for p in range(2 ):
cur = 1
if dp[p]:
parity = (p + x) % 2
cur = dp[p] + 1
ndp[parity] = max(ndp[parity], cur)
ndp[x% 2 ] = max(ndp[x% 2 ], 1 )
dp = ndp
ans = max(ans, dp[0 ], dp[1 ])
return ans
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
impl Solution {
pub fn longest_valid_subsequence (nums: Vec< i32 > ) -> i32 {
let mut dp = [0 , 0 ];
let mut ans = 1 ;
for & x in & nums {
let mut ndp = dp;
for p in 0 .. 2 {
let mut cur = 1 ;
if dp[p] > 0 {
let parity = (p + x as usize ) % 2 ;
cur = dp[p] + 1 ;
ndp[parity] = ndp[parity].max(cur);
}
ndp[(x% 2 ) as usize ] = ndp[(x% 2 ) as usize ].max(1 );
}
dp = ndp;
ans = ans.max(dp[0 ]).max(dp[1 ]);
}
ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
longestValidSubsequence (nums : number []): number {
let dp = [0 , 0 ];
let ans = 1 ;
for (const x of nums ) {
const ndp = dp .slice ();
for (let p = 0 ;p <2 ;++ p ) {
let cur = 1 ;
if ( dp [ p ]) {
const parity = ( p + x ) % 2 ;
cur = dp [ p ] + 1 ;
ndp [ parity ] = Math.max ( ndp [ parity ] , cur );
}
ndp [ x % 2 ] = Math.max ( ndp [ x % 2 ] , 1 );
}
dp = ndp ;
ans = Math.max ( ans , dp [ 0 ] , dp [ 1 ]);
}
return ans ;
}
}
Complexity#
⏰ Time complexity: O(n)
, where n is the length of nums.
🧺 Space complexity: O(1)
, only a constant number of variables are used.