You are given an array nums
consisting only of integers 0, 1, and 2.
A special subsequence is a sequence of indices (i1, i2, ..., ik)
such that:
j
in 1 ≤ j ≤ k
, nums[ij]
is in non-decreasing order.0
, followed by at least one 1
, followed by at least one 2
(in that order, not necessarily consecutively).nums
. Since the answer may be large, return it modulo 10^9 + 7
.
Constraints:
1 ≤ nums.length ≤ 10^5
nums[i]
is 0, 1, or 2At first glance, it may seem like we can generate all possible subsequences and count those that fit the pattern. However, with up to 105 elements, this brute-force approach is computationally infeasible.
Instead, we should look for a way to incrementally build up the count of valid subsequences as we process each element. This is reminiscent of dynamic programming, where we track partial results and use them to efficiently build the answer.
For each element in nums
, we want to know:
We'll use three counters:
count0
: Number of subsequences ending with 0 (at least one 0)count1
: Number of subsequences with at least one 0 followed by at least one 1count2
: Number of subsequences with at least one 0, then at least one 1, then at least one 2 (i.e., special subsequences)nums
:
count0 = count0 * 2 + 1
.count1 = count1 * 2 + count0
.count2 = count2 * 2 + count1
.10^9 + 7
at each step to avoid overflow.count2
as the answer.This approach ensures we count all valid subsequences efficiently, leveraging dynamic programming principles.
Let's consider nums = [0,1,2,2]
.
We'll track count0
, count1
, and count2
as we process each number:
count0=0, count1=0, count2=0
count0 = 0*2 + 1 = 1
count1 = 0*2 + 1 = 1
count2 = 0*2 + 1 = 1
count2 = 1*2 + 1 = 3
So, the answer is 3
.
The three special subsequences are:
Brute-force: Generating all subsequences is O(2^n)
, which is not feasible for n
up to 105.
Optimized approach: We process each element once and do constant work per element. Thus, time complexity is O(n)
.
Space complexity: We only use three integer counters, so space is O(1)
.
By recognizing the layered structure of special subsequences (0s, then 1s, then 2s), we avoid brute-force enumeration and instead use dynamic programming with three counters. This reduces the problem to a simple one-pass solution that is both elegant and efficient.
class Solution:
def countSpecialSubsequences(self, nums):
MOD = 10**9 + 7
count0 = count1 = count2 = 0
for num in nums:
if num == 0:
count0 = (count0 * 2 + 1) % MOD
elif num == 1:
count1 = (count1 * 2 + count0) % MOD
elif num == 2:
count2 = (count2 * 2 + count1) % MOD
return count2
class Solution {
public:
int countSpecialSubsequences(vector<int>& nums) {
const int MOD = 1e9 + 7;
long count0 = 0, count1 = 0, count2 = 0;
for (int num : nums) {
if (num == 0) {
count0 = (count0 * 2 + 1) % MOD;
} else if (num == 1) {
count1 = (count1 * 2 + count0) % MOD;
} else if (num == 2) {
count2 = (count2 * 2 + count1) % MOD;
}
}
return (int)count2;
}
};
class Solution {
public int countSpecialSubsequences(int[] nums) {
int MOD = 1_000_000_007;
long count0 = 0, count1 = 0, count2 = 0;
for (int num : nums) {
if (num == 0) {
count0 = (count0 * 2 + 1) % MOD;
} else if (num == 1) {
count1 = (count1 * 2 + count0) % MOD;
} else if (num == 2) {
count2 = (count2 * 2 + count1) % MOD;
}
}
return (int)count2;
}
}
var countSpecialSubsequences = function(nums) {
const MOD = 1e9 + 7;
let count0 = 0, count1 = 0, count2 = 0;
for (let num of nums) {
if (num === 0) {
count0 = (count0 * 2 + 1) % MOD;
} else if (num === 1) {
count1 = (count1 * 2 + count0) % MOD;
} else if (num === 2) {
count2 = (count2 * 2 + count1) % MOD;
}
}
return count2;
};